CallKit的研究
最近帮一个朋友做一个app,他有一个需求,希望来电话时候,可以在来电界面显示来电的相关信息,信息就来自于app内(app内维护一个企业通讯录,来电话的时候即使这个号码不在系统通讯录内,也可以通过app的通讯录查出来)。android肯定是没问题的,再iOS10 之前是不可想的,不过现在iOS 10 开放了CallKit的N多权限,我就研究了下。
认证来电呼叫(Identifying Incoming Callers)
app可以创建一个呼叫目录扩展(Call Directory Extension)来认证或者屏蔽来电。字面意思来看,认证来电这项貌似我们的要求匹配。
注意:电话号码需要用CXCallDirectoryPhoneNumber(int_64类型)来承载,同时包含了电话号码和国家码,中国是86,没有+。
iPhone收到来电后,系统首先查询系统通讯录。如果没有匹配信息,再去查找app的Call Directory。找到了,就会显示相关信息。
场景:你的某个社交app的好友给你打来电话,但是你根本就没存他的号码,一直都是用app的聊天私信之类的联系。这时候来电显示就能显示出相关信息,而不是纯陌生号码了。
操作
1、新建Call Directory Extension
新建一个target,选择Application Extensions - Call Directory Extension,注意和主target的bundle id要区分出来。
2、补充代码
创建完后,工程下会多出一个目录,自动生成CXCallDirectoryProvider子类,根据里面的代码进行补充。
- (void)beginRequestWithExtensionContext:(CXCallDirectoryExtensionContext *)context {
NSDictionary<NSNumber *, NSString *> *labelsKeyedByPhoneNumber = @{@(8613511111111) :@"我是周杰伦"};
for (NSNumber *phoneNumber in [labelsKeyedByPhoneNumber.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
NSString *label = labelsKeyedByPhoneNumber[phoneNumber];
[context addIdentificationEntryWithNextSequentialPhoneNumber:(CXCallDirectoryPhoneNumber)[phoneNumber unsignedLongLongValue] label:label];
}
[context completeRequestWithCompletionHandler:nil];
}
3、关键问题
app内通讯录数据都是从接口获取的,app第一次启动的时候肯定是没有的。文档上说,上面的方法只在系统启动app扩展的时候调用一次,我们必须在调用的时候就把认证信息都传进去,也就是说想通过接口取网络数据更新认证名单是没戏了。
demo中,点击get Contact Data按钮会利用NSUserDefaults存储一个简单的数据来模拟获取的通讯录数据,然后在beginRequestWithExtensionContext中进行读取。数据的传递利用app group。
4、总结
感觉并没有达到我的预期效果,主要问题
- 无法更新认证名单
- 系统通讯录如果存在这个号码,基本就没作用了。
- 卸载了app,通话记录还会存在认证信息。
iOS的权限开放程度和几年前比真是相差万别,现在系统也越来越花哨,总有一种感觉是为了迎合中国用户的需求。我还是喜欢简洁实用的系统。