Интеграция с CallKit
В этом документе мы рассмотрим, как интегрировать CallKit с приложением iOS.
Необходимые компоненты
- Учетная запись Azure с активной подпиской. Создайте учетную запись бесплатно .
- Развернутый ресурс Служб коммуникации. Создайте ресурс Служб коммуникации.
- Маркер доступа пользователя для включения клиента для вызовов. Дополнительные сведения см. в статье о создании маркеров доступа и управлении ими.
- Необязательно. Выполните краткое руководство по добавлению голосовых вызовов в приложение
Интеграция CallKit (в пакете SDK)
Интеграция CallKit в пакете SDK для iOS Службы коммуникации Azure обрабатывает взаимодействие с CallKit для нас. Для выполнения любых операций вызова, таких как отключение и отключение, удержание и возобновление, необходимо вызвать API только в пакете SDK Службы коммуникации Azure.
Инициализация агента вызова с помощью CallKitOptions
С настроенным экземпляром CallKitOptions
мы можем создать обработку CallAgent
CallKit
.
let options = CallAgentOptions()
let callKitOptions = CallKitOptions(with: createProviderConfig())
options.callKitOptions = callKitOptions
// Configure the properties of `CallKitOptions` instance here
self.callClient!.createCallAgent(userCredential: userCredential,
options: options,
completionHandler: { (callAgent, error) in
// Initialization
})
Указание сведений о получателе звонков для исходящих звонков
Сначала необходимо создать экземпляр исходящих вызовов или JoinCallOptions()
для группового StartCallOptions()
вызова:
let options = StartCallOptions()
or
let options = JoinCallOptions()
Затем создайте экземпляр CallKitRemoteInfo
options.callKitRemoteInfo = CallKitRemoteInfo()
- Назначьте значение для
callKitRemoteInfo.displayNameForCallKit
настройки отображаемого имени для получателей звонков и настройкиCXHandle
значения. Это значение, указанноеdisplayNameForCallKit
в том, как оно отображается в последнем телефонном журнале звонков. в последнем телефонном журнале звонков.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
cxHandle
Назначение значения — это то, что приложение получает при обратном вызове пользователя в этом контакте.
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")
Указание сведений о получателе звонка для входящих вызовов
Сначала необходимо создать экземпляр CallKitOptions
:
let callKitOptions = CallKitOptions(with: createProviderConfig())
Настройте свойства экземпляра CallKitOptions
:
Блокировка, передаваемая переменной provideRemoteInfo
, будет вызываться пакетом SDK при получении входящего вызова, и нам нужно получить отображаемое имя для входящего вызывающего объекта, который необходимо передать в CallKit.
callKitOptions.provideRemoteInfo = self.provideCallKitRemoteInfo
func provideCallKitRemoteInfo(callerInfo: CallerInfo) -> CallKitRemoteInfo
{
let callKitRemoteInfo = CallKitRemoteInfo()
callKitRemoteInfo.displayName = "CALL_TO_PHONENUMBER_BY_APP"
callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")
return callKitRemoteInfo
}
Настройка звукового сеанса
Настройка звукового сеанса будет вызвана перед размещением или принятием входящих вызовов и перед возобновлением вызова после его удержания.
callKitOptions.configureAudioSession = self.configureAudioSession
public func configureAudioSession() -> Error? {
let audioSession: AVAudioSession = AVAudioSession.sharedInstance()
var configError: Error?
do {
try audioSession.setCategory(.playAndRecord)
} catch {
configError = error
}
return configError
}
ПРИМЕЧАНИЕ. В случаях, когда Компания Contoso уже настроила звуковые сеансы, НЕ предоставляют nil
, но возвращают nil
ошибку в блоке.
callKitOptions.configureAudioSession = self.configureAudioSession
public func configureAudioSession() -> Error? {
return nil
}
Если nil
для configureAudioSession
этого пакет SDK вызывает реализацию по умолчанию в пакете SDK.
Обработка полезных данных для входящих push-уведомлений
Когда приложение получает входящие полезные данные push-уведомлений, необходимо вызвать handlePush
его для обработки. Службы коммуникации Azure пакет SDK для вызова вызовов вызывает IncomingCall
событие.
public func handlePushNotification(_ pushPayload: PKPushPayload)
{
let callNotification = PushNotificationInfo.fromDictionary(pushPayload.dictionaryPayload)
if let agent = self.callAgent {
agent.handlePush(notification: callNotification) { (error) in }
}
}
// Event raised by the SDK
public func callAgent(_ callAgent: CallAgent, didRecieveIncomingCall incomingcall: IncomingCall) {
}
Мы можем использовать reportIncomingCall
для обработки push-уведомлений при закрытии приложения или в противном случае.
if let agent = self.callAgent {
/* App is not in a killed state */
agent.handlePush(notification: callNotification) { (error) in }
} else {
/* App is in a killed state */
CallClient.reportIncomingCall(with: callNotification, callKitOptions: callKitOptions) { (error) in
if (error == nil) {
DispatchQueue.global().async {
self.callClient = CallClient()
let options = CallAgentOptions()
let callKitOptions = CallKitOptions(with: createProviderConfig())
callKitOptions.provideRemoteInfo = self.provideCallKitRemoteInfo
callKitOptions.configureAudioSession = self.configureAudioSession
options.callKitOptions = callKitOptions
self.callClient!.createCallAgent(userCredential: userCredential,
options: options,
completionHandler: { (callAgent, error) in
if (error == nil) {
self.callAgent = callAgent
self.callAgent!.handlePush(notification: callNotification) { (error) in }
}
})
}
} else {
os_log("SDK couldn't handle push notification", log:self.log)
}
}
}
Интеграция CallKit (в приложении)
Если вы хотите интегрировать CallKit в приложение и не использовать реализацию CallKit в пакете SDK, ознакомьтесь с примером краткого руководства. Но одна из важных вещей, чтобы заботиться о том, чтобы начать звук в нужное время. Как показано ниже
let outgoingAudioOptions = OutgoingAudioOptions()
outgoingAudioOptions.muted = true
let incomingAudioOptions = IncomingAudioOptions()
incomingAudioOptions.muted = true
var copyAcceptCallOptions = AcceptCallOptions()
copyStartCallOptions.outgoingAudioOptions = outgoingAudioOptions
copyStartCallOptions.incomingAudioOptions = incomingAudioOptions
callAgent.startCall(participants: participants,
options: copyStartCallOptions,
completionHandler: completionBlock)
Отключение динамиков и микрофона гарантирует, что физические звуковые устройства не используются, пока CallKit не вызывает его didActivateAudioSession
CXProviderDelegate
. В противном случае звонок может быть удален или звук не будет работать.
Когда didActivateAudioSession
следует запустить аудиопотоки.
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
Task {
guard let activeCall = await self.callKitHelper.getActiveCall() else {
print("No active calls found when activating audio session !!")
return
}
try await startAudio(call: activeCall)
}
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
Task {
guard let activeCall = await self.callKitHelper.getActiveCall() else {
print("No active calls found when deactivating audio session !!")
return
}
try await stopAudio(call: activeCall)
}
}
private func stopAudio(call: Call) async throws {
try await self.callKitHelper.muteCall(callId: call.id, isMuted: true)
try await call.stopAudio(stream: call.activeOutgoingAudioStream)
try await call.stopAudio(stream: call.activeIncomingAudioStream)
try await call.muteIncomingAudio()
}
private func startAudio(call: Call) async throws {
try await call.startAudio(stream: LocalOutgoingAudioStream())
try await self.callKitHelper.muteCall(callId: call.id, isMuted: false)
try await call.startAudio(stream: RemoteIncomingAudioStream())
try await call.unmuteIncomingAudio()
}
Важно также отключить исходящий звук перед остановкой звука в случаях, когда CallKit не вызывается didActivateAudioSession
. Затем пользователь может вручную отменить микрофон.
Примечание.
В некоторых случаях CallKit не вызывается didActivateAudioSession
, даже если приложение имеет повышенные разрешения на звук, в этом случае звук будет оставаться отключенным до получения обратного вызова. И пользовательский интерфейс должен отражать состояние динамика и микрофона. Удаленный участник или с в вызове увидит, что пользователь также отключил звук. В этих случаях пользователю придется вручную отменить ввод.