https://d226lax1qjow5r.cloudfront.net/blog/blogposts/how-to-make-outbound-calls-using-ios-callkit/ios-callkit_outbound-call.png

Comment passer des appels sortants à l'aide de CallKit iOS

Publié le October 18, 2023

Temps de lecture : 6 minutes

Dans ce tutoriel, vous allez créer une application SwiftUI capable de passer des appels téléphoniques à l'aide du Client Vonage Client SDK et de CallKit. CallKit vous permet d'intégrer votre application iOS dans le système. Lorsque vous passez des appels sortants, l'historique des appels de votre application sera disponible dans l'application Téléphone d'iOS.

Conditions préalables

  • Un Account API Vonage. Si vous n'en avez pas encore, vous pouvez vous inscrire aujourd'hui.

  • Un compte Apple Developer et un appareil iOS

  • Xcode 12 et Swift 5 ou supérieur.

  • Cocoapods pour installer le Vonage Client SDK pour iOS.

Vue d'ensemble

Tout d'abord, vous allez déployer un serveur pour gérer la création d'une application Vonage, les utilisateurs, la génération de JWT et les webhooks. Ensuite, vous adapterez une application iOS qui, à l'aide du Vonage Client SDK, passera des appels à l'aide de CallKit.

Déploiement du serveur

Ce projet utilisera le Vonage Cloud Runtime Marketplace pour déployer un serveur Client SDK Voice sur l'infrastructure de Vonage. Ouvrez le Exemple de serveur Client SDK Voice à la page du produit. Ouvrez l'onglet "Deploy Code", et si vous ne vous êtes pas encore connecté, faites-le maintenant.

Saisissez un nom pour le déploiement et choisissez une région. Cliquez ensuite sur le bouton "Déployer le code".

Client SDK Voice Sample Server "Deploy Code" page

Pour utiliser l'API Voice, vous devez acheter et attribuer un numéro Vonage à l'application. Cliquez sur "Attribuer un numéro" pour consulter vos numéros existants ou pour en acheter un nouveau. Une fois cela fait, cliquez sur "Continuer".

Assign number popup

Une fois le déploiement terminé, cliquez sur le bouton "Lancer". Cela ouvrira l'application du serveur dans votre navigateur, où vous pourrez en savoir plus sur le fonctionnement du serveur. Pour continuer le tutoriel, vous devez créer un utilisateur. Les Applications sont la façon d'identifier une application exécutant le Client SDK de Vonage avec les API de Vonage.

Client SDK Voice Sample Server landing page

Créer un utilisateur appelé "Alice" et générer un JWT. Les SDK clients utilisent le JWT pour s'authentifier auprès de Vonage. Lorsque vous passez un appel au numéro de Vonage que vous avez attribué à l'application plus tôt, Vonage envoie une demande à ce serveur qui renvoie un objet de contrôle d'appel (Call Control Object). objet de contrôle d'appel qui connectera l'appel entrant à l'utilisateur "Alice".

Generating a JWT for a user on the Client SDK Voice Sample Server

Télécharger le projet de démarrage

Ce tutoriel sera construit à partir d'un projet existant. Si vous n'êtes pas familier avec les appels sortants à l'aide du Client SDK de Vonage, il est recommandé de suivre le tutoriel suivant Comment passer des appels téléphoniques avec SwiftUI sur le blog. Lorsque vous êtes prêt, vous pouvez cloner le projet de démarrage à partir de GitHub en utilisant cette commande dans votre terminal :

git clone git@github.com:Vonage-Community/blog-clientsdk-ios_swift-swiftui_app_to_phone.git

Ensuite, changez de répertoire dans le dossier du projet et installez la dépendance VonageClientSDKVoice dépendance :

cd blog-clientsdk-ios_swift-swiftui_app_to_phone
pod install

Une fois le projet terminé, vous pouvez l'ouvrir à l'aide de cette commande :

xed .

Mise à jour du projet de démarrage

Puisque vous allez utiliser CallKit pour passer des appels, vous pouvez mettre à jour la fonction loginIfNeeded dans le fichier ContentView.swift pour supprimer l'indicateur isUsingCallKit pour supprimer l'indicateur Le SDK met par défaut cette valeur à true (vrai). Ici, vous pouvez également coller le JWT pour l'utilisateur "Alice" que vous avez créé plus tôt :

func loginIfNeeded() {
    guard status != "Connected" else { return }
    client.createSession("ey...") { error, sessionId in
        if let error {
            self.updateStatus(error.localizedDescription)
        } else {
            self.updateStatus("Connected")
        }
    }
}

Ajout du mode VoIP en arrière-plan

CallKit nécessite l'ajout du mode VoIP en arrière-plan. Assurez-vous d'être connecté à votre Account de développeur Apple dans Xcode via les préférences. Si c'est le cas, sélectionnez votre cible, puis choisissez Signature et capacités:

Add capability button in Xcode

Sélectionnez ensuite le bouton d'ajout de capacité et la capacité Modes d'arrière-plan. Sous la capacité Modes d'arrière-plan, sélectionnez Voice over IP:

Adding the VoIP background mode in Xcode

Lier le framework CallKit

Liez le framework CallKit à votre projet en l'ajoutant sous Frameworks, Libraries, and Embedded Content (Cadres, bibliothèques et contenu intégré) sous Général:

Adding the CallKit framework in Xcode

Création du gestionnaire de fournisseurs

Vous allez maintenant créer une classe, ProviderManager. CallKit gère la communication entre votre application et le système via la classe CXProvider. Créez un nouveau fichier Swift (CMD + N) appelé ProviderManager:

import CallKit
import Foundation
import VonageClientSDKVoice

protocol ProviderManagerDelegate: AnyObject {
    func callReported(_ providerManager: ProviderManager, callUUID: UUID)
    func providerReset()
}

final class ProviderManager: NSObject {
    private static var providerConfiguration: CXProviderConfiguration = {
        let providerConfiguration = CXProviderConfiguration()
        providerConfiguration.maximumCallsPerCallGroup = 1
        providerConfiguration.supportedHandleTypes = [.generic, .phoneNumber]
        return providerConfiguration
    }()
    
    private let provider = CXProvider(configuration: ProviderManager.providerConfiguration)
    weak var delegate: ProviderManagerDelegate?
    
    override init() {
        super.init()
        provider.setDelegate(self, queue: nil)
    }
    
    public func reportOutgoingCall(callUUID: UUID) {
        provider.reportOutgoingCall(with: callUUID, connectedAt: .now)
    }
    
    public func reportFailedCall(callUUID: UUID) {
        provider.reportCall(with: callUUID, endedAt: .now, reason: .failed)
    }
    
    public func reportEndedCall(callUUID: UUID) {
        provider.reportCall(with: callUUID, endedAt: .now, reason: .remoteEnded)
    }
}

Le code ci-dessus comprend la création d'un CXProvider et quelques fonctions d'aide pour signaler l'état des appels au système. La fonction ProviderManagerDelegate est également définie ici.

Mise en œuvre de laCXProviderDelegate

Le CXProviderDelegate vous permet d'obtenir des mises à jour du système concernant les appels. Ajoutez une extension au fichier ProviderManager qui implémente le délégué dans le même fichier :

extension ProviderManager: CXProviderDelegate {
    func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
        provider.reportOutgoingCall(with: action.callUUID, startedConnectingAt: .now)
        delegate?.callReported(self, callUUID: action.callUUID)
        action.fulfill()
    }
    
    func providerDidReset(_ provider: CXProvider) {
        delegate?.providerReset()
    }
    
    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
        VGVoiceClient.enableAudio(audioSession)
    }
    
    func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
        VGVoiceClient.disableAudio(audioSession)
    }
}

Lorsqu'un utilisateur saisit et numéro et démarre un appel, l'app demande à CallKit de démarrer l'appel. Si cette demande aboutit, la fonction CXStartCallAction sera appelée pour signaler l'appel sortant. Il est très important de noter que VGVoiceClient.enableAudio/VGVoiceClient.disableAudio est appelé ici avec la session audio fournie par CallKit CXProviderDelegate.

Mise à jour de laCallModel

Maintenant que le ProviderManager est mise en place, vous pouvez maintenant mettre à jour la classe CallModel pour l'utiliser. Ouvrez le fichier ContentView.swift et remplacez les variables en haut de la classe CallModel de la classe :

final class CallModel: NSObject, ObservableObject, VGVoiceClientDelegate {

    @Published var status: String = ""
    @Published var isCalling: Bool = false
    private let client = VGVoiceClient()
    var number: String = ""


    private var callId: (vonage: String?, callkit: UUID?)
    private let callController = CXCallController()
    private let providerManager = ProviderManager()
    private let audioSession = AVAudioSession.sharedInstance()

    ...
}

callId a été remplacé par un tuple pour gérer le mappage d'un ID d'appel Vonage à un UUID d'appel CallKit, providerManager a été ajouté ainsi que callController. callController est une instance de CXCallControllerqui sera utilisée pour demander au système de démarrer un appel.

Mise à jour de lastartCall Fonction

La fonction startCall doit maintenant être mise à jour pour demander un appel via la fonction callController lorsque l'utilisateur clique sur la fonction de démarrage de l'appel. Remplacez la fonction existante par la nouvelle :

func startCall() {
    isCalling = true
    let handle = CXHandle(type: .phoneNumber, value: number)
    self.callId.callkit = UUID()
    
    let startCallAction = CXStartCallAction(call: self.callId.callkit!, handle: handle)
    let transaction = CXTransaction(action: startCallAction)
    callController.request(transaction) { _ in }
}

Cette nouvelle fonction crée un UUID puisque CallKit a besoin d'un moyen d'identifier l'appel, mais vous n'obtiendrez pas l'ID de l'appel Vonage tant que le SDK n'aura pas passé un appel. Ensuite, un CXStartCallAction est utilisé dans un CXTransaction pour demander un appel. Cela appellera la fonction CXStartCallAction sur la fonction CXProviderDelegate que vous avez définie plus tôt.

Mise à jour de laendCall Fonction

De même, la fonction endCall doit être mise à jour pour être utilisée avec CallKit. Remplacez la fonction existante par la nouvelle :

func endCall() {
    client.hangup(callId.vonage!) { error in
        if error == nil {
            if let callkitUUID = self.callId.callkit {
                let transaction = CXTransaction(action: CXEndCallAction(call: callkitUUID))
                self.callController.request(transaction) { _ in }
            }
        }
    }
}

Cette nouvelle fonction a créé une action CXEndCallAction qui est utilisée dans un CXTransaction pour demander la fin de l'appel. En demandant la fin de l'appel, le système est en mesure de calculer la durée de l'appel avec précision. Vous devez également gérer le cas où l'appel est terminé à distance. Mettez à jour la fonction didReceiveHangupForCall de la fonction VGVoiceClientDelegate délégué :

func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {
    if let callkitUUID = self.callId.callkit {
        providerManager.reportEndedCall(callUUID: callkitUUID)
    }
    resetState()
}

Une fois encore, cela a permis de s'assurer que la fin de l'appel est signalée au système par l'intermédiaire de la touche providerManagerau système afin que la durée de l'appel puisse être calculée avec précision.

Mise en œuvre de laProviderManagerDelegate

Enfin, mettez en œuvre le ProviderManagerDelegate afin que le providerManager soit en mesure de communiquer les changements à l CallModel:

extension CallModel: ProviderManagerDelegate {
    func callReported(_ providerManager: ProviderManager, callUUID: UUID) {
        client.serverCall(["to": number]) { error, callId in
            if error == nil {
                providerManager.reportOutgoingCall(callUUID: callUUID)
                self.callId.vonage = callId
            } else {
                providerManager.reportFailedCall(callUUID: callUUID)
            }
        }
    }
    
    func providerReset() {
        resetState()
    }
}

Lorsque le providerManager a signalé l'appel au système avec succès, cette fonction déléguée crée un appel à l'aide du Client SDK de Vonage. Encore une fois, dans les cas de réussite et d'erreur, la fonction de délégation est utilisée pour signaler l'état de l'appel au système. providerManager est utilisée pour signaler l'état de l'appel au système. Vous pouvez maintenant passer un appel dans l'application en exécutant le projet Xcode sur un appareil physique. Si vous regardez les appels récents dans l'application téléphone sur iOS, vous devriez voir votre appel et le nom de l'application. Si vous cliquez sur l'icône d'information, vous pourrez également voir la durée de l'appel.

Call log from phone app

Quelle est la prochaine étape ?

Vous pouvez trouver le projet terminé sur GitHub. Vous pouvez faire beaucoup plus avec le Client SDK et CallKit ; vous pouvez utiliser CallKit pour les appels sortants. Pour en savoir plus sur le Client SDK, consultez la page Aperçu du Client SDK de Vonage et CallKit sur developer.apple.com.

Partager:

https://a.storyblok.com/f/270183/400x400/19c02db2d3/abdul-ajetunmobi.png
Abdul AjetunmobiVonage Ancien membre de l'équipe

Abdul est défenseur des développeurs chez Vonage. Il a travaillé dans le domaine des produits de consommation en tant qu'ingénieur iOS. Pendant son temps libre, il aime faire du vélo, écouter de la musique et conseiller ceux qui commencent leur parcours dans la technologie.