You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:52:26