Flutter应用后台或关闭状态下FCM自定义通知声音无法播放的解决方案咨询
解决Flutter FCM后台/关闭状态下自定义通知声音不生效问题
我来帮你搞定这个问题!其实这是因为FCM在应用不同状态下的通知处理机制不一样,前台时你的代码能接管逻辑,但后台或完全关闭时是系统直接处理通知,咱们一步步调整就能解决:
1. 先搞懂FCM的两种消息类型
FCM消息分两种,这是关键:
- 通知消息:带
notification字段的消息,后台/关闭状态下是系统直接弹出通知,不会触发你代码里的onMessage回调 - 数据消息:只有
data字段的消息,任何状态下都会传给你的代码处理,但需要自己构建通知
你现在用的是带notification的消息,所以后台时系统接管了通知,自定义声音得让系统来播放,而不是靠你代码里的assetsAudioPlayer。
2. 修改FCM推送Payload
在notification字段里添加sound参数,指定你的自定义声音文件名:
{ "notification": { "body": "this is a body", "title": "this is a title", "sound": "alert.mp3" // 这里填你的自定义声音文件名 }, "data": { "click_action":"FLUTTER_NOTIFICATION_CLICK", "type": "normal", "id": "1", "ride_id": "-MKp1WBP8G2kTgJBqwyl", "status": "done" }, "to":"dv9Yq4qHSVubIohoM8niDX:APA91bGJgQkP7Ir867vyo9oT1CeXbWPKP6xMSDUgwu3242W9odgr4vn5qIIgPmY2LQyPNjL8Pwl8GcRY4TbucxVcCBOM0eBZDHnfhh0E0qYvhdWc_0Yd1oBT_Vh1sA0q-haqXQ3KXib5" }
3. 客户端配置(Android + iOS)
Android端
- 把你的
alert.mp3文件复制到android/app/src/main/res/raw/目录(没有raw文件夹就新建一个) - 文件名必须符合Android资源规则:只能用小写字母、数字、下划线,不能有空格或特殊字符
- 确保
AndroidManifest.xml里有必要权限:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" />
iOS端
- 把音频文件添加到Xcode项目中,勾选「Copy items if needed」和对应的target
- 在
Info.plist里添加配置,开启远程通知后台模式:<key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array> <key>UNNotificationSoundName</key> <string>alert.mp3</string> - 确保在Xcode的「Signing & Capabilities」里开启了「Background Modes」并勾选「Remote notifications」
4. 调整Flutter代码逻辑
前台时你可以继续用assetsAudioPlayer播放声音,但后台/关闭状态下系统已经播放过了,不需要重复触发。另外建议升级到新版FCM API(你用的configure是旧版):
class PushNotificationService{ final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; Future initialize(BuildContext context) async{ // 请求通知权限(必须开启sound权限) NotificationSettings settings = await _firebaseMessaging.requestPermission( alert: true, badge: true, sound: true, ); // 前台收到消息时的处理 FirebaseMessaging.onMessage.listen((RemoteMessage message) { print("onMessage: ${message.toMap()}"); fetchRideInfo(message.data['orderId'], context); }); // 点击通知启动应用(关闭状态) FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { print("onMessageOpenedApp: ${message.toMap()}"); fetchRideInfo(message.data['orderId'], context); }); } Future<String> getToken() async{ print("fetching token"); String? token = await _firebaseMessaging.getToken(); print('token got as: $token'); return token ?? ''; } void fetchRideInfo(String? orderId, BuildContext context) { if (orderId == null) return; print("fetching info for order: $orderId"); showDialog( barrierDismissible: false, context: context, builder: (BuildContext context) => CustomProgressDialog(status:'Fetching details',), ); // 只有前台时播放自定义声音,后台/启动时系统已经处理过了 if (_firebaseMessaging.app.isForeground) { assetsAudioPlayer.open(Audio('sounds/alert.mp3')); assetsAudioPlayer.play(); } } }
5. 常见排查点
- 确认音频文件格式:Android支持mp3/wav,iOS支持caf/mp3
- 检查文件名是否符合平台要求,Android不能有大写字母
- 测试时不要用模拟器,尽量用真机测试(模拟器可能有通知声音限制)
内容的提问来源于stack exchange,提问作者custom apps
相关产品推荐
相关产品推荐

