Freigeben über


Integrieren Sie mit CallKit

In diesem Dokument erfahren Sie, wie Sie CallKit in Ihre iOS-Anwendung integrieren.

Voraussetzungen

CallKit-Integration (innerhalb des SDK)

CallKit-Integration im Azure Communication Services iOS SDK behandelt die Interaktion mit CallKit für uns. Zum Ausführen von Anrufvorgängen wie Stummschalten/Aufheben der Stummschaltung, Halten/Fortsetzen müssen wir nur die API des Azure Communication Services SDK aufrufen.

Initialisieren des Anruf-Agents mit CallKitOptions

Mit der konfigurierten Instanz von CallKitOptionskönnen wir CallAgent mit der Handhabung von CallKit erstellen.

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
})

Angeben von Anrufempfängerinformationen für ausgehende Anrufe

Zuerst müssen wir eine Instanz für StartCallOptions() ausgehende Anrufe oder JoinCallOptions() für Gruppenanrufe erstellen:

let options = StartCallOptions()

oder

let options = JoinCallOptions()

Erstellen Sie dann eine Instanz von CallKitRemoteInfo

options.callKitRemoteInfo = CallKitRemoteInfo()
  1. Weisen Sie einen Wert für callKitRemoteInfo.displayNameForCallKit zu, um den Anzeigenamen für Anrufempfänger anzupassen, und konfigurieren Sie den Wert für CXHandle. Dieser in displayNameForCallKit angegebene Wert wird genau so angezeigt, wie er im letzten gewählten Anrufprotokoll angezeigt wird. im Protokoll des letzten angerufenen Anrufs.
options.callKitRemoteInfo.displayNameForCallKit = "DISPLAY_NAME"
  1. Weisen Sie den cxHandle Wert zu, den die Anwendung empfängt, wenn der Benutzer an diesen Kontakt zurückruft
options.callKitRemoteInfo.cxHandle = CXHandle(type: .generic, value: "VALUE_TO_CXHANDLE")

Angeben von Anrufempfängerinformationen für eingehende Anrufe

Zuerst müssen wir eine Instanz von CallKitOptions:

let callKitOptions = CallKitOptions(with: createProviderConfig())

Konfigurieren sie die Eigenschaften der CallKitOptions Instanz:

Block, der an die Variable provideRemoteInfo übergeben wird, wird vom SDK aufgerufen, wenn ein eingehender Anruf empfangen wird, und wir müssen einen Anzeigenamen für den eingehenden Anrufer abrufen, den wir an das CallKit übergeben müssen.

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
}

Konfigurieren der Audiositzung

Die Audiositzung wird vor dem Tätigen oder Annehmen eines eingehenden Anrufs und vor dem Fortsetzen des Anrufs aufgerufen, nachdem er in den Haltebereich versetzt wurde.

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
}

HINWEIS: In Fällen, in denen Contoso bereits Audiositzungen konfiguriert hat, nil NICHT bereitstellen, sondern im Block nil einen Fehler zurückgeben

callKitOptions.configureAudioSession = self.configureAudioSession

public func configureAudioSession() -> Error? {
    return nil
}

falls nil für configureAudioSession angegeben ist, ruft das SDK die Standardimplementierung im SDK auf.

Behandeln eingehender Pushbenachrichtigungsnutzlast

Wenn die App eingehende Pushbenachrichtigungsnutzlast empfängt, müssen wir handlePush aufrufen, um sie zu verarbeiten. Das Azure Communication Services Calling SDK löst das IncomingCall Ereignis aus.

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, didReceiveIncomingCall incomingcall: IncomingCall) {
}

Wir können reportIncomingCall verwenden, um Push-Benachrichtigungen zu behandeln, wenn die App geschlossen ist oder anderweitig.

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-Integration (innerhalb der App)

Wenn Sie das CallKit in die App integrieren und nicht die CallKit-Implementierung im SDK verwenden möchten, lesen Sie hier das Schnellstartbeispiel. Eine der wichtigen Dinge, die Sie sich kümmern müssen, ist jedoch, die Audiowiedergabe zur richtigen Zeit zu starten. Wie folgt

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)

Durch Stummschalten von Lautsprecher und Mikrofon wird sichergestellt, dass keine physischen Audiogeräte verwendet werden, bis das CallKit die didActivateAudioSession auf CXProviderDelegateaufruft. Andernfalls könnte der Anruf unterbrochen werden, oder der Ton funktioniert nicht. Wann didActivateAudioSession sollten die Audiostreams gestartet werden?

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()
}
    

Es ist wichtig, die ausgehenden Audiodaten auch stumm zu schalten, bevor Sie die Audiodatei beenden, wenn CallKit didActivateAudioSession nicht aufruft. Der Benutzer kann dann die Stummschaltung des Mikrofons manuell aufheben.

Hinweis

In einigen Fällen ruft CallKit nicht an didActivateAudioSession , obwohl die App über erhöhte Audioberechtigungen verfügt, in diesem Fall bleibt die Audiowiedergabe stummgeschaltet, bis der Rückruf empfangen wird. Und die Benutzeroberfläche muss den Zustand des Lautsprechers und mikrofons widerspiegeln. Die Remoteteilnehmer im Anruf sehen, dass der Benutzer auch Audio stummgeschaltet hat. In solchen Fällen müssen Benutzer die Stummschaltung manuell aufheben.

Nächste Schritte