最近項(xiàng)目中新增了一個需求,需要使用
iOS 10
中新增的CallKit
來實(shí)現(xiàn)一個來電識別的功能验毡。按照慣例,先在網(wǎng)上搜索了一下帝嗡,看了幾篇文章晶通,覺得實(shí)現(xiàn)起來很簡單嘛。于是就愉快的開始了哟玷,然后就開始遇見一個個坑狮辽,網(wǎng)上目前存在的文章都是簡單的實(shí)現(xiàn)了號碼識別,但是關(guān)于號碼規(guī)則巢寡、大數(shù)量的數(shù)據(jù)如何處理等都沒有提及喉脖。這篇文字就記錄下我個人在實(shí)現(xiàn)這個功能時遇到的坑以及如何解決的。
一抑月,具體實(shí)現(xiàn)
如何實(shí)現(xiàn)就不在詳細(xì)描寫了树叽,網(wǎng)上已經(jīng)有很多的文章寫了。
二谦絮,具體功能實(shí)現(xiàn)遇到的各種坑
號碼規(guī)則
- 號碼必須進(jìn)行排列题诵,添加順序?yàn)閮?yōu)先添加小的號碼洁仗。譬如:123和132兩個號碼要先添加123,然后添加132.
- 號碼的格式化性锭,手機(jī)號碼前面需要添加國家碼赠潦,固話需要帶有區(qū)號,然后區(qū)號去零草冈,然后前面添加國家碼她奥。譬如手機(jī)號:185XXXXX8497 需要格式化為86185XXXXX8497;固話 0755-12345678 需要格式化為:8675512345678.
- 號碼去重怎棱,一個手機(jī)號碼只能添加一次哩俭,添加多次會開啟失敗。
PS:大文件的號碼排序蹄殃、去重可以看看我的另一篇文章:大文件內(nèi)容使用shell 排序携茂、去重
大數(shù)量的數(shù)據(jù)如何添加
大數(shù)據(jù)不能一下讀取到內(nèi)存中,否則會導(dǎo)致打開失敗诅岩。我們給的號碼庫有三十幾M讳苦,大概100萬數(shù)據(jù),剛開始直接讀入內(nèi)存中吩谦,一直打開失敗鸳谜。解決辦法:從文件中一行行讀取數(shù)據(jù),使用后釋放式廷。我的號碼庫文件咐扭,大概這樣的形式:
[
{"86196852102": "騷擾電話"},
{"86196852201": "詐騙電話"},
{"86196852202": "騷擾電話"},
{"86196852213": "詐騙電話"},
{"86201008613": "廣告推銷"},
{"86202096585": "詐騙電話"},
{"86211008611": "廣告推銷"},
{"86216618834": "廣告推銷"},
{"86219506524": "騷擾電話"},
]
具體代碼如下:
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupIdentifierExtension];
//文件路徑
containerURL = [containerURL URLByAppendingPathComponent:LocalstorageName];
NSString* fileRoot = containerURL.path;
FILE *file = fopen([fileRoot UTF8String], "r");
char buffer[1024];
while (fgets(buffer, 1024, file) != NULL){
@autoreleasepool {
NSString* result = [NSString stringWithUTF8String:buffer];
result = [result stringByReplacingOccurrencesOfString:@"," withString:@""];
NSData *jsonData = [result dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error:&err];
if(err)
{
}else
{
NSString *number = dic.allKeys[0];
NSString *name = dic[number];
if (number == nil || name == nil)
{
}else {
// number = [self fixPhone:number];
CXCallDirectoryPhoneNumber phoneNumber = [number longLongValue];
[context addIdentificationEntryWithNextSequentialPhoneNumber:phoneNumber label:name];
}
}
dic = nil;
}
}
實(shí)際測試,將近100萬的數(shù)據(jù)在 6S Plus 15S內(nèi)可以完成加載滑废。
號碼庫更新后如何通知系統(tǒng)更新數(shù)據(jù)
號碼庫可以通過下載進(jìn)行更新蝗肪,一般下載的是壓縮包,解壓縮后蠕趁,把數(shù)據(jù)寫進(jìn)共享文件內(nèi)薛闪,更新數(shù)據(jù)后,需要通知系統(tǒng)去刷新數(shù)據(jù)庫俺陋,是數(shù)據(jù)生效豁延。具體解壓縮可以搜索: SSZipArchive
,擴(kuò)展和主APP數(shù)據(jù)擴(kuò)展可以看這篇文章:WWDC2014之App Extensions學(xué)習(xí)筆記 通知系統(tǒng)刷新號碼數(shù)據(jù)庫的具體代碼:
//IdentifierExtension 為擴(kuò)展的 Bundle Identifier
CXCallDirectoryManager *manager = [CXCallDirectoryManager sharedInstance];
[manager reloadExtensionWithIdentifier:IdentifierExtension completionHandler:^(NSError * _Nullable error) {
}];
要使用真機(jī)調(diào)試
不要使用模擬器,用模擬器調(diào)試時的錯誤不要管腊状。血的教訓(xùn)诱咏,查看用戶擴(kuò)展的使用權(quán)限和更新數(shù)據(jù)時使用模擬器一直報(bào)錯,找了半天的錯誤缴挖,換了真機(jī)就沒有問題袋狞,也是我自己2了 [二哈] 。
數(shù)據(jù)可以分開寫
這句話的意思是先寫入少量的數(shù)據(jù),讓用戶打開權(quán)限時硕并,感覺不到延時法焰,當(dāng)權(quán)限打開后,在寫入大量的數(shù)據(jù)倔毙,刷新數(shù)據(jù)源埃仪,用戶感覺不到等待的時間。
因?yàn)橹罢f了寫入幾十萬的 數(shù)據(jù)需要大概十幾秒的時間陕赃,在我的思維里面覺得是很正常的卵蛉,但是在產(chǎn)品眼里這是不可接受的。巴拉巴拉說了一堆么库,說騰訊啊傻丝、360啊人家都打開的很快的。你娘八呷濉F乡帧!好吧算你贏忱反。
最后想到一個辦法泛释,先寫入很少量的數(shù)據(jù),然后在寫入大量的數(shù)據(jù)温算。這樣就完美的解決了第一次加載時間慢的問題怜校。
具體的來說就是,第一次請求用戶打開權(quán)限的時間注竿,先寫入很少量的數(shù)據(jù)茄茁,當(dāng)判斷用戶已經(jīng)打開了權(quán)限,就寫入大量的數(shù)據(jù)巩割,然后刷新下數(shù)據(jù)源裙顽,這樣就是在用戶完全沒有感知的情況下刷新了數(shù)據(jù)源。
最好提供一個演示視頻
審核的蘋果爸爸使用的 iPad 測試宣谈,然后把我們拒了愈犹,說不知道如何使用 CallKit
。