https://d226lax1qjow5r.cloudfront.net/blog/blogposts/make-app-to-phone-call-using-ios-and-flutter/flutter_inapp-call-2_1200x600.png

Passer un appel App-To-Phone avec iOS et Flutter

Publié le April 1, 2021

Temps de lecture : 12 minutes

Aujourd'hui, nous allons créer une iOS application en utilisant Flutter et utiliser le Vonage Client SDK pour passer un appel depuis une application mobile vers le téléphone en utilisant l Conversation API de Vonage. L'application aura 3 écrans (3 états de l'interface utilisateur) :

UI states: logon, make a call, and end call

Conditions préalables

Le code source de notre Flutter iOS est disponible sur GitHub.

Avant de commencer à construire l'application Flutter application pour l'appareil iOS nous devons préparer les conditions préalables suivantes :

  • Créer un objet de contrôle d'appel (NCCO)

  • Installer le Vonage CLI (précédemment Nexmo CLI)

  • Configurer le Vonage application

  • Installer le Flutter SDK

  • Créer le Flutter projet

Applications Vonage

Créer un OCNI

A Objet de contrôle d'appel (NCCO) est un JSON tableau que nous utilisons pour contrôler le flux d'un appel. Voice API call.

Les NCCO doit être public et accessible par l'internet. Pour ce faire, nous utiliserons dans ce tutoriel GitHub Gist qui offre un moyen pratique d'héberger la configuration. Ajoutons une nouvelle gist :

  1. Aller à https://gist.github.com/ (il faut être connecté à Github)

  2. Créer un nouveau gist avec ncco.json comme nom de fichier

  3. Copiez et collez l'objet suivant JSON suivant dans le gist :

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "number": "PHONE_NUMBER"
            }
        ]
    }
]
  1. Remplacer PHONE_NUMBER par votre numéro de téléphone (Les numéros de Vonage sont au format E.164, + et - ne sont pas valables. Veillez à préciser l'indicatif du pays lorsque vous saisissez le numéro, par exemple, US : 14155550100 et UK : 447700900001)

  2. Cliquez sur le bouton Create secret gist bouton

  3. Cliquez sur le bouton Raw bouton

  4. Prenez note de l'URL affichée dans le navigateur, nous l'utiliserons dans l'étape suivante.

Installer le CLI de Vonage

L'interface CLI de Vonage CLI de Vonage de Vonage nous permet d'effectuer de nombreuses opérations à l'aide de la ligne de commande. Si nous voulons effectuer des tâches telles que la création d'applications, la création de conversations, l'achat de numéros Vonage, etc., nous devons installer le CLI de Vonage.

La CLI de Vonage nécessite Node.jsNode.js, nous devrons donc installer Node.js en premier.

Pour installer la version Beta du CLI avec npm, exécutez cette commande :

npm install nexmo-cli@beta -g

Configurer le Vonage CLI pour utiliser le système Vonage API Key et API Secret. Nous pouvons les obtenir à partir de la page page des paramètres dans le tableau de bord.

Exécutez la commande suivante dans le terminal, en remplaçant API_KEY et API_SECRET par les valeurs du Tableau de bord:

nexmo setup API_KEY API_SECRET

Configuration de l'application Vonage

  1. Créez le répertoire du projet. Exécutez la commande suivante dans le terminal :

mkdir vonage-tutorial
  1. Allez dans le répertoire du projet :

cd vonage-tutorial
  1. Créez une application Vonage en copiant et en collant la commande ci-dessous dans le terminal. Veillez à modifier la valeur de l'argument --voice-answer-url en remplaçant GIST-URL par l'URL gist de l'étape précédente.

nexmo app:create "App to Phone Tutorial" --capabilities=voice --keyfile=private.key --voice-event-url=https://example.com/ --voice-answer-url=GIST-URL

Notez le message Application ID qui apparaît dans le terminal lors de la création de l'application.

NOTE : Un fichier caché nommé .nexmo-app est créé dans le répertoire du projet et contient le fichier nouvellement créé Vonage Application ID et la clé privée. Un fichier de clé privée nommé private.key est également créé dans le dossier en cours.

Créer un utilisateur

Chaque participant est représenté par un utilisateur et doit être authentifié par l'objet Client SDK. Dans une application de production, nous stockons généralement ces informations sur les utilisateurs dans une base de données.

Exécutez la commande suivante pour créer un utilisateur appelé Alice:

nexmo user:create name="Alice"

Générer un JWT

Le JWT est utilisé pour authentifier l'utilisateur. Exécutez la commande suivante dans le terminal pour générer un JWT pour l'utilisateur Alice. Dans la commande suivante, remplacez le APPLICATION_ID par l'ID de l'application :

nexmo jwt:generate sub=Alice exp=$(($(date +%s)+86400)) acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}' application_id=APPLICATION_ID

La commande ci-dessus fixe l'expiration du JWT à un jour à partir de maintenant, ce qui est le maximum.

Notez les JWT que nous avons généré pour Alice.

NOTE : Dans un environnement de production, l'application doit exposer un point de terminaison qui génère un JWT pour chaque demande du client.

Installer Xcode

Ouvrir l'AppStore et installer Xcode.

Mise en place de Flutter

Installer le SDK Flutter

Télécharger et installer Flutter SDK.

Cette étape varie en fonction de la taille de l'entreprise. MacOS, Win, et Linuxmais en général, elle se résume à télécharger Flutter SDK pour un système d'exploitation donné, d'extraire le fichier Flutter SDK et d'ajouter le dossier sdk\bin à la variable système PATH du système. Des instructions détaillées pour toutes les plateformes peuvent être trouvées ici.

Heureusement, Flutter est accompagné d'un outil qui nous permet de vérifier si SDK et tous les "composants" requis sont présents et configurés correctement. Exécutez la commande suivante :

flutter doctor

Flutter Doctor vérifiera si l'application Flutter SDK est installé et que les autres composants sont installés et configurés correctement.

Créer un projet Flutter

Nous allons créer un Flutter projet à l'aide du terminal :

flutter create app_to_phone_flutter

La commande ci-dessus crée un dossier app_to_phone_flutter contenant le Flutter projet.

Flutter le projet contient ios qui contient le projet iOS projet ; android le dossier contenant le Android projet ; et web dossier contenant le web le projet.

Ouvrez le fichier pubspec.yaml et ajoutez la dépendance permission_handler la dépendance (juste en dessous de sdk: flutter) :

dependencies:
  flutter:
    sdk: flutter
  
  permission_handler: ^6.0.1+1

L'indentation est importante dans les fichiers yaml assurez-vous donc que le niveau d'indentation de permission_handler soit au même niveau d'indentation que l'élément flutter: .

Exécutez maintenant cette commande (le chemin est la racine du projet Flutter ) pour télécharger la dépendance ci-dessus :

flutter pub get

La commande ci-dessus créera également Podfile dans le sous-dossier ios dans le sous-dossier Ouvrir ios\Podfile décommenter platform et mettez à jour la version de la plate-forme en 11:

platform :ios, '11.0'

A la fin du même fichier, ajouter pod 'NexmoClient':

target 'Runner' do
  use_frameworks!
  use_modular_headers!
  pod 'NexmoClient'

Ouvrir app_to_phone_flutter/ios dans le terminal et installer les pods :

pod install

La commande ci-dessus téléchargera toutes les dépendances nécessaires, y compris Flutterle gestionnaire de permissions, et Client SDK.

Ouvrir Runner.xcworkspace dans Xcode et lancez l'application pour vérifier que la configuration ci-dessus a été effectuée correctement.

Communication bidirectionnelle Flutter/iOS

Actuellement, Client SDK n'est pas disponible en tant que paquetage Flutter nous devrons donc utiliser le Client SDK natif d'Android et communiquer entre iOS et Flutter en utilisant CanalMéthode - de cette manière, Flutter appellera les méthodes Android, iOS appellera les méthodes Flutter méthodes.

Le code Flutter sera stocké dans le fichier lib/main.dart tandis que le code natif iOS le code natif sera stocké dans le fichier ios/Runner/AppDelegate.swift fichier.

Init Flutter Application

Les applications Flutter sont construites à l'aide d'un langage de programmation appelé Dart.

Ouvrir lib/main.dart et remplacez tout le contenu par le code suivant :

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CallWidget(title: 'app-to-phone-flutter'),
    );
  }
}

class CallWidget extends StatefulWidget {
  CallWidget({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _CallWidgetState createState() => _CallWidgetState();
}

class _CallWidgetState extends State<CallWidget> {
  SdkState _sdkState = SdkState.LOGGED_OUT;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(height: 64),
            _updateView()
          ],
        ),
      ),
    );
  }

  Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          child: Text("LOGIN AS ALICE")
      );
    }
  }

  Future<void> _loginUser() async {
      // Login user
  }

  Future<void> _makeCall() async {
      // Make call
  }

  Future<void> _endCall() async {
      // End call
  }
}

enum SdkState {
  LOGGED_OUT,
  LOGGED_IN,
  WAIT,
  ON_CALL,
  ERROR
}

Le code ci-dessus contient le code personnalisé CallWidget qui sera responsable de la gestion de l'état de l'application (enregistrement de l'utilisateur et gestion de l'appel). L'énumération SdkState représente les états possibles de Vonage Client SDK. Cette énumération sera définie deux fois - une pour Flutter en utilisant Dart et l'autre pour iOS utilisant Swift. Le widget contient la méthode _updateView qui modifiera l'interface utilisateur en fonction de la valeur de l'enum. SdkState valeur.

Exécutez l'application à partir de la page Xcode:

Running the application from xcode

Le bouton Login as Alice doit s'afficher :

Logged out screen showing Login as Alice button

Écran de connexion

Le bouton Login as Alice est désactivé, il faut donc maintenant ajouter onPressed à l'élément ElevatedButton pour permettre l'ouverture d'une session :

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    }
  }

Mise à jour du corps de _loginUser pour communiquer avec le code natif et connecter l'utilisateur :

Future<void> _loginUser() async {
    String token = "ALICE_TOKEN";

    try {
      await platformMethodChannel.invokeMethod('loginUser', <String, dynamic>{'token': token});
    } on PlatformException catch (e) {
      print(e);
    }
  }

Remplacer le ALICE_TOKEN par le jeton JWT que nous avons obtenu précédemment à partir de Vonage CLI pour authentifier l'utilisateur Alice pour l'accès à la conversation. Flutter appellera la méthode loginUser et transmettra la méthode token comme argument. La méthode loginUser est définie dans la classe MainActivity (nous y reviendrons dans un instant). Pour appeler cette méthode à partir de Flutter nous devons définir une méthode MethodChannel. Ajouter platformMethodChannel au sommet de la classe _CallWidgetState classe :

Ajouter platformMethodChannel en haut de la page _CallWidgetState classe :

class _CallWidgetState extends State<CallWidget> {
  SdkState _sdkState = SdkState.LOGGED_OUT;
  static const platformMethodChannel = const MethodChannel('com.vonage');

La chaîne com.vonage représente l'identifiant unique du canal auquel nous ferons également référence dans le code natif iOS (AppDelegate ). Nous devons maintenant gérer cet appel de méthode du côté natif. iOS côté natif.

Ouvrir ios/Runner/AppDelegate et la propriété vonageChannel qui contiendra la référence à la classe FlutterMethodChannel:

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  var vonageChannel: FlutterMethodChannel?
    
...

Pour écouter les appels de méthodes provenant de Flutter ajouter addFlutterChannelListener à l'intérieur de la AppDelegate (même niveau que la méthode application ci-dessus) :

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

La méthode ci-dessus "traduit" les appels de méthode Flutter en méthodes définies dans la classe AppDelegate (la classe loginUser pour l'instant).

Et il manque les méthodes loginUser à l'intérieur de la même classe (nous remplirons le corps bientôt) :

func loginUser(token: String) {

}

Ajoutez maintenant addFlutterChannelListener à l'intérieur de la méthode application à l'intérieur de la méthode :

override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        addFlutterChannelListener()
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

Le code est en place - après avoir appuyé sur le bouton Login As Alice l'application Flutter appellera la méthode _loginUser méthode. Par l'intermédiaire du canal Flutter la méthode appellera la méthode loginUser définie dans la classe AppDelegate classe.

Exécutez l'application à partir de Xcode pour s'assurer qu'elle se compile.

Avant de pouvoir se connecter à l'utilisateur, nous devons initialiser le fichier Vonage SDK Client.

Initialiser le client

Ouvrir AppDelegate et ajoutez l'élément NexmoClient au début du fichier :

import NexmoClient

Dans le même fichier, ajoutez la propriété client qui contiendra une référence à Vonage Client.

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    var vonageChannel: FlutterMethodChannel?
    let client = NXMClient.shared

...

Ajoutez maintenant la méthode initClient pour initialiser le client :

func initClient() {
        client.setDelegate(self)
    }

Pour appeler la méthode initClient à partir de la méthode application existante, nous allons devoir ajouter la ligne initClient() comme le montre l'exemple ci-dessous :

override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        initClient()
        addFlutterChannelListener()
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

Avant d'autoriser la conversation, nous devons nous assurer que l'utilisateur s'est correctement connecté. Dans le fichier AppDelegate ajouter un délégué pour écouter les changements d'état de connexion Vonage Client SDK les changements d'état de connexion :

extension AppDelegate: NXMClientDelegate {
    func client(_ client: NXMClient, didChange status: NXMConnectionStatus, reason: NXMConnectionStatusReason) {
        switch status {
        case .connected:
            notifyFlutter(state: .loggedIn)
        case .disconnected:
            notifyFlutter(state: .loggedOut)
        case .connecting:
            notifyFlutter(state: .wait)
        @unknown default:
            notifyFlutter(state: .error)
        }
    }
}

Enfin, la méthode notifyFlutter doit être ajoutée à la même classe :

func client(_ client: NXMClient, didReceiveError error: Error) {
        notifyFlutter(state: .error)
    }
}

Connexion de l'utilisateur

Modifier loginUser le corps de la méthode pour appeler login sur l'instance du client :

func loginUser(token: String) {
        self.client.login(withAuthToken: token)
    }

Cette méthode nous permettra de connecter l'utilisateur (Alice) à l'aide de l'icône Client SDK pour accéder à la conversation.

Notifier à Flutter le changement d'état du Client SDK

Pour notifier Flutter de toute modification de l'état de la base de données Client SDKnous devons ajouter un élément enum pour représenter les états de Client SDK. Nous avons déjà ajouté l'équivalent SdkState équivalent dans le fichier main.dart Nous avons déjà ajouté l'enum équivalent dans le fichier Ajoutez l'enum suivant SdkState suivante, au bas du fichier MainActivity.kt au bas du fichier :

enum SdkState: String {
        case loggedOut = "LOGGED_OUT"
        case loggedIn = "LOGGED_IN"
        case wait = "WAIT"
        case onCall = "ON_CALL"
        case error = "ERROR"
    }

Pour envoyer ces états à Flutter (à partir du délégué ci-dessus), nous devons ajouter la méthode notifyFlutter dans la AppDelegate dans la classe :

func notifyFlutter(state: SdkState) {
        vonageChannel?.invokeMethod("updateState", arguments: state.rawValue)
    }

Remarquez que nous stockons l'état dans l'énumération, mais que nous l'envoyons sous la forme d'une chaîne de caractères.

Récupérer la mise à jour de l'état du SDK par Flutter

Pour récupérer les mises à jour de l'état dans Flutter nous devons écouter les mises à jour du canal de la méthode. Ouvrir le fichier main.dart et ajoutez le constructeur _CallWidgetState avec un gestionnaire personnalisé :

_CallWidgetState() {
    platformMethodChannel.setMethodCallHandler(methodCallHandler);
  }

Dans la même classe (_CallWidgetState), ajoutez la méthode de gestion :

Future<dynamic> methodCallHandler(MethodCall methodCall) async {
    switch (methodCall.method) {
      case 'updateState':
        {
          setState(() {
            var arguments = 'SdkState.${methodCall.arguments}';
            _sdkState = SdkState.values.firstWhere((v) {return v.toString() == arguments;}
            );
          });
        }
        break;
      default:
        throw MissingPluginException('notImplemented');
    }
  }

Ces méthodes reçoivent le "signal" d'Android et le convertissent en une énumération. Mettez maintenant à jour le contenu de la méthode _updateView pour prendre en charge SdkState.WAIT et SdkState.LOGGED_IN comme le montre l'exemple ci-dessous :

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    }  else if (_sdkState == SdkState.WAIT) {
      return Center(
        child: CircularProgressIndicator(),
      );
    } else if (_sdkState == SdkState.LOGGED_IN) {
      return ElevatedButton(
          onPressed: () { _makeCall(); },
          child: Text("MAKE PHONE CALL")
      );
    }
  }

Pendant la durée de l'opération, la barre de progression s'affiche. SdkState.WAIT la barre de progression s'affiche. Une fois la connexion réussie, l'application affichera le bouton MAKE PHONE CALL s'affichera.

Lancez l'application et cliquez sur le bouton intitulé LOGIN AS ALICE. Le bouton MAKE PHONE CALL devrait apparaître, ce qui représente un autre état de l'application Flutter basé sur l'élément SdkState enum`). Un exemple de ceci est montré dans l'image ci-dessous :

Make a phone call UI state

Passer un appel

Nous devons maintenant ajouter la fonctionnalité permettant de passer un appel téléphonique. Ouvrez le fichier main.dart et mettez à jour le corps de la méthode _makeCall comme indiqué ci-dessous :

Future<void> _makeCall() async {
    try {
      await platformMethodChannel
          .invokeMethod('makeCall');
    } on PlatformException catch (e) {
      print(e);
    }
  }

La méthode ci-dessus communiquera avec iOS nous devons donc mettre à jour le code dans la classe AppDelegate également. Ajouter makeCall à l'instruction switch à l'intérieur de l'instruction addFlutterChannelListener à l'intérieur de la méthode :

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            case "makeCall":
                self.makeCall()
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

Maintenant, dans le même fichier, ajoutez la propriété onGoingCall qui définit si et quand un appel est en cours :

var onGoingCall: NXMCall?

REMARQUE : Actuellement, le Client SDK ne stocke pas la référence de l'appel en cours, nous devons donc la stocker dans la classe AppDelegate dans la classe Nous l'utiliserons plus tard pour mettre fin à l'appel.

Maintenant, dans la même classe, ajoutez makeCall méthode :

func makeCall() {
        client.call("IGNORED_NUMBER", callHandler: .server) { [weak self] (error, call) in
            guard let self = self else { return }
            
            if error != nil {
                self.notifyFlutter(state: .error)
                return
            }
            
            self.onGoingCall = call
            self.notifyFlutter(state: .onCall)
        }
    }

La méthode ci-dessus définit l'état de l'application Flutter à SdkState.WAIT et attend la réponse de Client SDK (erreur ou succès). Nous devons maintenant ajouter un support pour les deux états (SdkState.ON_CALL et SdkState.ERROR) dans le fichier main.dart fichier. Mettez à jour le corps de la méthode _updateView pour qu'il soit identique à celui présenté ci-dessous :

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    } else if (_sdkState == SdkState.WAIT) {
      return Center(
        child: CircularProgressIndicator(),
      );
    } else if (_sdkState == SdkState.LOGGED_IN) {
      return ElevatedButton(
          onPressed: () { _makeCall(); },
          child: Text("MAKE PHONE CALL")
      );
    } else if (_sdkState == SdkState.ON_CALL) {
      return ElevatedButton(
          onPressed: () { _endCall(); },
          child: Text("END CALL")
      );
    } else {
      return Center(
        child: Text("ERROR")
      );
    }
  }

Chaque changement d'état entraîne une modification de l'interface utilisateur. Avant de passer un appel, l'application a besoin de permissions spécifiques pour utiliser le microphone. Dans l'étape suivante, nous allons ajouter la fonctionnalité dans le projet pour demander ces permissions.

Demander des autorisations

L'application doit pouvoir accéder au microphone, nous devons donc demander l'accès au microphone (Permission.microphone pour Flutter ).

Ouvrir ios/Runner/info.plist et ajouter la clé Privacy - Microphone Usage Description clé avec Make a call valeur :

Setting add microphone permission

Nous avons déjà ajouté l'élément permission_handler au Flutter au projet Maintenant, en haut du fichier main.dart nous devons importer le paquetage permission_handler comme le montre l'exemple ci-dessous :

import 'package:permission_handler/permission_handler.dart';

Pour déclencher la demande de certaines autorisations, nous devons ajouter la méthode requestPermissions() dans la classe _CallWidgetState dans le fichier main.dart à l'intérieur de la classe. Ajoutez donc cette nouvelle méthode à l'intérieur de la classe :

Future<void> requestPermissions() async {
    await [ Permission.microphone ].request();
  }

La méthode ci-dessus demandera des autorisations en utilisant permission_handler.

Dans la même classe, modifiez le corps de la classe _makeCall pour demander des permissions avant d'appeler la méthode via le canal des méthodes :

Future<void> _makeCall() async {
    try {
      await requestPermissions();
 
      ...
  }

Lancez l'application et cliquez sur MAKE PHONE CALL pour démarrer un appel. La boîte de dialogue des autorisations s'affiche et, une fois les autorisations accordées, l'appel démarre.

Rappel : nous avons défini le numéro de téléphone plus tôt dans la NCCO

L'état de l'application sera mis à jour à SdkState.ON_CALL et l'interface utilisateur sera mise à jour :

On call UI

Fin de l'appel

Pour mettre fin à l'appel, nous devons déclencher la méthode sur l'application native iOS à l'aide de platformMethodChannel. Inside main.dart mettre à jour le corps de la méthode _endCall dans le fichier :

Future<void> _endCall() async {
    try {
      await platformMethodChannel.invokeMethod('endCall');
    } on PlatformException catch (e) {}
  }

La méthode ci-dessus communiquera avec iOSNous devons donc mettre à jour le code dans la classe AppDelegate également. Ajouter endCall à l'instruction switch à l'intérieur de la méthode addFlutterChannelListener à l'intérieur de la méthode :

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            case "makeCall":
                self.makeCall()
                result("")
            case "endCall":
                self.endCall()
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

Maintenant, dans la même classe, ajoutez la méthode endCall méthode :

func endCall() {
        onGoingCall?.hangup()
        onGoingCall = nil
        notifyFlutter(state: .loggedIn)
    }

La méthode ci-dessus définit l'état de l'application Flutter à SdkState.WAIT et attend la réponse de l'application Client SDKqui peut être une erreur ou un succès. Les deux états de l'interface utilisateur sont déjà pris en charge dans l'application Flutter application (méthode_updateView ).

Nous avons géré la fin de l'appel en appuyant sur le bouton END CALL dans l'interface utilisateur de l'application Flutter de l'application. Cependant, l'appel peut également se terminer en dehors de l'application. Flutter par exemple, l'appel sera rejeté ou répondu, et l'appelant y mettra fin plus tard (sur le vrai téléphone).

Pour prendre en charge ces cas, nous devons ajouter l'écouteur NexmoCallEventListener à l'instance d'appel et écouter les événements spécifiques à l'appel.

Dans le fichier AppDelegares.swift ajouter NXMCallDelegate:

extension AppDelegate: NXMCallDelegate {
    func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, with status: NXMCallMemberStatus) {
        if (status == .completed || status == .cancelled) {
            onGoingCall = nil
            notifyFlutter(state: .loggedIn)
        }
    }
    
    func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, isMuted muted: Bool) {
        
    }
    
    func call(_ call: NXMCall, didReceive error: Error) {
        notifyFlutter(state: .error)
    }
}

Pour enregistrer l'écouteur ci-dessus, modifiez onSuccess callback à l'intérieur de makeCall méthode :

func makeCall() {
        client.call("IGNORED_NUMBER", callHandler: .server) { [weak self] (error, call) in
            guard let self = self else { return }
            
            if error != nil {
                self.notifyFlutter(state: .error)
                return
            }
            
            self.onGoingCall = call
            self.onGoingCall?.setDelegate(self)
            self.notifyFlutter(state: .onCall)
        }
    }

Exécutez l'application et passez un appel téléphonique depuis l'application mobile vers un numéro de téléphone physique.

Résumé

Nous avons réussi à construire l'application. Ce faisant, nous avons appris à passer un appel téléphonique depuis une application mobile vers le téléphone en utilisant Vonage Client SDK. Pour le projet complet, veuillez consulter GitHub. Ce projet contient également le code natif Android (android ), ce qui nous permet d'exécuter cette application sur Android également.

Pour vous familiariser avec d'autres fonctionnalités, veuillez consulter d'autres tutoriels et Centre de développement de Vonage.

Références

Partager:

https://a.storyblok.com/f/270183/384x384/8ae5af43bb/igor-wojda.png
Igor WojdaAnciens de Vonage