版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.02.01 |
前言
苹果 iOS 10 新发布了一个新的框架CallKit,使第三方VOIP类型语音通话类APP有了更好的展现方式和用户体验的提升,接下来这几篇我们就一起看一下这个框架。
Overview
先看一下该框架的基本信息。
CallKit框架可以显示App的VoIP服务的系统调用UI,并协调其他应用程序和系统与您的呼叫服务。
CallKit可让您将呼叫服务与系统上其他与呼叫相关的应用程序集成在一起。 CallKit提供了呼叫接口,您可以使用VoIP服务处理后端通信。 对于传入和传出呼叫,CallKit显示与电话应用程序相同的接口,为您的应用程序提供更原生的外观和感觉。 CallKit可以正确响应系统级别的行为,例如Do Not Disturb
。
除了处理呼叫之外,您还可以提供Call Directory
应用程序扩展程序,以提供来电显示信息以及与您的服务关联的黑名单列表。
在苹果官方WWDC16 Enhancing VoIP Apps with CallKit(Session 230)
中,苹果的工程师为我们展示了集成Call Kit后的VOIP 通话APP的效果,例如在iPhone锁屏状态下APP来电时,通过Call Kit可以像iOS原生电话来电一样展现全屏的来电及接听界面,VOIP APP与系统Call有着相同的通话优先级别,而且在通讯录中的拔号记录,Siri唤起,勿扰模式等都有着很好的支持。
下面看一下原生APP、第三方APP在CallKit框架下的关系,在需要的时刻,原生或者第三方APP通过Call Kit提供的API向系统请求诸如来电、拔出等展现服务,由Call Service统一安排调度这些请求以达成统一的交互响应。
下面看一下框架的基本结构。
Receiving an Incoming Call - 接收来电
要配置您的应用程序以接收来电,请首先创建一个CXProvider对象并将其存储以供全局访问。 应用程序会向provider
报告来电,以响应外部通知,例如由PushKit生成的VoIP推送通知。
// Listing 1 Receiving a VoIP–related push notification
// MARK: PKPushRegistryDelegate
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
// report new incoming call
}
注意:有关VoIP推送通知和
PushKit
的更多信息,请参阅 Voice Over IP (VoIP) Best Practices。
使用外部通知提供的信息,应用程序将创建一个UUID
和一个CXCallUpdate对象来唯一标识调用和调用者,并使用 reportNewIncomingCallWithUUID:update:completion:方法将它们传递给provider
。
// Listing 2 Handling an incoming call
if let uuidString = payload.dictionaryPayload["UUID"] as? String,
let identifier = payload.dictionaryPayload["identifier"] as? String,
let uuid = UUID(uuidString: uuidString)
{
let update = CXCallUpdate()
update.callerIdentifier = identifier
provider.reportNewIncomingCall(with: uuid, update: update) { error in
// …
}
}
在呼叫连接之后,系统调用provider委托provider:performStartCallAction:方法。 在你的实现中,委托负责配置一个AVAudioSession,并在完成时调用fulfill。
// Listing 3 Initiating the audio for a call
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// configure audio session
action.fulfill()
}
Making Outgoing Calls - 打出电话
用户可以通过以下任何方式使用VoIP应用发起呼叫:
- 在应用程序内执行交互
- 使用受支持的自定义网址方案打开链接
- 使用Siri启动VoIP呼叫
要发出呼叫,应用程序将从其CXCallController对象请求一个CXStartCallAction对象。 该操作由唯一标识呼叫的UUID和指定收件人的CXHandle对象组成。
// Listing 4 Starting an outgoing call
let uuid = UUID()
let handle = CXHandle(type: .emailAddress, value: "jappleseed@apple.com")
let startCallAction = CXStartCallAction(call: uuid)
startCallAction.destination = handle
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { error in
if let error = error {
print("Error requesting transaction: \(error)")
} else {
print("Requested transaction successfully")
}
}
注意:有关注册和处理URL的更多信息,请参阅 Using URL Schemes to Communicate with Apps。有关使用Siri启动呼叫的更多信息,请参阅INStartAudioCallIntentHandling协议。
收件人应答呼叫后,系统会调用provider代理 provider:performStartCallAction:方法。 在你实现这个方法的时候,配置一个AVAudioSession,并在完成时调用action对象的fulfill方法。
// Listing 5 Initiating the call
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// configure audio session
action.fulfill()
}
注意:下载Speakerbox: Using CallKit to create a VoIP app程序示例代码项目,该示例演示如何使用CallKit框架创建VoIP应用程序。
Call Blocking and Identification - 呼叫阻止和识别
应用程序可以创建一个Call Directory应用程序扩展,以通过电话号码识别和阻止来电者。
Call Directory扩展中的电话号码由
CXCallDirectoryPhoneNumber
类型表示,由国家代码(如北美的1或中国的86)组成,后跟数字序列。
Creating a Call Directory App Extension - 创建一个Call Directory程序扩展
您可以通过添加一个新的项目目标并选择应用程序扩展下的Call Directory扩展模板来为您的应用程序创建一个Call Directory扩展。
您在Call Directory扩展的CXCallDirectoryProvider子类的beginRequestWithExtensionContext:方法的实现中设置了传入呼叫的标识和阻止。 系统启动应用扩展程序时调用此方法。
有关应用扩展程序的更多信息,请参阅 App Extension Programming Guide。
Identifying Incoming Callers - 识别来电
当电话收到来电时,系统首先咨询用户的联系人以找到匹配的电话号码。如果找不到匹配项,则系统会查询您的应用程序的呼叫目录分机以查找匹配的条目以识别电话号码。这对于维护与系统联系人分离的用户的联系人列表(例如社交网络)或者用于识别可以从应用内发起的来话呼叫的应用是有用的,诸如用于客户服务支持或者递送通知。
例如,考虑在社交网络应用程序中与Jane交朋友的用户,但是他们的联系人中没有她的电话号码。社交网络应用程序具有呼叫目录应用程序扩展,下载并添加所有用户的朋友的电话号码。因此,当用户从Jane收到来电时,系统会显示“(App Name)Caller ID:Jane Appleseed”
,而不是“Unknown Caller”
。
要提供有关传入调用者的标识信息,可以在beginRequestWithExtensionContext:的实现中使用 addIdentificationEntryWithNextSequentialPhoneNumber:label:方法。
// Listing 6
@interface CustomCallDirectoryProvider: CXCallDirectoryProvider
@end
@implementation CustomCallDirectoryProvider
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context {
NSDictionary<NSNumber *, NSString *> *labelsKeyedByPhoneNumber = @{ … };
for (NSNumber *phoneNumber in [labelsKeyedByPhoneNumber.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
NSString *label = labelsKeyedByPhoneNumber[phoneNumber];
[context addIdentificationEntryWithNextSequentialPhoneNumber:(CXCallDirectoryPhoneNumber)[phoneNumber unsignedLongLongValue] label:label];
}
[context completeRequestWithCompletionHandler:nil];
}
@end
由于此方法仅在系统启动应用程序扩展而不是针对每个单独呼叫时调用,因此您必须一次指定呼叫标识信息;例如,您不能向Web服务请求查找有关来电的信息。
Blocking Incoming Calls - 阻止来电
当电话收到来电时,系统首先查询用户的阻止列表以确定是否应阻止呼叫。 如果电话号码不在用户或系统定义的阻止列表中,则系统会查询您的应用程序的呼叫目录扩展以查找匹配的阻止号码。 例如,这对于维护已知律师的数据库或允许用户阻止符合一组标准的任何数字的应用程序很有用。
要阻止特定电话号码的来电,可以在beginRequestWithExtensionContext:的实现中使用 addBlockingEntryWithNextSequentialPhoneNumber:方法。
注意:您可以指定您的呼叫目录应用程序扩展在其beginRequestWithExtensionContext:的实现中添加标识和/或阻止电话号码。
// Listing 7
@interface CustomCallDirectoryProvider: CXCallDirectoryProvider
@end
@implementation CustomCallDirectoryProvider
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context {
NSArray<NSNumber *> *blockedPhoneNumbers.sorted = @[ … ];
for (NSNumber *phoneNumber in [blockedPhoneNumbers.sorted sortedArrayUsingSelector:@selector(compare:)]) {
[context addBlockingEntryWithNextSequentialPhoneNumber:(CXCallDirectoryPhoneNumber)[phoneNumber unsignedLongLongValue]];
}
[context completeRequestWithCompletionHandler:nil];
}
@end
Topics
1. First Steps
与通话相关的操作通过您的provider及其代理进行路由,您可以使用与您的服务进行通信。
-
- 代表电话provider的对象
-
- 由电话服务提供者对象调用的一组方法。
-
- 提供者对象的配置封装。
2. Incoming Calls
当PushKit通知指示来电时,您将生成适当的操作。 CallKit通过呈现用于应答呼叫的系统界面来处理该操作。
-
- 接听来电的行为的封装。
-
- 封装有关呼叫的新的和已更改的信息。
3. Outgoing Calls
呼叫控制器开始传出呼叫,并处理后续与您的provider代理交互。
-
- 用于与呼叫进行交互和观察的程序化界面。
-
- 包含零个或多个要由呼叫控制器执行的操作对象的对象。
-
- 发起呼叫行为的封装。
4. Call-Related Actions
回应CallKit报告的操作。
-
- 一个抽象类,为表示电话操作的对象声明一个编程接口。
-
- 表示与呼叫对象关联的电话操作的对象的编程接口。
-
- 封闭了结束通话的行为。
-
- 播放双音多频(DTMF)序列的封装。
-
- 分组或取消分组呼叫的封装。
-
- 将通话保持或将通话移除的行为的封装。
-
- 封闭静音或取消静音的行为。
5. Call Information
获取有关通话的信息,并在通话状态发生变化时收到通知。
-
- 电话呼叫。
-
- 用于管理活动呼叫列表并监视呼叫更改的对象的编程接口。
-
- 呼叫改变状态时由呼叫观察者对象调用的方法的集合。
-
- 可以到达呼叫接收方的方式,例如电话号码或电子邮件地址。
6. Caller ID
使用呼叫目录应用程序扩展可阻止呼叫并提供来电显示信息。
-
- 主机应用程序的Call Directory应用程序扩展的主要目标。
-
CXCallDirectoryExtensionContext
- 用于添加识别和阻止条目到Call Directory应用程序扩展的编程接口。
-
CXCallDirectoryExtensionContextDelegate
- 请求失败时由Call Directory扩展上下文对象调用的一组方法。
-
- 管理Call Directory应用程序扩展的对象的编程接口。
参考文章
- iOS Call Kit for VOIP
- XAMARIN Introduction to CallKit
- WWDC16 Session 230 (Enhancing VoIP Apps with CallKit)
- Apple Call Kit Speakerbox Demo
- PushKit Practice
后记
本篇已结束,后面更精彩~~~~