https://a.storyblok.com/f/270183/93755/d624bc5e0b/blog_swiftui_phone-call_1200x600.png

Comment passer des appels téléphoniques avec SwiftUI

Publié le July 5, 2023

Temps de lecture : 15 minutes

Dans ce tutoriel, vous allez créer une application SwiftUI capable de passer des appels vers un numéro de téléphone spécifié à l'aide du SDK Vonage Client pour iOS. SwiftUI est un framework d'interface utilisateur publié par Apple en 2019, qui aide à construire des applications sur toutes les plateformes d'Apple avec moins de code que ses prédécesseurs. Comme vous le verrez, SwiftUI a une syntaxe déclarative qui permet d'énoncer ce que l'interface utilisateur doit faire, ce qui facilite la lecture de l'application.

Conditions préalables

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

  • Xcode 12 et Swift 5 ou supérieur.

  • Cocoapods pour installer le Vonage Client SDK pour iOS.

  • Le CLI de Vonage. Si vous ne l'avez pas déjà, il peut être installé avec npm install -g @vonage/cli.

Vue d'ensemble

Ce projet comporte 3 parties, l'application Vonage, le serveur webhook et l'application iOS. L'application Vonage permet d'utiliser les produits Vonage, dans ce cas, l Voice API. L'application Vonage que vous allez créer nécessite 2 URLs, une answer_url et une event_url. L'URL answer_url doit renvoyer un objet de contrôle d'appel, qui indiquera à Vonage comment traiter l'appel. La partie serveur du projet renverra un objet de contrôle d'appel basé sur le numéro qui est spécifié dans l'application iOS.

Création du serveur

Comme indiqué précédemment, vous devez créer un serveur webhook qui expose deux URL, dont l'une renvoie un objet de contrôle d'appel. Il contiendra une action de connexion qui transmettra l'appel au numéro de téléphone du numéro de téléphone PSTN. Pour ce faire, vous devez extraire le numéro de destination du paramètre de requête to et en le renvoyant dans votre réponse.

Créez un nouveau répertoire de projet dans une destination de votre choix et changez de répertoire :

mkdir vonage-tutorial cd vonage-tutorial

À l'intérieur du dossier, initialisez un nouveau projet Node.js en exécutant cette commande :

npm init -y npm install express localtunnel --save

Vous aurez besoin d'un numéro Vonage. Vous pouvez acheter un numéro à l'aide de l'interface utilisateur de Vonage. La commande suivante permet d'acheter un numéro disponible aux Etats-Unis. Spécifiez un autre code de pays à deux caractères pour acheter un numéro dans un autre pays.

vonage numbers:search US vonage numbers:buy 15555555555 US

Dans le dossier de votre projet, créez un fichier nommé server.js et ajoutez le code tel qu'illustré ci-dessous - assurez-vous de remplacer NUMBER par votre numéro Vonage (en E.164 ), ainsi que SUBDOMAIN par une valeur unique. La valeur utilisée fera partie des URL que vous définirez en tant que webhooks à l'étape suivante.

Création de l'application Vonage

Dans cette étape, vous allez créer une application Vonage Applications capable de répondre à des cas d'utilisation de communication vocale in-App.

Créer une application

Créez une application Vonage en copiant et en collant la commande ci-dessous dans le terminal. Veillez à modifier les valeurs de --voice_answer_url et --voice_event_url en remplaçant SUBDOMAIN par la valeur réelle utilisée à l'étape précédente :

vonage apps:create "SwiftUICall" --voice_answer_url=https://SUBDOMAIN.loca.lt/voice/answer --voice_event_url=https://SUBDOMAIN.loca.lt/voice/event

Un fichier nommé vonage_app.json est créé dans le répertoire de votre projet et contient l'identifiant de l'application Vonage nouvellement créée et la clé privée. Un fichier de clé privée nommé SwiftUICall.key est également créé. Maintenant que votre application est créée, liez votre numéro Vonage à votre application :

vonage apps:link APPLICATION_ID --number=YOUR_VONAGE_NUMBER

Créer un utilisateur

La Conversation API de Vonage a le concept de utilisateurs. Un utilisateur représente un utilisateur unique de votre application et possède donc un identifiant unique. C'est ainsi que votre application iOS s'authentifiera auprès des serveurs de Vonage et sera identifiée par ces derniers. Vous pouvez utiliser le CLI pour créer un utilisateur :

vonage apps:users:create "Alice"

Ceci ajoutera un utilisateur, avec le nom d'utilisateur Alice, à votre application et produira son identifiant unique.

Créer un JWT

Les SDK de Vonage Client utilisent des jetons Web JSON (JWT) pour l'authentification. Les JWT sont une méthode de représentation sécurisée des demandes entre deux parties. Pour en savoir plus sur les JWT, consultez le site JWT.io ou sur les réclamations prises en charge par l Conversation API prend en charge. Nous allons utiliser la clé privée, l'identifiant de l'application et le nom d'utilisateur des sections précédentes pour créer le JWT nécessaire à votre application iOS. Encore une fois, cela se fait via le CLI. Remplacez la variable APPLICATION_ID par l'identifiant de votre application et la variable PRIVATE_KEY par le nom de votre fichier de clé privée.

vonage jwt --app_id=APPLICATION_ID --subject=Alice --key_file=./PRIVATE_KEY --acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}'

Vous obtiendrez ainsi le JWT de l'utilisateur Alice, qui a été signé à l'aide de votre clé privée. Conservez-la, car vous en aurez besoin plus tard.

Création de l'application iOS

Maintenant que le serveur et l'application Vonage sont configurés, il est temps de construire l'application iOS.

Créer un projet Xcode

Pour commencer, ouvrez Xcode et créez un nouveau projet en allant dans Fichier > Nouveau > Projet. Sélectionnez un modèle d'application et donnez-lui un nom. Sélectionnez SwiftUI pour l'interface, SwiftUI App pour le cycle de vie, et Swift pour le langage - enfin, un emplacement pour enregistrer votre projet.

Xcode project creation

Installer le Client SDK de Vonage

Maintenant que le projet est créé, vous pouvez ajouter le Vonage Client SDK comme dépendance. Naviguez jusqu'à l'emplacement où vous avez enregistré le projet dans votre terminal et exécutez les commandes suivantes.

  1. Exécutez la commande pod init pour créer un nouveau Podfile pour votre projet.

  2. Ouvrez le fichier Podfile dans Xcode en utilisant open -a Xcode Podfile.

  3. Mettre à jour le Podfile pour avoir VonageClientSDKVoice comme dépendance.

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'SwiftUICall' do
    # Comment the next line if you don't want to use dynamic frameworks
    use_frameworks!

    # Pods for SwiftUICall
    pod 'VonageClientSDKVoice'

end
  1. Installer le SDK en utilisant pod install.

  2. Ouvrez le nouvel espace de travail xcworkspace dans Xcode en utilisant open SwiftUICall.xcworkspace.

Autorisations pour le microphone

Étant donné que l'application utilisera le microphone pour passer des appels, vous devez demander explicitement l'autorisation de le faire. La première étape consiste à éditer le fichier Info.plist (en anglais). Il s'agit d'un fichier qui contient toutes les métadonnées nécessaires à l'application. Ajoutez une nouvelle entrée au fichier en passant votre souris sur la dernière entrée de la liste et en cliquant sur le petit bouton + qui apparaît. Choisissez Privacy - Microphone Usage Description dans la liste déroulante et ajoutez Microphone access required to make and receive audio calls. pour sa valeur. Vous effectuerez la deuxième étape de la demande d'autorisations pour les microphones plus loin dans le tutoriel.

Création de la classe de modèle

Avant de commencer à construire l'interface utilisateur (UI) de l'application, vous allez d'abord construire une classe de modèle. Cette classe est utilisée pour séparer la logique de l'application du code de visualisation. Dans le cas présent, la classe de modèle gérera les appels de délégués du Client SDK et le moment où le bouton d'appel doit s'afficher. Au début du fichier ContentView.swift importez le Client SDK et AVFoundation.

import SwiftUI
import AVFoundation
import VonageClientSDKVoice

Ensuite, au bas du fichier, créez une nouvelle classe appelée CallModel:

final class CallModel: NSObject, ObservableObject, VGVoiceClientDelegate {

}

Dans cette classe, définissez les propriétés et les fonctions d'aide nécessaires :

final class CallModel: NSObject, ObservableObject, VGVoiceClientDelegate {
    @Published var status: String = ""
    @Published var isCalling: Bool = false
    let client = VGVoiceClient()
    var number: String = ""
    
    private var callId: String?
    private let audioSession = AVAudioSession.sharedInstance()
    
    func updateStatus(_ text: String) {
        DispatchQueue.main.async {
            self.status = text
        }
    }
    
    func resetState() {
        DispatchQueue.main.async {
            self.callId = nil
            self.isCalling = false
            self.number = ""
        }
    }
}

L'enveloppe de propriété @Published permet à l'interface utilisateur de savoir quand réagir aux changements de la classe de modèle. Tout cela est géré pour vous car la classe se conforme au ObservedObject protocole. La propriété client est destinée au client Voice de Vonage, qui vous permettra de passer des appels. callId est utilisée pour stocker l'objet d'appel, et audioSession est utilisée pour demander les autorisations du microphone. Configurez le Client SDK :

func initializeClient() {
    let config = VGClientConfig(region: .US)
    client.setConfig(config)
    client.delegate = self
}

Pour terminer la demande d'autorisations de microphone pour l'application, ajoutez la fonction suivante à la classe CallModel la fonction suivante :

func requestPermissionsIfNeeded() {
    if audioSession.recordPermission != .granted {
        audioSession.requestRecordPermission { (isGranted) in
            print("Microphone permissions \(isGranted)")
        }
    }
}

Cette opération vérifie d'abord si les autorisations ont déjà été accordées ; si ce n'est pas le cas, elle les demande et imprime le résultat sur la console. Ensuite, vous devez vous connecter en tant qu'utilisateur Alice avec le Client SDK. Pour ce faire, ajoutez la fonction suivante à la classe CallModel en remplaçant ALICE_JWT par le JWT de tout à l'heure :

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

Cette fonction vérifie si le client est déjà connecté ; si ce n'est pas le cas, elle utilisera le JWT que vous avez généré plus tôt pour vous connecter et définira le délégué du client à cette classe. La fonction VGVoiceClientDelegate est la façon dont le Client SDK communique les changements avec les serveurs de Vonage à votre application. Ensuite, mettez en œuvre les fonctions de délégation requises.

func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {
    self.resetState()
}

func client(_ client: VGBaseClient, didReceiveSessionErrorWith reason: VGSessionErrorReason) {
    let reasonString: String!
    
    switch reason {
    case .tokenExpired:
        reasonString = "Expired Token"
    case .pingTimeout, .transportClosed:
        reasonString = "Network Error"
    default:
        reasonString = "Unknown"
    }
    
    status = reasonString
}

func voiceClient(_ client: VGVoiceClient, didReceiveInviteForCall callId: VGCallId, from caller: String, with type: VGVoiceChannelType) {}
func voiceClient(_ client: VGVoiceClient, didReceiveInviteCancelForCall callId: VGCallId, with reason: VGVoiceInviteCancelReason) {}

En cas d'erreur de session, la propriété status est mise à jour et si l'appel se termine, l'état du modèle est réinitialisé. Les deux fonctions suivantes que vous devez ajouter permettront à votre application d'effectuer des appels et d'y mettre fin. Ajoutez les fonctions suivantes.

func startCall() {
    self.isCalling = true
    client.serverCall(["to": number]) { error, callId in
        if error == nil {
            self.callId = callId
        }
    }
}

func endCall() {
    client.hangup(callId!) { error in
        if error == nil {
            self.resetState()
        }
    }
}

La fonction callNumber utilise le Client SDK pour appeler le numéro figurant dans la propriété number de la propriété. Elle utilise la fonction answer_url utilisée plus tôt dans le tutoriel. Vonage effectuera alors un appel HTTP vers votre application iOS avec le numéro. answer_url avec le numéro de l'application iOS, qui renverra un objet de contrôle d'appel avec des instructions pour que Vonage connecte votre application au numéro. Si tout cela réussit, le Client SDK renvoie un identifiant d'appel qui est stocké sur la classe. La fonction endCall raccroche l'appel, définit la propriété callId à nil et remet le booléen isCalling à false pour que l'interface utilisateur puisse être mise à jour.

La dernière fonction que vous devez ajouter à la fonction CallModel calls initializeClient, requestPermissionsIfNeeded, et loginIfNeeded aux fonctions.

func setup() {
    initializeClient()
    requestPermissionsIfNeeded()
    loginIfNeeded()
}

Créer l'interface utilisateur

L'interface utilisateur se compose d'un objet Text pour afficher l'état, d'un objet TextField pour la saisie du numéro, et d'une paire d'objets Button pour commencer et terminer les appels. Ajoutez une propriété pour la classe CallModel que vous avez créée précédemment à la structure ContentView et utilisez-la pour afficher l'état du Client SDK.

struct ContentView: View {
    @StateObject var callModel = CallModel()
    
    var body: some View {
        VStack {
            Text(callModel.status)
        }
        .animation(.default)
        .onAppear(perform: self.callModel.setup)
    }
}

Lorsque la vue apparaît, elle appelle la fonction setup de la classe de modèle, qui demandera les autorisations du microphone et connectera le client. Ce faisant, elle mettra à jour la propriété status de la classe de modèle, et le changement de sa valeur invitera la classe de modèle à se mettre à jour ! ContentView à se mettre à jour !

Maintenant que le client est connecté, vous pouvez utiliser le reste des propriétés publiées sur la classe de modèle pour construire le reste de l'interface utilisateur. Ajoutez le bloc de code suivant à la VStack.

if self.callModel.status == "Connected" {
    TextField("Enter a phone number", text: $callModel.number)
        .textFieldStyle(RoundedBorderTextFieldStyle())
        .multilineTextAlignment(.center)
        .keyboardType(.numberPad)
        .disabled(self.callModel.isCalling)
        .padding(20)
    
    if !self.callModel.isCalling {
        Button(action: { self.callModel.startCall() }) {
            HStack(spacing: 10) {
                Image(systemName: "phone")
                Text("Call")
            }
        }
    }
    
    if self.callModel.isCalling {
        Button(action: { self.callModel.endCall() }) {
            HStack(spacing: 10) {
                Image(systemName: "phone")
                Text("End Call")
            }
            .foregroundColor(Color.red)
        }
    }
}

Le TextField s'animera sur la vue si le client est connecté. La valeur de l'élément TextField est liée à la propriété number de la classe de modèle. Pour ce faire, on utilise le signe $ pour ce faire. Une fois qu'un nombre de longueur valide a été saisi, les conditions d'affichage du bouton d'appel sont remplies, et une fois qu'un appel a commencé, les conditions ne sont plus remplies, mais les conditions d'affichage du bouton de fin d'appel le sont. Ainsi, un seul bouton s'affiche à la fois, et toute la mise à jour de l'interface utilisateur est gérée pour vous !

Exécutez votre application

Si vous exécutez le projet (CMD + R), vous serez d'abord invité à autoriser le microphone. Vous pourrez alors entrer un numéro et l'appeler ! Le format des Numbers doit être conforme à la norme E.164 .

Making a call

Quelle est la prochaine étape ?

Vous pouvez trouver le projet terminé sur GitHub. Vous pouvez faire beaucoup plus avec le Client SDK. En savoir plus sur developer.vonage.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.