Swift — 說說 CallKit

顯示應用的 VoIP 服務的系統通話 UI,並且與其他應用和系統協調你的通話服務。

Jeremy Xue
Jeremy Xue ‘s Blog
7 min readSep 20, 2020

--

❖ 概論:

CallKit 使你能夠將你的通話服務與系統上其他通話相關的應用整合在一起。CallKit 提供了通話接口,你可以透過 VoIP 服務處理後端通訊。對於來電和撥出通話,CallKit 顯示與 “電話” APP 相同的介面,讓你的應用具有更原生的外觀和體驗。而且,CallKit 可以對系統級別的行為做出合適的響應,像是 “勿擾”

除了處理通話外,你還可以提供 “通話目錄(Call Directory)” 應用擴展來提供通話者 ID 資訊以及與服務相關連的阻擋號碼列表。

❖ 接聽來電

要配置你的應用來接收來電。首先,創建一個 CXProvider 物件,並將其存儲用於全局訪問。應用會響應外部通知,向 Provider 回報來電,例如:PushKit 生成的 VoIP 推播通知。

接收與 VoIP 相關的推播
Note:關於 VoIP 推播和 PushKit 的詳細訊息,請參閱 Voice Over IP (VoIP) 最佳實踐

應用透過外部通知提供的訊息創建一個 UUIDCXCallUpdate 物件來唯一標誌通話和通話者,並使用 reportNewIncomingCall(with:update:completion:) 方法將它們都傳遞給 Provider。

處理來電

在通話連結後,系統調用 Provider delegate 的 provider(_:perform:) 方法。在你的實現裡,delegate 負責配置 AVAudioSession 並在完成時調用 fullfill()

啟動通話音訊

❖ 撥出通話

用戶可以通過以下任何一種方式使用 VoIP 應用開始撥出通話:

  • 在應用內執行交互
  • 使用支援的自定義 URL Scheme 打開連結
  • 使用 Siri 發起 VoIP 調用

要製作一個撥出通話,應用會從其 CXCallController 物件請求一個 CXStartCallAction 物件。該操作由一個 UUID 用於唯一辨識通話和一個用於指定接收者的 CXHandle 物件所組成。

開始撥出通話
Note:關於註冊和處理 URLs 的更多資訊,請參閱 使用 URL Schemes 與 Apps 進行通訊。(連結已死 QQ)有關使用 Siri 發起通話的更多資訊,請參考 INStartAudioCallIntentHandling 協議。(已棄用 QQ)

在接收者回應後,系統將調用 Provider delegate 的 provider(_:perform:) 方法。在該方法實現中,配置一個 AVAudioSession 和在完成後調用 fullfill() 方法。

開始通話

❖ 通話阻擋與識別

應用可以創建 Call Directory 應用擴展來根據來電者的電話號碼進行識別和阻擋。

Note:在 Call Directory 中的電話號碼由 CXCallDirectoryPhoneNumber 類型所表示,並由國家/地區電話代號(例如:美國為 1)和數字序列所組成。

❖ 創建 Call Directory 應用擴展

你可以透過添加新的 project target 並在應用 Application Extensions 下選擇 Call Directory Extension 樣板,為包含的應用創建 Call Directory 擴展。

你可以在 Call Directory 擴展中 CXCallDirectoryProvider 子類的 beginRequest(with:) 的實現中設置來電的標誌以及阻擋。當系統啟動應用程序擴展時,將調用此方法。

有關應用擴展如何工作的更多資訊,請參閱 App Extension 編程指南

❖ 識別來電者

當電話接收到來電時,系統首先會查詢用戶的聯絡人來查詢匹配的電話號碼。如果找不到匹配項目,系統將查詢你應用的 Call Directory 擴展來查找匹配的條目來識別電話號碼。這對於維護與系統聯絡人分開的用戶的聯繫人列表(例如社交網路)的應用,或是用於識別可能從應用內發起的來電應用(例如客戶服務支援或交貨通知)時很有用。

例如,假設某個用戶與某個社交網路應用中的 Jane 為朋友,但其聯絡人中並沒有她的電話號碼。社交網路應用具有 Call Directory 應用擴展,可以下載和添加用戶所有朋友的電話號碼。因此,當用戶收到來自 Jane 的來電時,系統顯示類似 “(應用名稱)通話者 ID: Jane Appleseed” 而不是 “未知的來電者”

要提供關於來電者的標示資訊,請在 beginRequest(with:) 的實現中使用 addIdentificationEntry(withNextSequentialPhoneNumber:label:) 方法。

因為此方法只有在系統啟動應用擴展時才會被調用,而不是針對每個單獨的調用才調用此方法,所以你必須一次指定所有的呼叫辨識資訊。例如,你無法向 Web 服務發出請求來查找有關來電的資訊。

❖ 阻擋來電

當電話接收來電時,系統會先查詢用戶的阻擋列表來確定是否阻擋來電。如果電話號碼不再用戶或系統定義的阻擋列表中,則系統將查詢你應用的 Call Directory 擴展來查詢匹配的阻擋號碼。這對於維護已知數據庫或允許用戶阻止與一組標準匹配的任何數字的應用很有用。

要阻擋特定電話號碼的來電,請在 beginRequest(with:) 的實現中使用 addBlockingEntry(withNextSequentialPhoneNumber:) 方法。

Note:你可以指定自己的 Call Directory 應用擴展在 beginRequest(with:) 的實現中添加識別和/或阻止電話號碼。

❖ 後記

最近剛好碰到在 APP 中實現通話的需求(有點類似於 Line APP 通話方式),因此就來查詢關於如何在 iOS 中實現通話的功能,也意外地的發現有 CallKit 這個框架的能夠支援,因此就藉由這邊官方文章讓自己對於這框架的使用上更加理解。

感覺看了這份官方文件之後,就大概可以想像如何做出一個類似 who’s call 功能的 APP 了 XD。

--

--

Jeremy Xue
Jeremy Xue ‘s Blog

Hi, I’m Jeremy. [好想工作室 — iOS Developer]