iOS端Flutter CallKit切换其他应用后后台/终止状态收不到通知
iOS Flutter CallKit Incoming 后台/终止状态切应用后无法接收通知的排查与解决
问题描述
我的iOS应用使用Flutter CallKit Incoming插件时,原本前台、后台、终止状态下都能正常接收CallKit通话通知,但存在以下异常场景:
- 当应用处于后台或终止状态时,关闭/最小化我的应用后打开其他应用,后续在后台/终止状态下无法再接收CallKit通知。
- Android端无此问题,一切正常。
云函数发送静默通知代码
await admin.messaging().send({ token: token_o, notification: {}, data: { imageUrl: requesterImageUrl, chatRoomId: chatRoomId, screenName: 'voiceScreen', voiceCall: 'voiceCall', callerName: requesterName, callsDocId: callsDocId, senderId: requesterId, }, android: { notification: { click_action: "android.intent.action.MAIN" }, }, apns: { headers: { apns_priority: "10", }, payload: { aps: { badge: 1 }, notification: { title: "iOVoiceCallNotification", body: {}, }, mutable_content: true, content_available : true, } } }).then(value => { functions.logger.log("Notification for AudioCall is sent to the Receiver"); }).catch((e) => { functions.logger.log(e.toString()); });
排查与解决步骤
1. 修正APNs通知配置
你的APNs payload存在结构错误,这是导致iOS推送异常的核心原因之一:
- 调整payload结构:
notification字段不应放在payload根目录,需合并到aps的alert节点中,且body必须是字符串(不能是空对象);自定义业务数据要放在payload根目录(与aps同级)。 - 添加apns_topic:必须指定
apns_topic为你的App Bundle ID,确保通知定向到正确应用。
修正后的APNs配置示例:
apns: { headers: { apns_priority: "10", apns_topic: "com.yourapp.bundleid" // 替换为你的实际Bundle ID }, payload: { aps: { badge: 1, content_available: true, mutable_content: true, alert: { title: "iOVoiceCallNotification", body: "有来电提醒" // 改为非空字符串 } }, // 自定义业务数据移到此处 imageUrl: requesterImageUrl, chatRoomId: chatRoomId, screenName: 'voiceScreen', voiceCall: 'voiceCall', callerName: requesterName, callsDocId: callsDocId, senderId: requesterId, } }
- 规范字段拼写:
content_available : true中的空格建议去掉,保持语法严谨。
2. 确认iOS后台权限配置
- 开启VoIP后台模式:在Xcode中进入项目
Signing & Capabilities,添加Background Modes并勾选Voice over IP,同时确保Push Notifications权限已开启。 - 检查系统级权限:引导用户检查系统设置:
设置 > 你的应用 > 通知,确保允许通知、在锁定屏幕上显示开启;设置 > 通用 > 后台App刷新,开启你的应用权限。 - 验证VoIP证书:确认APNs的VoIP推送证书有效且未过期,云函数使用的是对应环境(开发/生产)的证书(VoIP证书与普通推送证书不通用)。
3. 检查Flutter端CallKit初始化逻辑
- 确保启动时初始化:在应用启动(包括终止状态被推送唤醒时),必须正确初始化CallKit并监听事件:
void initState() { super.initState(); _initCallKit(); } void _initCallKit() async { await FlutterCallkitIncoming.init( appName: '你的应用名称', iconName: 'ic_launcher', ); // 监听CallKit事件 FlutterCallkitIncoming.onEvent.listen((event) { if (event.event == EventAction.ACTION_CALL_INCOMING) { // 处理来电逻辑 } }); }
- 重新注册推送令牌:当应用从后台回到前台,或被其他应用切换后,重新获取并上传VoIP推送令牌到服务器,避免令牌失效导致推送无法送达。
4. 排查iOS系统限制
- 后台资源限制:iOS在低电量、内存紧张时会主动挂起后台应用,可测试关闭其他后台应用、关闭低电量模式,验证是否恢复正常。
- 专注模式拦截:检查iOS是否开启了
专注模式,该模式可能拦截应用通知,需确保你的应用在专注模式下允许通知。
内容的提问来源于stack exchange,提问作者Bill_The_Coder
相关产品推荐
相关产品推荐

