IOS-电话拦截
IOS10的电话拦截理念与android不一样,基于隐私保护的理念IOS没把对方号码送给应用,因此需要反过来由app把需要识别或拦截的电话存入系统数据库。这一功能通过Call Directory Extension模块实现(具体操作请见https://blog.csdn.net/sinat_30336277/article/details/54944057,或者https://www.jianshu.com/p/e3d0acda8dda),通过在Blocking和Indentification两个相关的方法中进行黑名单生成及识别号码的生成。用户在设置->电话->来电阻止与身份识别界面下开启应用的该项功能时,Extension应用的beginRequestWithExtensionContext方法会被系统调用。通过在addAllBlockingPhoneNumbersToContext函数里实现了某些固话号码段的屏蔽。这样实现的屏蔽号码,在设置界面下是看不到。
需要注意的问题:
1、电话号码要加国别、区号、升序排列、唯一,xcode默认生成的代码有问题,正确号码格式应该如:+8618907311234、+8673122126000。可参见:https://blog.csdn.net/Rex_xing/article/details/78184598
2、系统电话簿优先级高于此方法设置的识别号码,也就是同时有设置的情况下只会显示号码簿里面的姓名。
3、黑名单拦截的来电不会在历史通话中显示。
4、在按需更新号码的时候要注意如果插入了重复号码会失败(Extention模块中系统不会返回错误信息,只是在宿主进程的reloadExtensionWithIdentifier时返回错误),因此采取全量更新的办法。每次先调用removeAllIdentificationEntries,然后再插入。当然也可以在每个号码插入前先调用removeIdentificationEntryWithPhoneNumber。
5、使用sqlite3的时候,号码字段一定要记得采用bigint,我就是因为采用了int类型导致插入号码时好时坏。
6、号码的别名一定不要太长。之前犯糊涂,别名字段设置了个varchar(128),库中有大量的长度为三四十个字符的记录,结果总是报更新失败,又不知道原因。由于获取不到有效的调试信息,百思不得其解,熬了好几个夜才在一次偶然的情况下看到内存不足的信息,才慢慢发现这个问题。
7、另外,有个奇怪的、一直未能找到原因的现象:由于采用sqlite的数据库文件作为本地资源(懒得从网络更新),但插入该文件到工程中后很诡异的出现Extention不能运行,时好时坏,坏的时候连重装app都不灵。不过在后期使用中没再碰到过该问题。
下面是我的屏蔽多个号码段的代码:
1 CXCallDirectoryPhoneNumber allPhoneNumbers[] = { +8673122126000, +8673122129000, +8673182984000, +8673189520000, +8673189522000, +8673189526000, +8673189527000, +8673189587000 }; 2 NSUInteger count = (sizeof(allPhoneNumbers) / sizeof(CXCallDirectoryPhoneNumber)); 3 for (NSUInteger index = 0; index < count; index += 1) { 4 CXCallDirectoryPhoneNumber phoneNumber = allPhoneNumbers[index]; 5 for(int i=0;i<1000;i += 1){ 6 [context addBlockingEntryWithNextSequentialPhoneNumber:phoneNumber+i]; 7 } 8 }
每次通过设置来触发号码修改不方便,可以通过在宿主应用中主动触发Extension来刷新。在宿主应用中合适的位置(更行了号码数据后)调用下面的函数updateNumber,触发Extension的CallDirectoryHandler类的beginRequestWithExtensionContext方法(context.isIncremental为true)。xcode的示例代码会调用addOrRemoveIncrementalBlockingPhoneNumbersToContext和addOrRemoveIncrementalIdentificationPhoneNumbersToContext来更新号码。其中"xxx.qrcode.phone"是Extention应用的Bundle Identifier
- (void)updateNumber{ CXCallDirectoryManager *manager = [CXCallDirectoryManager sharedInstance]; [manager reloadExtensionWithIdentifier:@"xxx.qrcode.phone" completionHandler:^(NSError * _Nullable error) { if (error == nil) { UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"更新成功" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; [alert addAction:defaultAction]; [self presentViewController:alert animated:YES completion:nil]; }else{ UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"更新失败" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; [alert addAction:defaultAction]; [self presentViewController:alert animated:YES completion:nil]; } }]; }
此外,还有几个功能没尝试:
1、检查用户授权。参见:https://blog.csdn.net/qq_26918391/article/details/52913028、https://blog.csdn.net/qq_30513483/article/details/52768699?locationNum=1
2、实时监听来电。如:https://www.2cto.com/kf/201607/525336.html、https://blog.csdn.net/gf771115/article/details/46649115、https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653578016&idx=2&sn=ae1474cbc3037e5c00e6da5c69cd8569&chksm=84b3b127b3c43831191d37ca0e86d2f2f7b97d180d8c0ccd6dedb9c4a9a9a8c0af909d28d558&scene=4#wechat_redirect
3、与宿主应用间数据共享(Extension与主应用是两个应用,主应用的获取的数据如果需要传递到extension,得用到appgroup)。如:https://blog.csdn.net/Rex_xing/article/details/78184598、https://www.jianshu.com/p/7f8472a97aa6