iOS开发 - 来电识别和骚扰拦截
原作者:https://www.jianshu.com/p/9836bff5a0e0
需要注意的问题:
1、电话号码要加国别、区号、升序排列、唯一,xcode默认生成的代码有问题,正确号码格式应该如:+8618907311234、+8673122126000。
1.1 另外400号码属于虚拟号码, 放在PhoneNumber中的正确格式是,+86400xxxxxxx, 无区号.
1.2 目前好像只能全量更新数据,不能增量更新,效率比较低.
1.3 最大数量在100万到200万之间,原因可能是超时无效.
1.4 排序是指处理完号码, 添加国家码后的表单进行升序排列.
可参见: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都不灵。不过在后期使用中没再碰到过该问题。
- 苹果默认生成的代码, 号码格式是错误的, 请按照本文的要求生成.
一、创建一个新的target

选择Call Directory Extension

选中主程序YSCallDemo这个target,找到App Group打开
勾选一个开发者team

选中用于号码识别的target同样找到App Group打开
勾选一个开发者team

两个target都选中后会多了一个YSCallDemo.entitlements

有时候会出现文件找不到的情况,可以在target-->build phases里手动添加编译文件

二、准备号码库,更新号码识别库就可以号码识别了
//这里是采用realm数据库来存储号码,路径选择共享路径即可
- (void)realmConfiguation {
NSURL *url = [[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.yasha.group"] URLByAppendingPathComponent:@"IDCall"] URLByAppendingPathExtension:@"realm"];
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
// APP Group 宿主程序数据库共享
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.fileURL = [[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.yasha.group"] URLByAppendingPathComponent:@"IDCall"] URLByAppendingPathExtension:@"realm"];
[RLMRealmConfiguration setDefaultConfiguration:configuration];
NSLog(@"数据库地址:%@", [RLMRealmConfiguration defaultConfiguration].fileURL);
// 数据迁移
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
}
更新号码识别库
//调用这个方法就可以将数据写入到号码识别库
CXCallDirectoryManager *manager = [CXCallDirectoryManager sharedInstance];
[manager reloadExtensionWithIdentifier:@"yasuo.YSCallDemo.CallExtension" completionHandler:^(NSError * _Nullable error) {
}
调用更新后程序自动执行CallDirectoryHandler.m的方法
- (void)beginRequestWithExtensionContext:(CXCallDirectoryExtensionContext *)context {
context.delegate = self;
[self addOrRemoveIncrementalIdentificationPhoneNumbersToContext:context];
//这里直接调用号码增加和移除的方法
[context completeRequestWithCompletionHandler:nil];
}
调用这个方法数据写入
(void)addOrRemoveIncrementalIdentificationPhoneNumbersToContext:(CXCallDirectoryExtensionContext *)context {
//配置数据库
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.fileURL = [[[[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:@"group.com.yasha.group"] URLByAppendingPathComponent:@"IDCall"] URLByAppendingPathExtension:@"realm"];
[RLMRealmConfiguration setDefaultConfiguration:configuration];
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
RLMResults *results = [[YSContactModel allObjects] sortedResultsUsingKeyPath:@"phone" ascending:YES];
[realm commitWriteTransaction];
if (results.count != 0) {
[context removeAllIdentificationEntries];
NSMutableArray *allPhoneNumbersArray = [NSMutableArray array];
NSMutableArray *labelsArray = [NSMutableArray array];
for (YSContactModel *model in results) {
[allPhoneNumbersArray addObject:[NSString stringWithFormat:@"%zd",model.phone ]];
[labelsArray addObject:model.name];
}
for (NSUInteger i = 0; i < allPhoneNumbersArray.count; i ++) {
CXCallDirectoryPhoneNumber phoneNumber = [allPhoneNumbersArray[i] longLongValue];
NSString *label = labelsArray[I];
[context addIdentificationEntryWithNextSequentialPhoneNumber:phoneNumber label:label];
}
}
}
这里就可以实现号码识别了
三、常见错误
号码存入时需要加国家区号,要升序排列
比如com.apple.CallKit.error.calldirectorymanager Code=4 表示数据重复
授权没打开也会报,Domain=com.apple.CallKit.error.calldirectorymanager Code=6
官方
网上找的swift版本的报错枚举
public enum Code : Int {
public typealias _ErrorType = CXErrorCodeCallDirectoryManagerError
case unknown
case noExtensionFound
case loadingInterrupted
case entriesOutOfOrder
case duplicateEntries
case maximumEntriesExceeded
case extensionDisabled
@available(iOS 10.3, *)
case currentlyLoading
@available(iOS 11.0, *)
case unexpectedIncrementalRemoval
}
三、通过cocoapod进来的第三方和让共享target可以使用的方法
第一步:
PROJECT --info --configurations,将对应的Debug和Release 设置成pods-你的Xcode项目名.debug和pods-你的Xcode项目名.release。
这些是在下图中可以选择的,不需要手动填写。!

31A227EF2AD6879836E434A72CC3F038.jpg
第二步:
TARGETS--Build Phases --Link Binary With Libraries,将pods的.a文件引入

作者:白河三
链接:https://www.jianshu.com/p/9836bff5a0e0
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。