Flutter来电界面修复插件flutter_callkit_incoming_fix的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter来电界面修复插件flutter_callkit_incoming_fix的使用

插件简介

flutter_callkit_incoming 是一个Flutter插件,用于在Flutter应用中显示来电界面。它支持自定义Android来电界面和iOS的Callkit功能。该插件可以帮助开发者轻松实现来电通知、呼出电话、结束通话等功能,并且提供了丰富的配置选项来满足不同的需求。

主要特性

  • 显示来电通知
  • 发起呼出电话
  • 自定义Android来电界面/Callkit for iOS
  • 支持Pushkit/VoIP(仅限iOS)

注意事项

  • iOS: 仅在真实设备上有效,模拟器不支持Callkit框架。

安装步骤

1. 安装依赖

通过以下命令安装插件:

flutter pub add flutter_callkit_incoming

pubspec.yaml 文件中添加依赖:

dependencies:
  flutter_callkit_incoming: any
2. 配置项目
Android配置

AndroidManifest.xml 中添加以下权限:

<manifest...>
    <!-- 用于从互联网加载图片 -->
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>
iOS配置

Info.plist 中添加以下配置:

<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
    <string>remote-notification</string>
    <string>voip</string>
</array>

使用示例

1. 导入插件

在Dart文件中导入插件:

import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
2. 接收来电通知

以下是接收来电通知的完整示例代码:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/entities/android_params.dart';
import 'package:flutter_callkit_incoming/entities/call_kit_params.dart';
import 'package:flutter_callkit_incoming/entities/ios_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:uuid/uuid.dart';

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print("Handling a background message: ${message.messageId}");
  showCallkitIncoming(Uuid().v4());
}

Future<void> showCallkitIncoming(String uuid) async {
  final params = CallKitParams(
    id: uuid,
    nameCaller: 'Hien Nguyen',
    appName: 'Callkit',
    avatar: 'https://i.pravatar.cc/100',
    handle: '0123456789',
    type: 0, // 0 - 音频通话, 1 - 视频通话
    duration: 30000, // 来电显示时间(毫秒)
    textAccept: '接受',
    textDecline: '拒绝',
    textMissedCall: '未接来电',
    textCallback: '回拨',
    extra: {'userId': '1a2b3c4d'},
    headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'},
    android: AndroidParams(
      isCustomNotification: true,
      isShowLogo: false,
      isShowCallback: true,
      isShowMissedCallNotification: true,
      ringtonePath: 'system_ringtone_default',
      backgroundColor: '#0955fa',
      backgroundUrl: 'assets/test.png',
      actionColor: '#4CAF50',
    ),
    ios: IOSParams(
      iconName: 'CallKitLogo',
      handleType: 'generic',
      supportsVideo: true,
      maximumCallGroups: 2,
      maximumCallsPerCallGroup: 1,
      audioSessionMode: 'default',
      audioSessionActive: true,
      audioSessionPreferredSampleRate: 44100.0,
      audioSessionPreferredIOBufferDuration: 0.005,
      supportsDTMF: true,
      supportsHolding: true,
      supportsGrouping: false,
      supportsUngrouping: false,
      ringtonePath: 'system_ringtone_default',
    ),
  );
  await FlutterCallkitIncoming.showCallkitIncoming(params);
}

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  late final Uuid _uuid;
  String? _currentUuid;

  @override
  void initState() {
    super.initState();
    _uuid = Uuid();
    initFirebase();
    WidgetsBinding.instance.addObserver(this);
    // 检查应用启动时是否有未接来电
    checkAndNavigationCallingPage();
  }

  Future<void> getCurrentCall() async {
    // 检查当前是否有正在进行的通话
    var calls = await FlutterCallkitIncoming.activeCalls();
    if (calls is List && calls.isNotEmpty) {
      print('DATA: $calls');
      _currentUuid = calls[0]['id'];
      return calls[0];
    } else {
      _currentUuid = "";
      return null;
    }
  }

  Future<void> checkAndNavigationCallingPage() async {
    var currentCall = await getCurrentCall();
    if (currentCall != null) {
      // 跳转到通话页面
      NavigationService.instance.pushNamedIfNotCurrent('/callingPage', args: currentCall);
    }
  }

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
    print(state);
    if (state == AppLifecycleState.resumed) {
      // 应用从后台恢复时检查是否有未接来电
      checkAndNavigationCallingPage();
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  Future<void> initFirebase() async {
    // 初始化Firebase
    await Firebase.initializeApp();
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      print(
          'Message title: ${message.notification?.title}, body: ${message.notification?.body}, data: ${message.data}');
      _currentUuid = _uuid.v4();
      showCallkitIncoming(_currentUuid!);
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(),
      onGenerateRoute: (settings) {
        // 路由生成逻辑
        return MaterialPageRoute(builder: (context) => HomePage());
      },
      initialRoute: '/',
    );
  }

  Future<void> getDevicePushTokenVoIP() async {
    var devicePushTokenVoIP = await FlutterCallkitIncoming.getDevicePushTokenVoIP();
    print(devicePushTokenVoIP);
  }
}

其他功能

1. 显示未接来电通知
this._currentUuid = _uuid.v4();
CallKitParams params = CallKitParams(
  id: _currentUuid,
  nameCaller: 'Hien Nguyen',
  handle: '0123456789',
  type: 1,
  textMissedCall: '未接来电',
  textCallback: '回拨',
  extra: {'userId': '1a2b3c4d'},
);
await FlutterCallkitIncoming.showMissCallNotification(params);
2. 发起呼出电话
this._currentUuid = _uuid.v4();
CallKitParams params = CallKitParams(
  id: this._currentUuid,
  nameCaller: 'Hien Nguyen',
  handle: '0123456789',
  type: 1,
  extra: {'userId': '1a2b3c4d'},
  ios: IOSParams(handleType: 'generic')
);
await FlutterCallkitIncoming.startCall(params);
3. 结束通话
await FlutterCallkitIncoming.endCall(this._currentUuid);
4. 结束所有通话
await FlutterCallkitIncoming.endAllCalls();
5. 获取活跃通话
var activeCalls = await FlutterCallkitIncoming.activeCalls();
print(activeCalls);
6. 获取VoIP推送令牌(仅限iOS)
var devicePushTokenVoIP = await FlutterCallkitIncoming.getDevicePushTokenVoIP();
print(devicePushTokenVoIP);
7. 监听事件
FlutterCallkitIncoming.onEvent.listen((CallEvent event) {
  switch (event!.event) {
    case Event.ACTION_CALL_INCOMING:
      // 收到来电通知
      break;
    case Event.ACTION_CALL_START:
      // 开始呼出电话
      break;
    case Event.ACTION_CALL_ACCEPT:
      // 接受来电
      break;
    case Event.ACTION_CALL_DECLINE:
      // 拒绝来电
      break;
    case Event.ACTION_CALL_ENDED:
      // 结束通话
      break;
    case Event.ACTION_CALL_TIMEOUT:
      // 未接来电
      break;
    case Event.ACTION_CALL_CALLBACK:
      // 点击未接来电通知中的“回拨”按钮
      break;
    case Event.ACTION_CALL_TOGGLE_HOLD:
      // 切换保持状态(仅限iOS)
      break;
    case Event.ACTION_CALL_TOGGLE_MUTE:
      // 切换静音状态(仅限iOS)
      break;
    case Event.ACTION_CALL_TOGGLE_DMTF:
      // 切换DTMF(仅限iOS)
      break;
    case Event.ACTION_CALL_TOGGLE_GROUP:
      // 切换分组(仅限iOS)
      break;
    case Event.ACTION_CALL_TOGGLE_AUDIO_SESSION:
      // 切换音频会话(仅限iOS)
      break;
    case Event.ACTION_DID_UPDATE_DEVICE_PUSH_TOKEN_VOIP:
      // 更新VoIP推送令牌(仅限iOS)
      break;
  }
});

更多关于Flutter来电界面修复插件flutter_callkit_incoming_fix的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter来电界面修复插件flutter_callkit_incoming_fix的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用flutter_callkit_incoming_fix插件的示例代码。这个插件旨在解决iOS设备上Flutter应用来电界面(CallKit)的一些兼容性问题。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加flutter_callkit_incoming_fix依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_callkit_incoming_fix: ^最新版本号  # 请替换为实际的最新版本号

然后运行flutter pub get来安装依赖。

2. 配置iOS项目

在iOS项目中,你需要进行一些配置以启用CallKit功能。

2.1 配置Info.plist

在你的ios/Runner/Info.plist文件中,添加以下权限请求:

<key>NSCalendarsUsageDescription</key>
<string>我们需要访问您的日历以处理来电</string>
<key>NSContactsUsageDescription</key>
<string>我们需要访问您的联系人以处理来电</string>
<key>NSMicrophoneUsageDescription</key>
<string>我们需要访问您的麦克风以处理来电</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>我们需要访问您的照片库以处理来电</string>
<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
    <string>voip</string>
</array>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>

2.2 配置AppDelegate.swift

在你的ios/Runner/AppDelegate.swift文件中,你需要添加对flutter_callkit_incoming_fix的初始化和配置。

import UIKit
import Flutter
import flutter_callkit_incoming_fix  // 导入插件

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    // 配置flutter_callkit_incoming_fix
    let callKitFix = CallKitIncomingFix()
    callKitFix.configure()
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  // 覆盖 handleIncomingCall 方法来处理来电
  override func application(_ application: UIApplication,
                            continue userActivity: NSUserActivity,
                            restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
       let callUUID = userActivity.userInfo?[UIApplication.ActivityUserInfoKey.webpageURL] as? URL,
       let uuidString = callUUID.lastPathComponent {
      // 处理来电逻辑,例如显示来电界面
      // 这里可以调用你的Flutter代码来显示来电UI
      
      // 示例:使用 MethodChannel 发送消息到 Flutter
      let channel = FlutterMethodChannel(name: "com.example.myapp/callkit", binaryMessenger: self.flutterEngine?.binaryMessenger)
      channel.invokeMethod("handleIncomingCall", arguments: ["callUUID": uuidString])
      
      return true
    }
    return false
  }
}

3. 在Flutter中处理来电

在你的Flutter代码中,你需要设置一个MethodChannel来监听来自iOS原生代码的来电通知。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming_fix/flutter_callkit_incoming_fix.dart';

void main() {
  const platform = MethodChannel('com.example.myapp/callkit');

  platform.setMethodCallHandler((call) async {
    if (call.method == "handleIncomingCall") {
      final callUUID = call.arguments["callUUID"];
      // 处理来电逻辑,例如显示来电界面
      showIncomingCallUi(callUUID);
    }
  });

  runApp(MyApp());
}

void showIncomingCallUi(String callUUID) {
  // 显示来电界面的逻辑
  // 例如,使用第三方库或自定义UI
  // 这里只是示例,实际逻辑需要根据需求实现
  print("Received incoming call with UUID: $callUUID");
  // 假设有一个函数来显示来电界面
  // displayIncomingCallScreen(callUUID);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter CallKit Example'),
        ),
        body: Center(
          child: Text('Check the console for incoming call UUIDs'),
        ),
      ),
    );
  }
}

总结

上述代码展示了如何在Flutter项目中集成和使用flutter_callkit_incoming_fix插件来处理iOS设备的来电界面。你需要根据实际需求进一步完善来电界面的显示逻辑。请注意,处理来电通常需要更多的逻辑,包括接听、挂断、拒绝等,这里只是展示了一个基本的框架。

回到顶部