如何用connectycube_flutter_call_kit实现Flutter自定义来电UI及通知
解决方案:Flutter自定义来电界面与推送触发逻辑
一、先解决来电界面不弹出的核心问题
你的代码存在关键逻辑错误:ConnectycubeFlutterCallKit.instance.init 放在了 _call 方法内,每次发起通话才初始化插件,会导致事件绑定不及时,无法正常唤起系统级来电界面。
修正初始化逻辑
将初始化操作移至 initState 中,确保仅执行一次:
void initState() { super.initState(); // 先初始化事件处理器 ConnectycubeFlutterCallKit.initEventsHandler(); // 初始化CallKit实例 ConnectycubeFlutterCallKit.instance.init( onCallAccepted: _onCallAccepted, onCallRejected: _onCallRejected, icon: 'app_icon', // 确保该图标已在Android mipmap/iOS Assets中配置 color: '#000000', ); } void _call() { Uuid uuid = Uuid(); CallEvent callEvent = CallEvent( sessionId: uuid.v4(), callType: 1, // 1=语音通话,2=视频通话,按需调整 callerId: 1, callerName: 'VCA Marina Bay Cities Animal Hospital', opponentsIds: {101}.toSet(), ); // 直接触发来电通知 ConnectycubeFlutterCallKit.showCallNotification(callEvent); }
补全平台权限配置
- Android:在
AndroidManifest.xml中添加必要权限<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> - iOS:在
Info.plist中添加权限说明<key>NSCameraUsageDescription</key> <string>需要使用摄像头进行视频通话</string> <key>NSMicrophoneUsageDescription</key> <string>需要使用麦克风进行语音通话</string> <key>UIBackgroundModes</key> <array> <string>voip</string> <!-- 若为VoIP通话需添加 --> <string>remote-notification</string> </array>
二、自定义来电通知与界面(无需依赖完整Connectycube SDK)
如果不想使用插件自带的系统来电界面,可完全自定义实现:
1. 编写自定义来电界面Widget
实现一个全屏来电UI,包含接听、挂断核心操作:
class CustomCallScreen extends StatelessWidget { final CallEvent callEvent; final Function(CallEvent) onAccept; final Function(CallEvent) onReject; const CustomCallScreen({ super.key, required this.callEvent, required this.onAccept, required this.onReject, }); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black.withOpacity(0.8), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(callEvent.callerName, style: const TextStyle(color: Colors.white, fontSize: 28)), const SizedBox(height: 40), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.green, fixedSize: const Size(120, 120), shape: const CircleBorder() ), onPressed: () => onAccept(callEvent), child: const Icon(Icons.call, color: Colors.white, size: 40), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, fixedSize: const Size(120, 120), shape: const CircleBorder() ), onPressed: () => onReject(callEvent), child: const Icon(Icons.call_end, color: Colors.white, size: 40), ), ], ), ], ), ); } }
2. 替换默认通知,触发自定义界面
使用 flutter_local_notifications 发送自定义来电通知,点击通知时唤起自定义界面:
// 初始化通知插件 final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); void initState() { super.initState(); // 配置通知初始化参数 const AndroidInitializationSettings androidInit = AndroidInitializationSettings('app_icon'); const IOSInitializationSettings iosInit = IOSInitializationSettings(); const InitializationSettings initSettings = InitializationSettings(android: androidInit, iOS: iosInit); _notificationsPlugin.initialize(initSettings, onDidReceiveNotificationResponse: (response) { // 点击通知时打开自定义来电界面 if (response.payload != null) { CallEvent callEvent = CallEvent.fromJson(jsonDecode(response.payload!)); Navigator.push(context, MaterialPageRoute(builder: (_) => CustomCallScreen( callEvent: callEvent, onAccept: _onCallAccepted, onReject: _onCallRejected, ))); } }); } // 自定义触发来电的方法 void _triggerCustomCall() { Uuid uuid = Uuid(); CallEvent callEvent = CallEvent( sessionId: uuid.v4(), callType: 1, callerId: 1, callerName: 'VCA Marina Bay Cities Animal Hospital', opponentsIds: {101}.toSet(), ); // 发送全屏来电通知 const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'call_channel', '来电通知', importance: Importance.max, priority: Priority.high, fullScreenIntent: true, // 关键:触发全屏通知 ); const NotificationDetails notificationDetails = NotificationDetails(android: androidDetails); _notificationsPlugin.show( 0, '来电', callEvent.callerName, notificationDetails, payload: jsonEncode(callEvent.toJson()), ); // APP前台时直接打开来电界面 Navigator.push(context, MaterialPageRoute(builder: (_) => CustomCallScreen( callEvent: callEvent, onAccept: _onCallAccepted, onReject: _onCallRejected, ))); }
三、通过推送通知自动展示来电界面
1. 推送消息回调处理
以FCM为例,在收到通话类型的推送时,解析通话数据并触发来电界面:
// 前台消息监听 FirebaseMessaging.onMessage.listen((RemoteMessage message) { if (message.data['type'] == 'call') { // 解析推送中的通话数据 CallEvent callEvent = CallEvent( sessionId: message.data['sessionId'], callType: int.parse(message.data['callType']), callerId: int.parse(message.data['callerId']), callerName: message.data['callerName'], opponentsIds: {int.parse(message.data['opponentId'])}.toSet(), ); // 触发来电通知与界面 _showCallNotificationAndScreen(callEvent); } }); // 后台消息处理(Android) Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { if (message.data['type'] == 'call') { CallEvent callEvent = CallEvent.fromJson(message.data); // 后台触发全屏来电通知 const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'call_channel', '来电通知', importance: Importance.max, priority: Priority.high, fullScreenIntent: true, ); const NotificationDetails notificationDetails = NotificationDetails(android: androidDetails); FlutterLocalNotificationsPlugin().show( 0, '来电', callEvent.callerName, notificationDetails, payload: jsonEncode(callEvent.toJson()), ); } }
2. 关键平台配置
- Android:需配置后台服务,确保推送能唤醒APP处理通话请求
- iOS:若需在后台/锁屏下触发来电,必须使用VoIP推送(普通推送无法在后台唤起界面),需在苹果开发者后台配置对应权限
内容的提问来源于stack exchange,提问作者Vijay Balaji N
相关产品推荐
相关产品推荐

