前言
最近兩天公司有需求研究CallKit來電識(shí)別和號(hào)碼拉黑姆坚,在網(wǎng)上找了一些相關(guān)博文拌倍。但是發(fā)現(xiàn)對(duì)于沒接觸過這方面的人來說勋又,還是會(huì)遇到一些問題,所以打算自己再寫一篇詳盡的文章八拱。
懶得看的請(qǐng)直接下載最下面demo。
細(xì)節(jié)
在沒有了解CallKit這兩個(gè)功能之前涯塔,因?yàn)橄旅娴膬?nèi)容肌稻,導(dǎo)致產(chǎn)生一些失(cao)敗(dan)的嘗試。包括但不限于以下:
- 如果該號(hào)碼已存在手機(jī)里匕荸,標(biāo)記識(shí)別將會(huì)無效
- 如果屏蔽某號(hào)碼爹谭,看不到該號(hào)碼來電
- 打開主App和擴(kuò)展App的數(shù)據(jù)共享,以實(shí)現(xiàn)兩個(gè)應(yīng)用共享數(shù)據(jù)
- 添加到call表單中的電話號(hào)碼必須帶上國家區(qū)號(hào)
- 添加號(hào)碼到表單之前榛搔,需要對(duì)數(shù)據(jù)進(jìn)行去重和升序排列
- 最大數(shù)量在100萬到200萬之間诺凡,原因可能是超時(shí)無效
- 目前好像只能全量更新數(shù)據(jù),不能增量更新践惑,效率比較低
過程
1. 首先腹泌,建立一個(gè)工程或者在原有工程上,加入擴(kuò)展應(yīng)用 Call Directory Extension:
- 選擇new->target->Call Directory Extension
-
在這個(gè)文件中尔觉,蘋果默認(rèn)已經(jīng)寫好了注入事件的代碼凉袱,并默認(rèn)添加了兩個(gè)手機(jī)號(hào)供參考格式。
正是因?yàn)檫@倆默認(rèn)號(hào)碼的格式侦铜,容易產(chǎn)生誤導(dǎo)专甩,如果按照這個(gè)格式來寫,不帶國家區(qū)號(hào)的話钉稍,號(hào)碼是無法添加到 CXCallDirectoryExtensionContext 里面的涤躲,也就是會(huì)添加失敗,導(dǎo)致產(chǎn)生了一種“這不可能”的心態(tài)贡未。
- 在做這里的時(shí)候种樱,我想當(dāng)然的認(rèn)為,它只是一個(gè)本地沙盒或者數(shù)據(jù)庫類型的介質(zhì)羞秤,也就是任何形式的字符數(shù)據(jù)都可以存儲(chǔ)進(jìn)去(CXCallDirectoryPhoneNumber是int64_t)缸托,實(shí)際上,它在存儲(chǔ)前進(jìn)行了數(shù)據(jù)格式判斷瘾蛋,不帶 #國家區(qū)號(hào)# 的數(shù)據(jù)是無法存儲(chǔ)成功的俐镐,直接失敗并導(dǎo)致權(quán)限丟失。
權(quán)限打開方式:設(shè)置->電話->來電阻止與身份識(shí)別
- 我嘗試了一下是否可以用openUrl方式哺哼,直接讓應(yīng)用跳轉(zhuǎn)到來電身份權(quán)限頁面佩抹。遺憾的是失敗了叼风,可能是沒有開放這個(gè)接口,或者我沒找到棍苹。第一行跳轉(zhuǎn)到電話設(shè)置頁面有效无宿。
Phone — prefs:root=Phone
Phone — prefs:root=Phone&CALL_BLOCKING&IDENTIFICATION
2. 接著,進(jìn)行Main App和Extension App之間數(shù)據(jù)通訊枢里。
- 測試功能時(shí)孽鸡,直接在擴(kuò)展應(yīng)用 Call Directory Extension 中寫入了自己的號(hào)碼嘗試成功。不過栏豺,擴(kuò)展APP和主APP雖然在同一個(gè)工程里彬碱,但是是兩個(gè)應(yīng)用,傳遞數(shù)據(jù)的話需要用到數(shù)據(jù)共享:App Group.
- App共享數(shù)據(jù)的方法有兩種奥洼,至于寫入數(shù)據(jù)的方式巷疼,可以采用數(shù)組、字典或者數(shù)據(jù)庫灵奖。
- 使用共享url地址嚼沿,寫入文件
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.RexLocalGroup"];
- 使用本地沙盒,寫入沙盒中
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.RexLocalGroup"];
- 簡書上有人采用 fgets(char *buf, int bufsize, FILE *stream) 函數(shù)讀行的形式來解析數(shù)據(jù)瓷患,我試了一下骡尽,可以實(shí)現(xiàn)存入100萬條數(shù)據(jù),但200萬的時(shí)候會(huì)異常尉尾,應(yīng)該是蘋果做了一些限制爆阶。不過這種方式,只適合從服務(wù)器拉取數(shù)據(jù)文件寫入沙咏,如果想在移動(dòng)端去添加數(shù)據(jù)到文件里辨图,就會(huì)非邏輯化。所以如果想實(shí)現(xiàn)移動(dòng)端主動(dòng)寫入的話肢藐,用數(shù)據(jù)庫會(huì)容易操作一些故河。
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.RexLocalGroup"];
containerURL = [containerURL URLByAppendingPathComponent:@"Library/"];
NSString * dbPath = [NSString stringWithFormat:@"%@%@",containerURL.absoluteString, @"LocalNumberDB.sqlite"];
_dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
- 主應(yīng)用中把數(shù)據(jù)庫建立到這個(gè)數(shù)據(jù)共享URL位置,然后吆豹,在擴(kuò)展應(yīng)用中提取數(shù)據(jù)并填入CXCallDirectoryExtensionContext表單中鱼的。這樣就實(shí)現(xiàn)了數(shù)據(jù)傳遞。比較遺憾的是目前只能是全量更新號(hào)碼庫痘煤,無法實(shí)現(xiàn)增量更新凑阶,所以更新一條數(shù)據(jù)也需要全部重新存一遍,速度比較慢衷快,可能這也是種隱私保護(hù)宙橱。
NSArray * contacts = [[FMDataBaseManager shareInstance] getAllContacts:kNumberTable];
for (int i= 0; i < contacts.count; i ++) {
@autoreleasepool {
ContactModel * contact = contacts[i];
if (contact.phoneNumber && contact.identification) {
CXCallDirectoryPhoneNumber phoneNumber = [contact.phoneNumber longLongValue];
NSString * label = contact.identification;
[context addIdentificationEntryWithNextSequentialPhoneNumber:phoneNumber label:label];
}
contact = nil;
}
}
- 簡單幾步,即可感覺到這個(gè)強(qiáng)(mei)大(luan)的(yong)功能的作用。
有疑問可以留言
參考項(xiàng)目下載
做了一個(gè)完整的demo放在了GitHub上师郑,有興趣可以下載环葵。