版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2019.04.14 星期日 |
前言
蘋果 iOS 10 新發(fā)布了一個(gè)新的框架CallKit,使第三方VOIP類型語音通話類APP有了更好的展現(xiàn)方式和用戶體驗(yàn)的提升俏橘,接下來這幾篇我們就一起看一下這個(gè)框架寺庄。感興趣的看下面幾篇文章。
1. CallKit框架詳細(xì)解析(一) —— 基本概覽(一)
開始
首先看一下寫作環(huán)境
Swift 4.2, iOS 12, Xcode 10
本篇了解您的應(yīng)用如何使用CallKit進(jìn)行系統(tǒng)級(jí)電話集成,以及如何構(gòu)建用于呼叫阻止和識(shí)別的目錄擴(kuò)展忘蟹。
iOS上的生活并不總是適合VoIP(Voice over IP)
應(yīng)用程序開發(fā)人員。 特別是们陆,發(fā)送通知很困難寒瓦。 在后臺(tái)使用您的應(yīng)用程序,用戶唯一的選擇是定期通知坪仇,這很容易被遺漏杂腰。 如果沒有豐富的內(nèi)置調(diào)用UI,您的應(yīng)用程序就會(huì)感覺集成度不夠椅文。
幸運(yùn)的是喂很,Apple在iOS 10
中引入了CallKit
!
在本教程中皆刺,您將通過構(gòu)建以下應(yīng)用程序來了解CallKit
的強(qiáng)大功能:
- 使用系統(tǒng)服務(wù)報(bào)告?zhèn)魅牒蛡鞒龊艚小?/li>
- 管理呼叫目錄以識(shí)別或阻止來電少辣。
注意:
CallKit
功能在模擬器中不起作用。 要繼續(xù)學(xué)習(xí)本教程羡蛾,您需要安裝iOS 12.0
或更高版本的iPhone漓帅。
在Xcode中打開項(xiàng)目文件,然后在Project
導(dǎo)航器中選擇Hotline
。
首先更改bundle identifier
忙干。 選擇項(xiàng)目后器予,轉(zhuǎn)到General
選項(xiàng)卡,然后找到Identity
部分捐迫。 將bundle identifier
更改為唯一的標(biāo)識(shí)符:
接下來乾翔,查找簽名Signing
部分。 在Team
旁邊的下拉列表中選擇您喜歡的開發(fā)團(tuán)隊(duì)(在我的情況下施戴,這是我的個(gè)人團(tuán)隊(duì))反浓。 請(qǐng)務(wù)必選中自動(dòng)管理簽名(Automatically manage signing)
。 這允許Xcode自動(dòng)為應(yīng)用程序創(chuàng)建配置文件(provisioning profile)
赞哗。
注意:如果您看到Add Account…
按鈕雷则,則需要輸入 Apple Developer帳戶憑據(jù)才能選擇開發(fā)團(tuán)隊(duì)。
要測(cè)試您的設(shè)置懈玻,請(qǐng)?jiān)趇Phone上構(gòu)建并運(yùn)行該應(yīng)用程序巧婶。
目前該應(yīng)用程序不會(huì)做太多,但你會(huì)注意到啟動(dòng)項(xiàng)目中有幾個(gè)源文件涂乌。 這些文件主要負(fù)責(zé)設(shè)置UI和處理用戶交互艺栈。 在繼續(xù)之前,有兩個(gè)主要類別值得一看:
-
Call
代表一個(gè)電話湾盒。 該類公開用于標(biāo)識(shí)call的屬性(例如其UUID
或handle
)以及指示用戶何時(shí)啟動(dòng)湿右,應(yīng)答或結(jié)束call的生命周期回調(diào)。 -
CallManager
當(dāng)前維護(hù)應(yīng)用程序中正在進(jìn)行的呼叫列表罚勾,并具有添加或刪除呼叫的方法毅人。 您將在整個(gè)教程中進(jìn)一步擴(kuò)展此類。
What is CallKit?
CallKit
是一個(gè)旨在通過允許應(yīng)用程序與本機(jī)電話UI集成來改善VoIP
體驗(yàn)的框架尖殃。 通過采用CallKit
丈莺,您的應(yīng)用程序?qū)⒛軌颍?/p>
- 在鎖定和未鎖定狀態(tài)下使用本機(jī)來電屏幕
(native incoming call screen)
。 - 從本機(jī)電話應(yīng)用程序的“聯(lián)系人”
Contacts
送丰,“收藏夾”Favorites
和“最近”Recents
屏幕開始呼叫calls
缔俄。 - 與系統(tǒng)中的其他呼叫
calls
相互作用。
在本節(jié)中器躏,您將更加熟悉CallKit
架構(gòu)俐载。 下圖顯示了所有主要參與者:
使用CallKit時(shí),您將與兩個(gè)主要類進(jìn)行交互:CXProvider和CXCallController登失。是時(shí)候潛入了遏佣!
1. CXProvider
您的應(yīng)用將使用CXProvider
向系統(tǒng)報(bào)告任何帶外通知。這些通常是外部事件揽浙,例如來電状婶。
發(fā)生此類事件時(shí)意敛,CXProvider
會(huì)創(chuàng)建一個(gè)呼叫更新(call update)
以通知系統(tǒng)。呼叫更新封裝了新的或更改的呼叫相關(guān)信息太抓。它們屬于CXCallUpdate
類空闲,它暴露諸如呼叫者姓名之類的屬性,或者呼叫是視頻還是僅音頻走敌。
當(dāng)系統(tǒng)想要通知應(yīng)用程序事件時(shí),它使用CXAction
實(shí)例逗噩。CXAction
是一個(gè)代表電話操作的抽象類掉丽。對(duì)于每個(gè)動(dòng)作,CallKit
提供了CXAction
的不同具體實(shí)現(xiàn)异雁。例如捶障,CXStartCallAction
表示發(fā)起撥出呼叫,而CXAnswerCallAction
表示接聽來電纲刀。唯一的UUID
標(biāo)識(shí)可能失敗或?qū)崿F(xiàn)的每個(gè)操作项炼。
應(yīng)用程序可以通過CXProviderDelegate
協(xié)議與CXProvider
進(jìn)行通信,該協(xié)議定義了provider
生命周期事件和傳入操作的方法示绊。
2. CXCallController
該應(yīng)用程序?qū)⑹褂?code>CXCallController通知系統(tǒng)用戶發(fā)起的請(qǐng)求锭部,例如啟動(dòng)呼叫操作。 這是CXProvider
和CXCallController
之間的主要區(qū)別:provider
向系統(tǒng)報(bào)告面褐,而呼叫控制器(call controller)
代表用戶向系統(tǒng)發(fā)出請(qǐng)求拌禾。
呼叫控制器使用事務(wù)來發(fā)出這些請(qǐng)求。 由CXTransaction
表示的事務(wù)包含一個(gè)或多個(gè)CXAction
實(shí)例展哭。 呼叫控制器將事務(wù)發(fā)送到系統(tǒng)湃窍。 如果一切順利,系統(tǒng)將以適當(dāng)?shù)牟僮黜憫?yīng)provider
匪傍。
這在實(shí)踐中是什么樣的您市?
Incoming Calls
下圖顯示了傳入呼叫流的高級(jí)概述:
- 1) 響應(yīng)來電,應(yīng)用程序構(gòu)造一個(gè)
CXCallUpdate
并使用provider
將其發(fā)送到系統(tǒng)役衡。 - 2) 系統(tǒng)將此發(fā)布為對(duì)其所有服務(wù)的傳入呼叫茵休。
- 3) 當(dāng)用戶應(yīng)答呼叫時(shí),系統(tǒng)會(huì)將
CXAnswerCallAction
實(shí)例發(fā)送給provider
映挂。 - 4) 該應(yīng)用程序通過實(shí)現(xiàn)適當(dāng)?shù)?code>CXProviderDelegate方法來應(yīng)答調(diào)用泽篮。
ProviderDelegate
首先,為provider
創(chuàng)建委托柑船。 返回Xcode帽撑,在Project
導(dǎo)航器中突出顯示App組,創(chuàng)建一個(gè)名為ProviderDelegate.swift
的新文件鞍时。
將以下代碼添加到文件中:
import AVFoundation
import CallKit
class ProviderDelegate: NSObject {
// 1.
private let callManager: CallManager
private let provider: CXProvider
init(callManager: CallManager) {
self.callManager = callManager
// 2.
provider = CXProvider(configuration: ProviderDelegate.providerConfiguration)
super.init()
// 3.
provider.setDelegate(self, queue: nil)
}
// 4.
static var providerConfiguration: CXProviderConfiguration = {
let providerConfiguration = CXProviderConfiguration(localizedName: "Hotline")
providerConfiguration.supportsVideo = true
providerConfiguration.maximumCallsPerCallGroup = 1
providerConfiguration.supportedHandleTypes = [.phoneNumber]
return providerConfiguration
}()
}
這就是上面代碼中發(fā)生的事情:
- 1) 存儲(chǔ)對(duì)
provider
和call controller
的引用亏拉。provider
代理將與它們進(jìn)行交互扣蜻。 - 2) 使用適當(dāng)?shù)?code>CXProviderConfiguration初始化
provider
,存儲(chǔ)為下面的靜態(tài)變量及塘。provider
配置指定調(diào)用的行為和功能莽使。 - 3) 設(shè)置委托以響應(yīng)來自
provider
的事件。 此行將導(dǎo)致構(gòu)建錯(cuò)誤笙僚,因?yàn)?code>ProviderDelegate尚未符合CXProviderDelegate
芳肌。 - 4) 在
Hotline
的情況下,provider
配置允許視頻呼叫和電話號(hào)碼處理肋层,并將呼叫組的數(shù)量限制為一個(gè)亿笤。 有關(guān)進(jìn)一步的自定義,請(qǐng)參閱CallKit documentation栋猖。
在配置下方净薛,添加以下幫助方法:
func reportIncomingCall(
uuid: UUID,
handle: String,
hasVideo: Bool = false,
completion: ((Error?) -> Void)?
) {
// 1.
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
update.hasVideo = hasVideo
// 2.
provider.reportNewIncomingCall(with: uuid, update: update) { error in
if error == nil {
// 3.
let call = Call(uuid: uuid, handle: handle)
self.callManager.add(call: call)
}
// 4.
completion?(error)
}
}
此幫助方法允許應(yīng)用程序調(diào)用CXProvider API來報(bào)告?zhèn)魅牒艚小?這是發(fā)生了什么:
- 1) 準(zhǔn)備系統(tǒng)的呼叫更新,其中包含相關(guān)的呼叫元數(shù)據(jù)蒲拉。
- 2) 在
provider
上調(diào)用reportNewIncomingCall(with:update:completion)
以通知系統(tǒng)有來電肃拜。 - 3) 一旦系統(tǒng)處理呼叫,將調(diào)用完成處理程序雌团。 假設(shè)沒有錯(cuò)誤燃领,您可以創(chuàng)建一個(gè)
Call
實(shí)例并通過CallManager
將其添加到調(diào)用列表中。 - 4) 如果它不是
nil
辱姨,則調(diào)用完成處理程序柿菩。
應(yīng)用程序中的其他類可以調(diào)用此方法以模擬傳入的調(diào)用。
CXProviderDelegate
下一步是確保協(xié)議一致性雨涛。 仍然在ProviderDelegate.swift
中枢舶,聲明一個(gè)符合CXProviderDelegate
的新擴(kuò)展:
// MARK: - CXProviderDelegate
extension ProviderDelegate: CXProviderDelegate {
func providerDidReset(_ provider: CXProvider) {
stopAudio()
for call in callManager.calls {
call.end()
}
callManager.removeAllCalls()
}
}
CXProviderDelegate
僅指定一個(gè)必需的方法providerDidReset(_ :)
。 provider
在重置時(shí)調(diào)用此方法替久,使您的應(yīng)用程序有機(jī)會(huì)清除正在進(jìn)行的任何調(diào)用并恢復(fù)到干凈狀態(tài)凉泄。 在此實(shí)現(xiàn)中,您將終止正在進(jìn)行的音頻會(huì)話并處理所有活動(dòng)的呼叫蚯根。
現(xiàn)在ProviderDelegate
提供了一種報(bào)告來電的方法后众,現(xiàn)在是時(shí)候使用了!
打開AppDelegate.swift
并首先向該類添加一個(gè)新屬性:
var providerDelegate: ProviderDelegate!
在return
之前將以下內(nèi)容添加到application(_:didFinishLaunchingWithOptions:)
:
providerDelegate = ProviderDelegate(callManager: callManager)
provider delegate
已準(zhǔn)備好使用颅拦! 將以下方法添加到AppDelegate.swift
:
func displayIncomingCall(
uuid: UUID,
handle: String,
hasVideo: Bool = false,
completion: ((Error?) -> Void)?
) {
providerDelegate.reportIncomingCall(
uuid: uuid,
handle: handle,
hasVideo: hasVideo,
completion: completion)
}
此方法允許其他類訪問provider delegate
的幫助程序方法蒂誉。
最后一部分是將此調(diào)用連接到用戶界面。 打開CallsViewController.swift
距帅,它是應(yīng)用程序主屏幕的控制器右锨。 找到unwindForNewCall(_ :)
的空實(shí)現(xiàn),并用以下代碼替換它:
// 1.
guard
let newCallController = segue.source as? NewCallViewController,
let handle = newCallController.handle
else {
return
}
let videoEnabled = newCallController.videoEnabled
// 2.
let backgroundTaskIdentifier =
UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
AppDelegate.shared.displayIncomingCall(
uuid: UUID(),
handle: handle,
hasVideo: videoEnabled
) { _ in
UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)
}
}
該代碼段執(zhí)行以下操作:
- 1) 從
NewCallViewController
中提取調(diào)用的屬性碌秸,NewCallViewController
是此展開segue
的源绍移。 - 2) 用戶可以在操作完成之前暫停應(yīng)用程序悄窃,因此應(yīng)該使用后臺(tái)任務(wù)。
后記
本篇主要講述了CallKit框架基本使用蹂窖,感興趣的給個(gè)贊或者關(guān)注~~~
`