Flutter通话保持插件mitek_callkeep的使用
Flutter通话保持插件mitek_callkeep的使用
展示通过iOS CallKit和Android自定义UI在Flutter中显示来电通知/屏幕。
原生设置
mitek_callkeep
需要以下权限。
Android
无需额外设置。
iOS
在 Info.plist
文件中添加:
<key>UIBackgroundModes</key>
<array>
<string>processing</string>
<string>remote-notification</string>
<string>voip</string>
</array>
然后需要更新 AppDelegate.swift
来处理PushKit,因为由于iOS 13 PushKit VoIP限制,推送处理必须通过原生iOS代码进行。
import UIKit
import PushKit
import Flutter
import mitek_callkeep
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// 设置VOIP
let mainQueue = DispatchQueue.main
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [PKPushType.voIP]
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// 处理更新的推送凭据
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
print(credentials.token)
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
print(deviceToken)
// 将设备令牌保存到服务器
MitekCallKeepPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken)
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
print("didInvalidatePushTokenFor")
MitekCallKeepPlugin.sharedInstance?.setDevicePushTokenVoIP("")
}
// 处理传入的推送
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
print("didReceiveIncomingPushWith")
guard type == .voIP else { return }
let id = payload.dictionaryPayload["id"] as? String ?? ""
let callerName = payload.dictionaryPayload["callerName"] as? String ?? ""
let userId = payload.dictionaryPayload["callerId"] as? String ?? ""
let handle = payload.dictionaryPayload["handle"] as? String ?? ""
let isVideo = payload.dictionaryPayload["isVideo"] as? Bool ?? false
let data = MitekCallKeep.Data(id: id, callerName: callerName, handle: handle, hasVideo: isVideo)
// 设置更多数据
data.extra = ["userId": userId, "platform": "ios"]
data.appName = "Done"
// data.iconName = ...
// data.....
MitekCallKeepPlugin.sharedInstance?.displayIncomingCall(data, fromPushKit: true)
}
}
使用方法
设置
你需要有基本的 CallKeep
配置以减少代码重复并使显示来电更加容易:
final callKeepBaseConfig = CallKeepBaseConfig(
appName: 'Done',
androidConfig: CallKeepAndroidConfig(
logo: 'logo',
notificationIcon: 'notification_icon',
ringtoneFileName: 'ringtone.mp3',
accentColor: '#34C7C2',
),
iosConfig: CallKeepIosConfig(
iconName: 'Icon',
maximumCallGroups: 1,
),
);
显示来电
配置和uuid是必需的参数:
// 配置和uuid是必需的参数
final config = CallKeepIncomingConfig.fromBaseConfig(
config: callKeepBaseConfig,
uuid: uuid,
contentTitle: 'Incoming call from Done',
hasVideo: hasVideo,
handle: handle,
callerName: incomingCallUsername,
extra: callData,
);
await CallKeep.instance.displayIncomingCall(config);
显示未接来电通知(仅限Android)
配置和uuid是必需的参数:
// 配置和uuid是必需的参数
final config = CallKeepIncomingConfig.fromBaseConfig(
config: callKeepBaseConfig,
uuid: uuid,
contentTitle: 'Incoming call from Done',
hasVideo: hasVideo,
handle: handle,
callerName: incomingCallUsername,
extra: callData,
);
await CallKeep.instance.showMissCallNotification(config);
开始外呼
配置和uuid是必需的参数:
// 配置和uuid是必需的参数
final config = CallKeepOutgoingConfig.fromBaseConfig(
config: DoneCallsConfig.instance.callKeepBaseConfig,
uuid: uuid,
handle: handle,
hasVideo: hasVideo ?? false,
);
CallKeep.instance.startCall(config);
处理事件
监听事件:
CallKeep.instance.onEvent.listen((event) async {
// TODO: 实现其他事件
if (event == null) return;
switch (event.type) {
case CallKeepEventType.callAccept:
final data = event.data as CallKeepCallData;
print('call answered: ${data.toMap()}');
NavigationService.instance
.pushNamedIfNotCurrent(AppRoute.callingPage, args: data.toMap());
if (callback != null) callback.call(event);
break;
case CallKeepEventType.callDecline:
final data = event.data as CallKeepCallData;
print('call declined: ${data.toMap()}');
await requestHttp("ACTION_CALL_DECLINE_FROM_DART");
if (callback != null) callback.call(data);
break;
default:
break;
}
});
自定义(Android)
你可以通过在 {{yourApp}}/android/app/src/main/res/values
和 {{yourApp}}/android/app/src/main/res/values-{{languageCode}}
添加值来定制背景颜色和添加本地化文本。
主要值包括:
在 colors.xml
中:
<!-- 用于显示在自定义来电UI顶部的十六进制颜色值 -->
<color name="incoming_call_bg_color">#80ffffff</color>
在 strings.xml
中:
<!-- 接受按钮来电文本,便于本地化 -->
<string name="accept_text">接受</string>
<!-- 拒绝按钮来电文本,便于本地化 -->
<string name="decline_text">拒绝</string>
<!-- 未接来电文本,便于本地化 -->
<string name="text_missed_call">未接来电</string>
<!-- 回拨按钮文本,便于本地化 -->
<string name="text_call_back">回拨</string>
<!-- 自定义来电UI头部,便于本地化 -->
<!-- 这也可以从Flutter中设置 -->
<string name="call_header">来自CallKeep的来电</string>
更多关于Flutter通话保持插件mitek_callkeep的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter通话保持插件mitek_callkeep的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用mitek_callkeep
插件的示例代码。mitek_callkeep
插件主要用于处理来电界面(Call Screen)和通话保持功能。请注意,由于mitek_callkeep
可能并非一个广为人知的库(在撰写时,callkeep
是更常见的库名),以下示例将基于一个假设的mitek_callkeep
插件的API设计,该设计类似于广泛使用的callkeep
插件。
首先,确保在pubspec.yaml
文件中添加依赖项(假设库名为mitek_callkeep
,实际使用时请替换为正确的库名):
dependencies:
flutter:
sdk: flutter
mitek_callkeep: ^x.y.z # 替换为实际的版本号
然后运行flutter pub get
来安装依赖。
接下来,在ios/Runner/Info.plist
和android/app/src/main/AndroidManifest.xml
中添加必要的权限和配置,以允许应用处理来电。这些配置取决于具体的插件文档,以下是一个示例配置(针对callkeep
插件,mitek_callkeep
可能有所不同,请参考其官方文档):
iOS (Info.plist):
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSVoIPUsageDescription</key>
<string>Need VoIP permissions for calling features</string>
Android (AndroidManifest.xml):
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<service
android:name="io.flutter.plugins.callkeep.CallKeepService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:foregroundServiceType="voip">
<intent-filter>
<action android:name="android.telecom.CallScreeningService" />
</intent-filter>
</service>
在Dart代码中,初始化并使用mitek_callkeep
插件(假设其API与callkeep
类似):
import 'package:flutter/material.dart';
import 'package:mitek_callkeep/mitek_callkeep.dart';
void main() {
runApp(MyApp());
_configureCallKeep();
}
void _configureCallKeep() {
// 初始化 CallKeep
MitekCallKeep().setup(
android: AndroidInitSettings(
packageName: 'com.example.myapp', // 替换为你的包名
alicePackageName: null, // 如果需要
notificationChannelName: 'My Call Keep Channel',
notificationChannelDescription: 'Channel for Call Keep notifications',
defaultToSpeaker: false,
),
ios: IOSInitSettings(
appName: 'MyApp',
),
);
// 监听来电事件
MitekCallKeep().addEventListener((CallKeepEvent event) {
switch (event.type) {
case CallKeepEventType.didReceiveStartCallAction:
_handleIncomingCall(event.uuid);
break;
case CallKeepEventType.didPerformSetMutedAction:
_handleMuteCall(event.uuid, event.muted);
break;
// 处理其他事件...
default:
break;
}
});
}
void _handleIncomingCall(String uuid) {
MitekCallKeep().startCall(uuid, handleType: 'generic');
MitekCallKeep().displayIncomingCall(uuid, localizedCallerName: 'John Doe');
}
void _handleMuteCall(String uuid, bool muted) {
// 在这里处理静音逻辑
print('Call $uuid is ${muted ? 'muted' : 'unmuted'}');
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter CallKeep Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
// 发起一个模拟来电
final uuid = Uuid().v4(); // 使用uuid库生成唯一标识符
_handleIncomingCall(uuid);
},
child: Text('Start Mock Call'),
),
),
),
);
}
}
请注意,上述代码中的Uuid()
来自uuid
包,你需要在pubspec.yaml
中添加依赖:
dependencies:
uuid: ^x.y.z # 替换为实际的版本号
并且运行flutter pub get
来安装它。
由于mitek_callkeep
可能是一个假想的库名或者一个不常见的库,具体的API和配置可能会有所不同。务必参考该库的官方文档和示例代码进行集成。如果mitek_callkeep
实际上并不存在,你可能需要查找并使用一个更广泛支持的库,如callkeep
。