Flutter CallKit Incoming在iOS应用终止状态下无法工作的问题
iOS后台/终止状态CallKit无法触发及通话通知隐藏方案
问题1:iOS后台/终止状态无法显示CallKit
核心原因
iOS终止状态下,普通FCM数据消息无法唤醒Flutter引擎,_firebaseMessagingBackgroundHandler不会执行。必须依赖**VoIP推送(PushKit)**触发原生层的CallKit调用——PushKit是iOS专门为语音/视频通话设计的推送机制,能在App终止/后台状态下直接唤醒原生代码。
修复步骤
完善PushKit原生代理实现
在AppDelegate.swift中确保正确实现PushKit的代理方法,直接在原生层触发CallKit,无需经过Flutter后台handler:import PushKit class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate { override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 初始化PushKit let registry = PKPushRegistry(queue: DispatchQueue.main) registry.delegate = self registry.desiredPushTypes = [.voIP] // 其他Flutter初始化代码 GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // 上传VoIP令牌到服务器 func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) { let token = pushCredentials.token.map { String(format: "%02x", $0) }.joined() // 将token发送到你的后端服务 } // 接收VoIP推送并触发CallKit func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { let data = payload.dictionaryPayload["data"] as? [String: Any] ?? [:] // 构造CallKit参数并调用原生方法 FlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming([ "id": UUID().uuidString, "nameCaller": "APP Screen Sharing Call", "handle": data["senderName"] as? String ?? "", "type": 0, "avatar": data["senderImageUrl"] as? String ?? "", "extra": [ "guestRoomCode": data["guestRoomCode"] as? String ?? "", "receiverName": data["receiverName"] as? String ?? "" ], "ios": [ "supportsVideo": true, "ringtonePath": "system_ringtone_default" ] ]) completion() } }同时在
Info.plist添加VoIP权限描述:<key>NSExtensionUsageDescription</key> <string>需要VoIP权限接收屏幕共享来电通知</string>切换为VoIP推送类型
服务器必须发送VoIP格式的推送,而非普通FCM通知。示例Payload:{ "aps": { "content-available": 1 }, "data": { "topic": "screen.sharing.invite", "senderName": "测试用户", "senderImageUrl": "https://example.com/avatar.jpg", "guestRoomCode": "123456" } }移除Flutter后台handler的无效调用
iOS终止状态下Flutter引擎无法启动,_firebaseMessagingBackgroundHandler中的showCallkitIncoming不会执行,可保留该监听处理其他非通话类后台消息,但通话触发逻辑仅保留原生PushKit代理中的实现。
问题2:隐藏该通话的通知,保留其他通知正常显示
iOS端
- 使用VoIP推送触发CallKit时,系统会直接显示系统级来电界面,不会生成普通通知,无需额外处理。
- 若需隐藏未接来电通知,可在
CallKitParams的missedCallNotification中设置showNotification: false。
Android端
- 利用独立通知渠道隔离:你已为通话设置了专属渠道
screen_share_call,可动态禁用该渠道来隐藏通话通知,不影响其他渠道:import 'package:flutter_local_notifications/flutter_local_notifications.dart'; void toggleCallNotificationChannel(bool enable) async { final FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin(); if (enable) { await notificationsPlugin.enableNotificationChannel('screen_share_call'); } else { await notificationsPlugin.disableNotificationChannel('screen_share_call'); } } - 若需来电时仅在锁屏显示、不弹出通知,可调整
AndroidParams参数:
注:Android前台服务要求必须显示通知,无法完全隐藏,仅能通过样式调整降低干扰。android: const AndroidParams( isShowLogo: true, textColor: "#ffffff", actionColor: '#dda088', backgroundColor: '#dda088', isShowCallID: true, isCustomNotification: true, isShowFullLockedScreen: true, // 设置静音无震动,减少干扰 ringtonePath: '', incomingCallNotificationChannelName: 'screen_share_call', missedCallNotificationChannelName: "screen_share_miss_call", )
内容的提问来源于stack exchange,提问作者amit.flutter
相关产品推荐
相关产品推荐

