Поделиться через


Интеграция с CallKit

В этом документе мы рассмотрим, как интегрировать CallKit с приложением iOS.

Необходимые компоненты

Интеграция 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()
  1. Назначьте значение для callKitRemoteInfo.displayNameForCallKit настройки отображаемого имени для получателей звонков и настройки CXHandle значения. Это значение, указанное displayNameForCallKit в том, как оно отображается в последнем телефонном журнале звонков. в последнем телефонном журнале звонков.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
  1. 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 , даже если приложение имеет повышенные разрешения на звук, в этом случае звук будет оставаться отключенным до получения обратного вызова. И пользовательский интерфейс должен отражать состояние динамика и микрофона. Удаленный участник или с в вызове увидит, что пользователь также отключил звук. В этих случаях пользователю придется вручную отменить ввод.

Следующие шаги