fix:调整为callkit实现
This commit is contained in:
parent
2ab2a48f02
commit
4e08f57c48
@ -7,11 +7,15 @@
|
||||
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <PushKit/PushKit.h>
|
||||
#import <CallKit/CallKit.h>
|
||||
// #import <UMCommon/UMCommon.h>
|
||||
|
||||
|
||||
@interface AppDelegate()<PKPushRegistryDelegate>
|
||||
@interface AppDelegate()<PKPushRegistryDelegate, CXProviderDelegate>
|
||||
@property (nonatomic, strong) FlutterMethodChannel *methodChannel;
|
||||
@property (nonatomic, strong) CXProvider *callKitProvider;
|
||||
@property (nonatomic, copy) NSString *pendingCallKitEvent; // 缓存未处理的CallKit事件
|
||||
@property (nonatomic, strong) NSUUID *lastCallUUID;
|
||||
|
||||
@end
|
||||
|
||||
@ -45,6 +49,45 @@
|
||||
self.window.rootViewController = VC;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
// 初始化FlutterMethodChannel
|
||||
FlutterViewController *controller = (FlutterViewController *)self.window.rootViewController;
|
||||
self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"com.starlock/callkit" binaryMessenger:controller.binaryMessenger];
|
||||
// 注册拉取pending事件方法
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.methodChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
|
||||
if ([call.method isEqualToString:@"get_pending_event"]) {
|
||||
if (weakSelf.pendingCallKitEvent) {
|
||||
result(weakSelf.pendingCallKitEvent);
|
||||
weakSelf.pendingCallKitEvent = nil;
|
||||
} else {
|
||||
result(nil);
|
||||
}
|
||||
} else if ([call.method isEqualToString:@"end_call"]) {
|
||||
NSLog(@"[CallKit] 收到Flutter端结束通话请求");
|
||||
// 结束CallKit通话
|
||||
// 这里只能结束最近一次来电,需保存UUID
|
||||
if (weakSelf.lastCallUUID) {
|
||||
CXCallEndedReason reason = CXCallEndedReasonRemoteEnded;
|
||||
[weakSelf.callKitProvider reportCallWithUUID:weakSelf.lastCallUUID endedAtDate:[NSDate date] reason:reason];
|
||||
weakSelf.lastCallUUID = nil;
|
||||
result(@"ok");
|
||||
} else {
|
||||
NSLog(@"[CallKit] 无有效UUID,无法结束通话");
|
||||
result(@"no_call");
|
||||
}
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}];
|
||||
// 初始化CallKit Provider(仅国外包)
|
||||
#if USE_CALLKIT
|
||||
CXProviderConfiguration *providerConfiguration = [[CXProviderConfiguration alloc] initWithLocalizedName:@"来电"];
|
||||
providerConfiguration.supportsVideo = NO;
|
||||
providerConfiguration.maximumCallsPerCallGroup = 1;
|
||||
self.callKitProvider = [[CXProvider alloc] initWithConfiguration:providerConfiguration];
|
||||
[self.callKitProvider setDelegate:self queue:nil];
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -190,13 +233,52 @@
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
|
||||
if ([type isEqualToString:PKPushTypeVoIP]) {
|
||||
NSLog(@"[VoIP] didReceiveIncomingPushWithPayload: %@", payload.dictionaryPayload);
|
||||
#if USE_CALLKIT
|
||||
// 国外环境,直接用CallKit弹窗
|
||||
NSString *callerName = @"来电"; // 可根据payload内容自定义
|
||||
// 复用已初始化的provider
|
||||
CXCallUpdate *update = [[CXCallUpdate alloc] init];
|
||||
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:callerName];
|
||||
update.hasVideo = NO;
|
||||
NSUUID *callUUID = [NSUUID UUID];
|
||||
self.lastCallUUID = callUUID;
|
||||
[self.callKitProvider reportNewIncomingCallWithUUID:callUUID update:update completion:^(NSError * _Nullable error) {
|
||||
if (error) {
|
||||
NSLog(@"CallKit error: %@", error);
|
||||
}
|
||||
}];
|
||||
#else
|
||||
// 国内环境,使用LiveCommunicationKit弹窗
|
||||
UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||
NSString *callerName = @"来电"; // 可根据payload内容自定义
|
||||
[LCKBridge presentCallInterfaceFromRootVC:rootVC callerName:callerName];
|
||||
#endif
|
||||
}
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - CXProviderDelegate
|
||||
// 用户点击"接听"
|
||||
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
|
||||
NSLog(@"[CallKit] 用户接听来电");
|
||||
if (self.methodChannel) {
|
||||
[self.methodChannel invokeMethod:@"callkit_answered" arguments:nil];
|
||||
} else {
|
||||
self.pendingCallKitEvent = @"callkit_answered";
|
||||
}
|
||||
[action fulfill];
|
||||
}
|
||||
// 用户点击"拒绝"或挂断
|
||||
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
|
||||
NSLog(@"[CallKit] 用户拒绝/挂断来电");
|
||||
if (self.methodChannel) {
|
||||
[self.methodChannel invokeMethod:@"callkit_declined" arguments:nil];
|
||||
} else {
|
||||
self.pendingCallKitEvent = @"callkit_declined";
|
||||
}
|
||||
[action fulfill];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -109,6 +109,8 @@
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
<string>processing</string>
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
|
||||
@ -1,9 +1,37 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
#if USE_CALLKIT
|
||||
import CallKit
|
||||
#endif
|
||||
import LiveCommunicationKit
|
||||
|
||||
@objc class LCKBridge: NSObject {
|
||||
@objc static func presentCallInterfaceFromRootVC(_ rootVC: UIViewController, callerName: String) {
|
||||
@objc(LCKBridge)
|
||||
class LCKBridge: NSObject {
|
||||
// CallKit来电弹窗
|
||||
@objc(presentCallInterfaceWithCallKit:)
|
||||
class func presentCallInterfaceWithCallKit(_ callerName: NSString) {
|
||||
#if USE_CALLKIT
|
||||
let providerConfiguration = CXProviderConfiguration(localizedName: callerName as String)
|
||||
providerConfiguration.supportsVideo = false
|
||||
providerConfiguration.maximumCallsPerCallGroup = 1
|
||||
let provider = CXProvider(configuration: providerConfiguration)
|
||||
let update = CXCallUpdate()
|
||||
update.remoteHandle = CXHandle(type: .generic, value: callerName as String)
|
||||
update.hasVideo = false
|
||||
provider.setDelegate(nil, queue: nil)
|
||||
provider.reportNewIncomingCall(with: UUID(), update: update) { error in
|
||||
if let error = error {
|
||||
print("CallKit来电弹窗失败: \(error.localizedDescription)")
|
||||
} else {
|
||||
print("CallKit来电弹窗成功")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// LiveCommunicationKit来电弹窗
|
||||
@objc(presentCallInterfaceFromRootVC:callerName:)
|
||||
class func presentCallInterfaceFromRootVC(_ rootVC: UIViewController, callerName: NSString) {
|
||||
#if !USE_CALLKIT
|
||||
if #available(iOS 17.4, *) {
|
||||
// 配置ConversationManager
|
||||
let config = ConversationManager.Configuration(
|
||||
@ -16,7 +44,7 @@ import LiveCommunicationKit
|
||||
supportedHandleTypes: [.generic, .phoneNumber, .emailAddress]
|
||||
)
|
||||
let manager = ConversationManager(configuration: config)
|
||||
let local = Handle(type: .generic, value: callerName, displayName: callerName)
|
||||
let local = Handle(type: .generic, value: callerName as String, displayName: callerName as String)
|
||||
let update = Conversation.Update(localMember: local, members: [local], activeRemoteMembers: [local])
|
||||
Task {
|
||||
do {
|
||||
@ -27,5 +55,6 @@ import LiveCommunicationKit
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -109,6 +109,8 @@
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
<string>processing</string>
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
|
||||
@ -109,6 +109,8 @@
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
<string>processing</string>
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
|
||||
@ -19,6 +19,7 @@ import 'package:star_lock/talk/starChart/handle/impl/debug_Info_model.dart';
|
||||
import 'package:star_lock/talk/starChart/status/appLifecycle_observer.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
import 'package:star_lock/tools/bugly/bugly_tool.dart';
|
||||
import 'package:star_lock/tools/callkit_handler.dart';
|
||||
import 'package:star_lock/tools/device_info_service.dart';
|
||||
import 'package:star_lock/tools/eventBusEventManage.dart';
|
||||
import 'package:star_lock/tools/jverify_one_click_login.dart';
|
||||
@ -65,6 +66,7 @@ FutureOr<void> main() async {
|
||||
// runApp(MultiProvider(providers: [
|
||||
// ChangeNotifierProvider(create: (_) => DebugInfoModel()),
|
||||
// ], child: MyApp(isLogin: isLogin)));
|
||||
CallKitHandler.setupListener();
|
||||
runApp(MyApp(isLogin: isLogin));
|
||||
}, onException: (FlutterErrorDetails details) async {
|
||||
debugPrint('FlutterErrorDetails ${details.exceptionAsString()}');
|
||||
|
||||
56
lib/tools/callkit_handler.dart
Normal file
56
lib/tools/callkit_handler.dart
Normal file
@ -0,0 +1,56 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/appRouters.dart';
|
||||
import 'package:star_lock/app_settings/app_settings.dart';
|
||||
|
||||
class CallKitHandler {
|
||||
static const MethodChannel _channel = MethodChannel('com.starlock/callkit');
|
||||
static bool _isInitialized = false;
|
||||
|
||||
/// 初始化监听,无需context
|
||||
static void setupListener() async {
|
||||
if (_isInitialized) {
|
||||
print('CallKitHandler.setupListener 已初始化,跳过');
|
||||
return;
|
||||
}
|
||||
_isInitialized = true;
|
||||
print('CallKitHandler.setupListener 初始化,准备拉取pending事件');
|
||||
// 启动时主动拉取pending事件
|
||||
final pendingEvent =
|
||||
await _channel.invokeMethod<String>('get_pending_event');
|
||||
print('CallKitHandler 拉取到pendingEvent: $pendingEvent');
|
||||
if (pendingEvent == 'callkit_answered') {
|
||||
print('启动时拉取到callkit_answered,跳转到对讲页面');
|
||||
// 如需跳转页面可在此处实现
|
||||
} else if (pendingEvent == 'callkit_declined') {
|
||||
print('启动时拉取到callkit_declined,返回主页面');
|
||||
} else {
|
||||
print('启动时无pending事件');
|
||||
}
|
||||
// 注册实时监听
|
||||
_channel.setMethodCallHandler((call) async {
|
||||
print('CallKitHandler 收到原生事件: ${call.method}');
|
||||
if (call.method == 'callkit_answered') {
|
||||
print('跳转到对讲页面');
|
||||
String currentRoute = Get.currentRoute;
|
||||
print('当前路由: $currentRoute');
|
||||
if (currentRoute != Routers.h264View) {
|
||||
Get.toNamed(
|
||||
Routers.h264View,
|
||||
);
|
||||
}
|
||||
} else if (call.method == 'callkit_declined') {
|
||||
print('返回主页面');
|
||||
} else {
|
||||
print('收到未知事件: ${call.method}');
|
||||
}
|
||||
});
|
||||
print('CallKitHandler.setupListener 监听已注册');
|
||||
}
|
||||
|
||||
/// 通知原生端结束CallKit通话
|
||||
static Future<void> endCall() async {
|
||||
print('CallKitHandler.endCall 通知原生端结束通话');
|
||||
await _channel.invokeMethod('end_call');
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user