ios - 未调用 CXProviderDelegate 方法

标签 ios objective-c callkit

我的目标是在用户接听电话后打开我的 CallViewController。我在这里阅读了一些摘录,因此可以使用以下方法完成:

- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
    NSLog(@"performAnswerCallAction");
}

- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
     NSLog(@"performStartCallAction");
}

上面的代码在 AppDelegate 中。

但是,使用 NSLogs,这些方法根本不会被触发。我似乎找不到任何关于使用 Objective-C 实现的教程,这些教程很容易从初学者的 POV 理解。我将不胜感激任何见解,谢谢!

最佳答案

首先,你是否设置了CXProvider的delegate?

let provider = CXProvider(configuration: your_call_kit_config)
provider.setDelegate(self, queue: nil) // 'nil' means it will run on main queue

另外,让 AppDelegate.swift 文件符合 CXProviderDelegate

provider:performAnswerCallAction: 当用户点击系统提供的来电屏幕上的“接听”按钮时调用。 (苹果文档 HERE)。

provider:performStartCallAction: 在成功请求 CXCallController 以执行 CXStartCallAction 后被调用(Apple 文档 HERE)。

编辑:对于 Objective-C

好的,这里是 Objective-C 片段,例如,在 AppDelegate 中。首先,你需要让AppDelegate符合CXProviderDelegate,像这样:

@interface AppDelegate () <CXProviderDelegate>

然后,为 CXProviderCXCallController 添加一个属性,如下所示:

@interface AppDelegate () <CXProviderDelegate>

@property (nonatomic, nonnull, strong) CXProvider *provider;
@property (nonatomic, nonnull, strong) CXCallController *callController;

@end

在 AppDelegate 的函数 application:willFinishLaunchingWithOptions: 中,使用调用配置初始化 CXProvider 对象,如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Setup CallKit
    CXProviderConfiguration *providerConfiguration = [[CXProviderConfiguration alloc] initWithLocalizedName:@"MyApp"];
    providerConfiguration.supportsVideo = YES;
    providerConfiguration.includesCallsInRecents = YES;
    self.provider = [[CXProvider alloc] initWithConfiguration: providerConfiguration];

    // Since `AppDelegate` conforms to `CXProviderDelegate`, set it to the provider object
    // Setting 'nil' to `queue` argument means, that the methods will be executed on main thread.
    // Optionally, you can assign private serial queue to handle `CXProvider` method responses
    [self.provider setDelegate:self queue:nil];

    // Initialize `CallController`
    self.callController = [[CXCallController alloc] init];

    return YES;

AppDelegate.m文件的底部,实现CXProviderDelegate方法:

#pragma mark: - CXProvider delegate methods

- (void)providerDidReset:(CXProvider *)provider {
    // Drop all calls here (if there are pending)
}

/*!
 This method gets called when user presses on 'Accept' button on the incoming call screen provided by the system.
 Here you should configure `AVAudioSession` for VoIP calls and handle logic for answering the call.
 */
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
    // Put your answering logic here
    // Note: It is important to fulfill the action inside the scope of it's function, or to fail, depending if error occured during answering
    [action fulfill];
}

/*!
 This method gets called when CXCallController object finishes the CXStartCallAction request. You need to request
 start call action to the CXCallController instance, when starting an outgoing VoIP call. After successful transaction,
 the provider will respond with this delegate method. Here you should also configure `AVAudioSession` for VoIP calls.
 */
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
    // Put your outgoing call action here
    // Note: It is important to fulfill the action inside the scope of it's function, or to fail, depending if error occured during starting a call
    [action fulfill];
}

要开始拨出 VoIP 调用,您需要向 CXCallController 实例请求带有操作的事务,如下所示:

#pragma mark - Call Controller requests

- (void)startOutgoingVoIPCallWithNumber:(NSString *)number {
    NSUUID *callUUID = [NSUUID UUID]; // Here you create or assign UUID of call.
    CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:number];
    CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:callUUID handle:callHandle];
startCallAction.video = YES; // Yes or no is call is video or audio.

    CXTransaction *startCallTransaction = [[CXTransaction alloc] initWithAction:startCallAction];

    [self.callController requestTransaction:startCallTransaction completion:^(NSError * _Nullable error) {
        if (error) {
            // Handle start call error here
            // Ususally, error occurs if the system cannot handle the new outgoing call, since there are others pending
        }
        // If there is no error, CXProvider will respond with `provider:performStartCallAction:` method.
    }];
}

显示系统调用界面

#pragma mark - Report New incoming call

/*!
 You need to call this function each time you receive a new incoming call, usually right from the VoIP push notification.
 */
- (void)reportNewIncomingCallWithNumber:(NSString *)number {
    NSUUID *callUUID = [NSUUID UUID]; // Call UUID, you should have this in some Call object, not generating the new here
    CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:number];
    CXCallUpdate *callInfo = [[CXCallUpdate alloc] init];
    callInfo.remoteHandle = callHandle;
    [self.provider reportNewIncomingCallWithUUID:[NSUUID UUID] update:callInfo completion:^(NSError * _Nullable error) {
        if (error) {
            // Handle error here
        }
        // If there is no error, system will display incoming call screen and when user taps on 'Answer',
        // `CXProvider` will respond with `provider:performAnswerCallAction:`
    }];
}

关于ios - 未调用 CXProviderDelegate 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52529501/

相关文章:

ios - 如何为 CallKit 来电 UI 设置超时

objective-c - didActivateAudioSession 很少不被调用

ios - 在浏览器中启动应用后验证

objective-c - MPMoviePlayerController 播放直播流

objective-c - 带有音频文件的 iPhone 应用程序太大了。如何减小尺寸?

ios - 使用 CallKit 接听电话时如何显示 ViewController

iphone - iOS 同步动画

ios - NSURLConnection 完成错误 - 代码 -1022

ios - 为什么 collectionView.scrollToItem 使用 Swift 将 indexPath 滚动到 View 之外?

ios - CoreData 所需类型 = NSManagedObject;给定类型 = __NSSingleObjectSetI