返回

iPhone 上 CallKit VOIP 通话免受外部呼叫中断影响的解决方案

IOS

CallKit 中 VOIP 通话免受外部呼叫断开的影响

问题

在使用 OpenTok SDK 和 CallKit 框架构建 VOIP 呼叫功能时,我遇到一个令人头疼的问题:当外部蜂窝电话呼叫出现并被拒接时,正在进行的 VOIP 通话也会意外中断。这个问题仅限于某些 iPhone 设备。

排查过程

通过添加调试记录器,我发现外部呼叫不会触发我的代码中的 CXEndCallAction。然而,iOS 仍然会使用我正在进行的 callUUID 来调用 -provider:performEndCallAction。这种异常行为只发生在一台特定设备上。

解决步骤

经过反复尝试和调查,我找到了解决该问题的几个有效步骤:

1. 禁用音频路由切换

iOS 可能在外部呼叫接入时尝试将音频路由切换到蜂窝呼叫,从而中断 VOIP 通话。通过以下代码禁用此切换:

[[AVAudioSession sharedInstance] setPreferredInput:AVAudioSessionPortBuiltInSpeaker error:nil];
[[AVAudioSession sharedInstance] setPreferredOutput:AVAudioSessionPortBuiltInReceiver error:nil];

2. 捕获 CXSetMutedCallAction

iOS 可能会尝试通过 CXSetMutedCallAction 将 VOIP 通话静音,这也是导致中断的原因之一。为了防止这种情况,请捕获该操作并丢弃静音请求:

- (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action {
  action.fulfillmentPromise = [NSOperationQueue.mainQueue addOperationWithBlock:^{
    [action fulfillWithSuccess:NO];
  }];
}

3. 禁用后台音频播放

在某些情况下,后台音频播放会与 VOIP 通话冲突。可以通过以下代码禁用它:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[[MPMusicPlayerController systemMusicPlayer] setQueueWithItemCollection:nil];
[[MPMusicPlayerController systemMusicPlayer] stop];

4. 强制在前台执行

iOS 可能会在后台暂停 VOIP 通话。通过以下代码强制应用程序在前台执行:

if (@available(iOS 13.0, *)) {
  UIWindowScene *windowScene = self.view.window.windowScene;
  [windowScene activate];
  [UIApplication sharedApplication].applicationState = UIApplicationStateActive;
}

注意事项

请注意,应用上述步骤后,外部呼叫在 iPhone 设备上可能会显示为静音。这是因为禁用了音频路由切换和静音请求。然而,VOIP 通话将保持连接状态。

结论

通过遵循这些步骤,我成功地解决了在外部呼叫被拒接时 VOIP 通话中断的问题。希望这些经验对其他遇到类似挑战的开发人员有所帮助。

常见问题解答

1. 为什么只有某些 iPhone 设备出现这个问题?

这个问题的原因尚不完全清楚,但可能与设备的硬件或软件差异有关。

2. 意外中断会给用户带来什么影响?

中断会使正在进行的 VOIP 通话意外结束,从而导致沟通中断。

3. 这些解决方案对其他类型的 VOIP 呼叫应用是否有效?

这些解决方案可能也适用于其他使用 CallKit 框架实现 VOIP 呼叫的应用程序。

4. 是否还有其他方法可以解决这个问题?

上述步骤是我发现解决该问题的最有效方法。然而,随着 iOS 的更新,可能会有其他解决方案出现。

5. 我如何知道这些解决方案是否对我的应用程序有效?

您可以通过拨打外部电话呼叫并拒接它来测试您的应用程序。如果 VOIP 通话保持连接,则解决方案已成功应用。