【关注 融云全球互联网通信云】2016 年,苹果 iOS10 发布了 CallKit 框架,使第三方 VoIP 类型语音通话类 APP,可以拥有与手机系统一样的来电体验——直接显示在锁屏界面,并且通话过程中,APP 的音视频权限和运营商电话一样,不会被其他应用打断。如何实现?
2018 年,苹果 APP 审核中心通过邮件告知开发者:在中国大陆地区上架的 APP 不可使用 Callkit。
并且,从 iOS13 开始,基于安全角度考虑,苹果要求在使用 VoIP 推送时必须配合 CallKit 框架使用,否则 iOS 系统将在收到 VoIP 推送后杀掉 APP 进程,就像没有收到 VoIP 推送一样。
苹果 CallKit 框架无法在国内上架使用,我们也就无法在国内使用 VoIP 推送功能在手机后台唤醒息屏了的 APP。
但是,对于在没有上架限制地区投放的应用,苹果 CallKit 依然是提升用户使用体验的重要手段。
当下,出海浪潮浩浩荡荡,融云作为布局全球的通信云服务商,为全球开发者提供安全、可靠的互联网通信云服务。上架海外应用商店的 APP,在使用融云 SDK 获得稳定通信能力后集成苹果 CallKit,可以大幅提高用户体验和使用便捷性。
本文分享通过苹果 CallKit 框架实现来电、接听、挂断、呼叫等通话场景的流程。
苹果 CallKit 效果
在 iPhone 锁屏状态下 APP 来电时,通过苹果 CallKit 可以像 iOS 原生电话来电一样展现全屏的来电及接听界面,VoIP APP 与系统 Call 有着相同的通话优先级别,而且在通讯录中的拔号记录、Siri 唤起、勿扰模式等都可以得到很好的支持。
下图简略描述了原生 APP、第三方 APP 在 CallKit 框架下的关系。CallKit 在系统中提供了一种独有的服务,在需要的时刻,原生或者第三方 APP 通过 CallKit 提供的 API 向系统请求诸如来电、拔出等展现服务,由 Call Service 统一安排调度这些请求以达成统一的交互响应。
如何使用苹果 CallKit
苹果 CallKit 提供了统一的语音通话 UI 及与该 UI 交互的 API,但实际的通话链路监听、搭建和管理还需要沿用 APP 原有的实现思路。下面,我们分享来电、拔出等场景下 APP 与 CallKit 的交互流程。
Prepare
① 创建 CXProvider,指定 CallKit 展现 UI 中的 APP 名称和图标、通话数量、来电铃声等 Configuration
② 实现 CXProviderDelegate 协议,以接收来自 Call Service 发来的更新状态,例如用户点击了接听或者挂断等动作,决定网络链路的处理动作;还有 AudioSession 的激活状态,决定 Audio 播放录制的启动关闭时机
③ 创建 CXCallController,使 APP 可以发送更新状态给 Call Service,例如用户拔出电话或者对方挂断电话等状态
④ 如果需锁屏界面及 APP 未启动状态下显示来电界面,要搭建 PushKit 通路,与 APNS 差不多,只是 APP 端处理方式有些不同。
Incoming Call
① APP 前台时收到来自网络 Server 端的连接请求,或者 APP 后台时收到来自网络 Push Server 的 PushEvent
② APP 收到连接请求或者 Push 消息后,创建 CXCallUpdate 对象,指定此次来电的号码等属性
③ 将上面创建的 CXCallUpdate 对象通过 CXProvider 的 reportNewIncomingCall WithUUID 方法报告给 iOS 系统
④ Call Service 收到新的来电请求后根据当前的状态,展现原生来电 UI
Answer Call
① 用户点击来电界面上的接听按钮
② Call Service 通过 CXProvider 的 Delegate 协议 performAnswerCallAction 方法告知 APP
③ APP 将接听命令通过网络传给对端,开始实际音频数据传输,进行通话
End Call
① 用户点击 APP UI 中的挂断按钮
② 创建 CXEndCallAction 对象,指定此次通话的 UUID 属性
③ 创建 CXTransaction,将 Action 指定给它
④ 通过 CXCallController,调用 request Transaction 将这个挂断事件通知给 Call Service
⑤ Call Service 通过当前通话状态,通过 CXProvider 将挂断动作通知回给 APP
⑥ 在 CXProviderDelegate 中的 performEnd CallAction 中结束此次通话的网络链路,停止音频录制播放 Loop
Outgoing Call
① 用户通过 APP UI、通话录、Siri 发起一个拔出请求
② 创建 CXHandle 指定拨出的电话号码,创建 CXStartCallAction 并将 CXHandle 指定给它
③ 创建 CXTransaction,将刚刚的 Action 指定给它
④ 通过 CXCallController 调用 request Transaction,将这个拔出事件通知给 Call Service
⑤ Call Service 收到新的拨出请求后根据当前的状态,通过 CXProvider 将拨出动作通知回 APP
⑥ 在 CXProviderDelegate 中的 perform StartCallAction 中开启此次呼叫的网络链路,通过 CXProvider 的 reportOutgoing CallWithUUID 设置呼叫与接通时间,根据链路建立的结果来展现原生呼叫 UI 的状态(呼叫成功或者失败)
苹果 CallKit 开发框架,赋予语音或视频通话应用的开发者诸多便利——
允许开发者将 UI 界面整合在 iPhone 原生的电话 APP 中;
允许开发者将通讯 APP 的功能内建在电话 APP 的“常用联络资讯”以及“通话记录”,方便用户透过原生电话 APP,直接取用这些第三方功能;
允许用户在通知中心直接浏览并回复来电,来电的画面也将整合在 iOS 原生的 UI 里。
总而言之,苹果 CallKit 让 iOS 原本单纯用来打电信电话的“电话”功能,能够结合众多第三方语音通讯软件,具备更完整的数码电话能力。而对融云服务的广大出海开发者来说,集成苹果 CallKit,应用内的 VOIP 通话可以获得系统级的通话效果,极大地提升用户使用体验。