iOS10增加了識別騷擾電話的API玖瘸,有三款主流的軟件已經(jīng)實(shí)現(xiàn)秸讹。也有一些報(bào)道分析 前幾天查了查資料,動手寫了一個(gè)Demo.
原理
電話號碼是用Call Directory extension事先存在系統(tǒng)里的雅倒,當(dāng)來電時(shí)璃诀,系統(tǒng)會查詢存儲的數(shù)據(jù), 根據(jù)號碼綁定的label,決定直接屏蔽還是顯示來電蔑匣。
When using CallKit's Call Blocking & Identification feature (new in iOS
10), phone numbers to be blocked or identified are loaded by your app's
Call Directory extension prior to an incoming call and the phone numbers
are stored by the system. Then, when an incoming call arrives, this stored
data is consulted by the system and an incoming call may either be
blocked or identified in the incoming call UI with the label provided.
For privacy and performance reasons, Call Directory app extensions are
not launched when incoming calls arrive and an app extension cannot
retrieve the phone number for an incoming call
http://stackoverflow.com/questions/38098036/how-to-get-the-incoming-call-number-by-using-callkit
https://www.zhihu.com/question/47542405
步驟
1 . 新建一個(gè)工程劣欢,New 一個(gè) Target,選Call Directory Extension
,會自動生成模版代碼裁良。
override func beginRequest(with context: CXCallDirectoryExtensionContext) {
context.delegate = self
do {
try addBlockingPhoneNumbers(to: context)
} catch {
NSLog("Unable to add blocking phone numbers")
let error = NSError(domain: "CallDirectoryHandler", code: 1, userInfo: nil)
context.cancelRequest(withError: error)
return
}
do {
try addIdentificationPhoneNumbers(to: context)
} catch {
NSLog("Unable to add identification phone numbers")
let error = NSError(domain: "CallDirectoryHandler", code: 2, userInfo: nil)
context.cancelRequest(withError: error)
return
}
NSLog("beginRequest context ", context);
context.completeRequest()
}
private func addBlockingPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
// Retrieve phone numbers to block from data store. For optimal performance and memory usage when there are many phone numbers,
// consider only loading a subset of numbers at a given time and using autorelease pool(s) to release objects allocated during each batch of numbers which are loaded.
//
let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ +8618005555555, +8618005555555 ]
for phoneNumber in phoneNumbers {
context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
}
}
private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
// Retrieve phone numbers to identify and their identification labels from data store. For optimal performance and memory usage when there are many phone numbers,
// consider only loading a subset of numbers at a given time and using autorelease pool(s) to release objects allocated during each batch of numbers which are loaded.
//
// Numbers must be provided in numerically ascending order.
let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ +8618005555555, +8618005555555 ]
let labels = [ "騷擾電話", "Local business" ]
for (phoneNumber, label) in zip(phoneNumbers, labels) {
context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)
}
}
2 . 手工給Extension 生成 一個(gè) CallDirectoryExtension.entitlements 文件凿将。
3 . 運(yùn)行。在設(shè)備的設(shè)置 —> 電話 —> Call Blocking & Identification价脾,開啟我們的 App牧抵。
4 . 打電話
效果
API
beginRequest
該方法在 Containing App 調(diào)用 reload 或者在 設(shè)置 —> 電話 —> Call Blocking & Identification里開啟權(quán)限的時(shí)候,會自動被調(diào)用侨把。但是打斷點(diǎn)的時(shí)候犀变,無法進(jìn)來。
open class CXCallDirectoryProvider : NSObject, NSExtensionRequestHandling {
open func beginRequest(with context: CXCallDirectoryExtensionContext)
}
給系統(tǒng)數(shù)據(jù)庫增加騷擾電話號碼
open func addBlockingEntry(withNextSequentialPhoneNumber
phoneNumber: CXCallDirectoryPhoneNumber)
- 數(shù)據(jù)量大時(shí)座硕,需要分批處理弛作,注意內(nèi)存問題。consider only loading a subset of numbers at a given time and using autorelease pool(s) to release objects allocated during each batch of numbers which are loaded.
- 號碼升序排列华匾。 Numbers must be provided in numerically ascending order
- 號碼需要加區(qū)號映琳。 Edit retrievePhoneNumbersToIdentifyAndLabels() to include the number and label you want. Add +CountryCode at the start (not confirmed yet if this is essential)
給系統(tǒng)數(shù)據(jù)庫增加騷擾電話號碼以及提示的文本
open func addIdentificationEntry(withNextSequentialPhoneNumber phoneNumber:
CXCallDirectoryPhoneNumber, label: String)
提交
open func completeRequest(completionHandler completion:
(@escaping (Bool) -> Swift.Void)? = nil)
蘋果開發(fā)交流網(wǎng)站上的總結(jié)
https://forums.developer.apple.com/thread/48837
I've managed to get this working, here's what I did and
some observations:
1) Create a new target of Type Call Directory Extension.
2) Edit retrievePhoneNumbersToIdentifyAndLabels() to include the number
and label you want. Add +CountryCode at the start (not confirmed yet
if this is essential)
3) Run the containing app target.
4) In setting go to Phone/Call Blocking & IdentificationAnd turn on you
extension (or it will automatically be turned on if you run the
entension target rather than the containing app target)
5) Make a call
Its not possible to hit any breakpoints in the extension if running in
XCode regardless of which target you execute. NSLog statements can be
viewed via XCode's devices, it indicates that the extension is called in
step 4) if the above steps are called. I don't know if/when its called
subsequently after that, it has to be otherwise how can an updated list
be applied?
If you want to make a change to the label, the OS does caching, so turn
off the extension, delete the containing app app, clear the call history
from the phone app, install and run again.