
App-To-Phone-Anrufe mit iOS und Flutter
Lesedauer: 11 Minuten
Heute werden wir eine iOS Anwendung mit Flutter und nutzen das Vonage Client SDK um einen Anruf von einer mobilen Anwendung auf das Telefon zu tätigen. Vonage Conversation API. Die Anwendung wird 3 Bildschirme (3 UI-Zustände) haben:

Voraussetzungen
Der Quellcode für unsere Flutter iOS Anwendung ist verfügbar auf GitHub.
Bevor wir mit der Erstellung der Flutter Anwendung für das iOS Gerät zu erstellen, müssen wir die folgenden Voraussetzungen erfüllen:
Erstellen Sie ein Call Control Object (NCCO)
Installieren Sie die
Vonage CLI(zuvorNexmo CLI)Einrichten der
Vonage applicationInstallieren Sie die
Flutter SDKErstellen Sie das
FlutterProjekt
Vonage-Anwendung
Ein NCCO erstellen
A Anrufsteuerungsobjekt (NCCO) ist ein JSON Array, das wir zur Steuerung des Ablaufs einer Voice API call.
Die NCCO muss öffentlich und über das Internet zugänglich sein. Um dies zu erreichen, werden wir in diesem Tutorial Folgendes verwenden GitHub Gist das eine bequeme Möglichkeit bietet, die Konfiguration zu hosten. Fügen wir einen neuen Gist hinzu:
Besuchen Sie https://gist.github.com/ (wir müssen bei Github angemeldet sein)
Erstellen Sie einen neuen Gist mit
ncco.jsonals DateinameKopieren und fügen Sie das folgende
JSONObjekt in den Gist ein:
[
{
"action": "talk",
"text": "Please wait while we connect you."
},
{
"action": "connect",
"endpoint": [
{
"type": "phone",
"number": "PHONE_NUMBER"
}
]
}
]Ersetzen Sie
PHONE_NUMBERdurch Ihre Rufnummer (Vonage Numbers sind im E.164-Format,+und-sind nicht gültig. Achten Sie darauf, bei der Eingabe der Numbers die Landesvorwahl anzugeben, z. B. US: 14155550100 und UK: 447700900001)Klicken Sie auf die
Create secret gistSchaltflächeKlicken Sie auf die
RawSchaltflächeNotieren Sie sich die im Browser angezeigte URL, wir werden sie im nächsten Schritt verwenden
Vonage CLI installieren
Die Vonage CLI ermöglicht es uns, viele Vorgänge über die Befehlszeile auszuführen. Wenn wir Aufgaben wie das Erstellen von Applications, das Anlegen von Konversationen, den Kauf von Vonage Numbers usw. ausführen möchten, müssen wir die Vonage CLI installieren.
Vonage CLI erfordert Node.jsalso müssen wir zuerst Node.js installieren.
Um die Beta-Version des CLIs mit npm zu installieren, führen Sie diesen Befehl aus:
npm install nexmo-cli@beta -gRichten Sie die Vonage CLI zur Verwendung der Vonage API Key und API Secret. Diese können wir auf der Einstellungsseite im Dashboard.
Führen Sie den folgenden Befehl im Terminal aus und ersetzen Sie dabei API_KEY und API_SECRET durch Werte aus der Datei Dashboard:
nexmo setup API_KEY API_SECRET Vonage-Anwendung einrichten
Erstellen Sie das Projektverzeichnis. Führen Sie den folgenden Befehl im Terminal aus:
mkdir vonage-tutorialWechseln Sie in das Projektverzeichnis:
cd vonage-tutorialErstellen Sie eine Vonage-Anwendung, indem Sie den unten stehenden Befehl kopieren und in das Terminal einfügen. Vergewissern Sie sich, dass Sie den Wert von
--voice-answer-urlArgument durch Ersetzen vonGIST-URLdurch die Gist-URL aus dem vorherigen Schritt ersetzen.
nexmo app:create "App to Phone Tutorial" --capabilities=voice --keyfile=private.key --voice-event-url=https://example.com/ --voice-answer-url=GIST-URLNotieren Sie sich die Application ID die bei der Erstellung der Anwendung im Terminal ausgegeben wird.
HINWEIS: Eine versteckte Datei namens
.nexmo-appwird im Projektverzeichnis erstellt und enthält den neu erstelltenVonage Application IDund den privaten Schlüssel. Eine private Schlüsseldatei mit dem Namenprivate.keywird ebenfalls im aktuellen Ordner erstellt.
Benutzer erstellen
Jeder Teilnehmer wird durch einen Benutzer Objekt repräsentiert und muss durch das Client SDK. In einer Produktionsanwendung würden wir diese Benutzerinformationen normalerweise in einer Datenbank speichern.
Führen Sie den folgenden Befehl aus, um einen Benutzer namens Alice:
nexmo user:create name="Alice" JWT generieren
Die JWT wird zur Authentifizierung des Benutzers verwendet. Führen Sie den folgenden Befehl im Terminal aus, um eine JWT für den Benutzer Alice. Ersetzen Sie im folgenden Befehl die APPLICATION_ID durch die ID der Anwendung:
nexmo jwt:generate sub=Alice exp=$(($(date +%s)+86400)) acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}' application_id=APPLICATION_IDMit dem obigen Befehl wird der Ablauf der JWT auf einen Tag ab jetzt, was das Maximum ist.
Notieren Sie sich die JWT die wir für Alice.
HINWEIS: In einer Produktionsumgebung sollte die Anwendung einen Endpunkt bereitstellen, der für jede Client-Anfrage eine
JWTfür jede Client-Anfrage erzeugt.
Xcode installieren
AppStore öffnen und installieren Xcode.
Flatter-Einrichtung
Flutter SDK installieren
Herunterladen und installieren Flutter SDK.
Dieser Schritt variiert je nach MacOS, Win, und Linuxvariieren, aber im Allgemeinen läuft es auf das Herunterladen von Flutter SDK für ein bestimmtes Betriebssystem herunter, extrahiert die Flutter SDK Datei zu extrahieren und den sdk\bin Ordner zur System PATH Variable hinzuzufügen. Eine detaillierte Anleitung für alle Plattformen finden Sie hier.
Zum Glück, Flutter ein Werkzeug zur Verfügung, mit dem wir überprüfen können, ob SDK und alle erforderlichen "Komponenten" vorhanden und korrekt konfiguriert sind. Führen Sie diesen Befehl aus:
flutter doctorFlutter Doctor wird verifiziert, ob Flutter SDK installiert ist und andere Komponenten korrekt installiert und konfiguriert sind.
Flutter-Projekt erstellen
Wir erstellen ein Flutter Projekt mit Hilfe des Terminals:
flutter create app_to_phone_flutterDer obige Befehl erstellt app_to_phone_flutter Ordner, der das Flutter Projekt.
FlutterProjekt enthältiosOrdner, der dasiOSProjekt;androidOrdner, der dasAndroidProjekt enthält; undwebOrdner, der daswebProjekt.
Öffnen Sie die pubspec.yaml Datei, und fügen Sie permission_handler Abhängigkeit (direkt unter sdk: flutter):
dependencies:
flutter:
sdk: flutter
permission_handler: ^6.0.1+1Die Einrückung ist wichtig in
yamlDateien wichtig, stellen Sie also sicher, dasspermission_handlerauf der gleichen Einrückungsebene liegt wie derflutter:Element.
Führen Sie nun diesen Befehl aus (der Pfad ist das Stammverzeichnis des Flutter Projekts), um die oben genannte Abhängigkeit herunterzuladen:
flutter pub getDer obige Befehl erstellt auch Podfile in ios Unterordner. Öffnen Sie ios\Podfile unkommentiert platform Zeile und aktualisieren Sie die Plattformversion auf 11:
platform :ios, '11.0'Am Ende der gleichen Datei hinzufügen pod 'NexmoClient':
target 'Runner' do
use_frameworks!
use_modular_headers!
pod 'NexmoClient'Öffnen Sie app_to_phone_flutter/ios Ordner im Terminal und installieren Sie Pods:
pod installMit dem obigen Befehl werden alle erforderlichen Abhängigkeiten heruntergeladen, einschließlich Flutter, Berechtigungshandler, und Client SDK.
Öffnen Sie Runner.xcworkspace in Xcode und führen Sie die Anwendung aus, um zu überprüfen, ob die obige Einrichtung korrekt durchgeführt wurde.
Zwei-Wege-Flutter/iOS-Kommunikation
Derzeit, Client SDK ist nicht als Flutter Paket verfügbar, daher müssen wir das Android-eigenes Client SDK verwenden und die Kommunikation zwischen iOS und Flutter über Methoden-Kanal - auf diese Weise, Flutter werden Android-Methoden aufgerufen, iOS ruft Flutter Methoden.
Der Flutter-Code wird in der Datei lib/main.dart Datei gespeichert, während iOS nativer Code wird in der Datei ios/Runner/AppDelegate.swift Datei gespeichert wird.
Init Flutter Anwendung
Flutter Applications werden mit einer Programmiersprache namens Dart.
Öffnen Sie die Datei lib/main.dart Datei und ersetzen Sie den gesamten Inhalt durch den folgenden Code:
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
}Der obige Code enthält eine benutzerdefinierte CallWidget die für die Verwaltung des Anwendungsstatus (Protokollierung des Benutzers und Verwaltung des Anrufs) zuständig ist. Die SdkState enum repräsentiert mögliche Zustände von Vonage Client SDK. Dieses Enum wird zweimal definiert - einmal für Flutter mit Dart und eine für iOS Verwendung von Swift. Das Widget enthält die _updateView Methode, die das UI basierend auf dem SdkState Wert.
Führen Sie die Anwendung vom Xcode:

Die Schaltfläche Login as Alice Schaltfläche sollte angezeigt werden:

Anmeldebildschirm
Die Schaltfläche Login as Alice Schaltfläche ist deaktiviert, also fügen Sie jetzt onPressed Handler zu der ElevatedButton um die Anmeldung zu ermöglichen:
Widget _updateView() {
if (_sdkState == SdkState.LOGGED_OUT) {
return ElevatedButton(
onPressed: () { _loginUser(); },
child: Text("LOGIN AS ALICE")
);
}
}Aktualisieren Sie den Körper der _loginUser Methode, um mit dem nativen Code zu kommunizieren und den Benutzer anzumelden:
Future<void> _loginUser() async {
String token = "ALICE_TOKEN";
try {
await platformMethodChannel.invokeMethod('loginUser', <String, dynamic>{'token': token});
} on PlatformException catch (e) {
print(e);
}
}Ersetzen Sie die ALICE_TOKEN durch das JWT Token, das wir zuvor von Vonage CLI zur Authentifizierung des Benutzers Alice für den Zugriff auf die Konversation zu authentifizieren. Flutter ruft die loginUser Methode auf und übergibt die token als Argument übergeben. Die Methode loginUser Methode ist definiert in der MainActivity Klasse definiert (dazu kommen wir gleich noch). Um diese Methode von Flutter aufzurufen, müssen wir eine MethodChannel. hinzufügen. platformMethodChannel Feld am Anfang der _CallWidgetState Klasse:
hinzufügen platformMethodChannel Feld am Anfang von _CallWidgetState Klasse:
class _CallWidgetState extends State<CallWidget> {
SdkState _sdkState = SdkState.LOGGED_OUT;
static const platformMethodChannel = const MethodChannel('com.vonage');Die com.vonage steht für die eindeutige Kanal-ID, die wir auch dem nativen iOS Code (AppDelegate Klasse). Nun müssen wir diesen Methodenaufruf auf der nativen iOS Seite behandeln.
Öffnen Sie ios/Runner/AppDelegate Klasse und vonageChannel Eigenschaft, die den Verweis auf die FlutterMethodChannel:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var vonageChannel: FlutterMethodChannel?
...Um auf Methodenaufrufe zu warten, die von Flutter hinzufügen addFlutterChannelListener Methode innerhalb der AppDelegate Klasse (gleiche Ebene wie obige application Methode):
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)
}
})
}Die obige Methode "übersetzt" die Flutter Methodenaufrufe in Methoden, die in der AppDelegate Klasse (die loginUser für jetzt).
Und es fehlen die loginUser Methoden innerhalb derselben Klasse (wir werden den Körper bald füllen):
func loginUser(token: String) {
}Jetzt hinzufügen addFlutterChannelListener Methodenaufruf innerhalb der application Methode ein:
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
addFlutterChannelListener()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}Der Code ist vorhanden - nach dem Drücken des Login As Alice Schaltfläche ruft die Flutter-App die _loginUser Methode auf. Über den Flutter Plattformkanal ruft die Methode die loginUser Methode auf, die in der AppDelegate Klasse definiert ist.
Führen Sie die Anwendung von Xcode um sicherzustellen, dass sie kompiliert wird.
Bevor wir uns als Benutzer anmelden können, müssen wir die Initialisierung der Vonage SDK Client.
Client initialisieren
Öffnen Sie AppDelegate Klasse und fügen Sie den NexmoClient Import am Anfang der Datei hinzu:
import NexmoClientIn der gleichen Datei fügen Sie client Eigenschaft, die einen Verweis auf Vonage Client.
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var vonageChannel: FlutterMethodChannel?
let client = NXMClient.shared
...Jetzt hinzufügen initClient Methode hinzu, um den Client zu initialisieren:
func initClient() {
client.setDelegate(self)
}Zum Aufruf der initClient Methode von der bestehenden application Methode aufzurufen, müssen wir die initClient() Zeile hinzufügen, wie im folgenden Beispiel gezeigt:
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
initClient()
addFlutterChannelListener()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}Bevor wir eine Konversation zulassen, müssen wir wissen, dass der Benutzer korrekt angemeldet ist. In der AppDelegate Datei einen Delegaten hinzufügen, der auf Vonage Client SDK Änderungen des Verbindungsstatus:
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)
}
}
}Schließlich muss die notifyFlutter Methode zur gleichen Klasse hinzugefügt werden:
func client(_ client: NXMClient, didReceiveError error: Error) {
notifyFlutter(state: .error)
}
} Anmeldung des Benutzers
Ändern Sie loginUser Methodenkörper zum Aufruf login auf der Client-Instanz aufzurufen:
func loginUser(token: String) {
self.client.login(withAuthToken: token)
}Diese Methode ermöglicht es uns, den Benutzer (Alice) unter Verwendung der Client SDK auf die Konversation zuzugreifen.
Flutter über Client SDK Statusänderung benachrichtigen
Zur Mitteilung Flutter über alle Änderungen des Zustands in der Client SDKzu benachrichtigen, müssen wir ein enum hinzufügen, das die Zustände der Client SDK. Wir haben bereits das entsprechende SdkState Aufzählung in der main.dart Datei hinzugefügt. Fügen Sie die folgende SdkState enum, am Ende der Datei MainActivity.kt Datei:
enum SdkState: String {
case loggedOut = "LOGGED_OUT"
case loggedIn = "LOGGED_IN"
case wait = "WAIT"
case onCall = "ON_CALL"
case error = "ERROR"
}Um diese Zustände an Flutter (vom obigen Delegaten) zu senden, müssen wir die notifyFlutter Methode in der AppDelegate Klasse hinzufügen:
func notifyFlutter(state: SdkState) {
vonageChannel?.invokeMethod("updateState", arguments: state.rawValue)
}Beachten Sie, dass wir den Status in der Aufzählung speichern, ihn aber als String senden.
SDK-Status-Update durch Flutter abrufen
Zum Abrufen von Statusaktualisierungen in Flutter abzurufen, müssen wir auf Aktualisierungen des Methodenkanals warten. Öffnen Sie main.dart Datei und fügen Sie _CallWidgetState Konstruktor mit benutzerdefiniertem Handler:
_CallWidgetState() {
platformMethodChannel.setMethodCallHandler(methodCallHandler);
}Innerhalb der gleichen Klasse (_CallWidgetState) fügen Sie die Handler-Methode hinzu:
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');
}
}Diese Methoden empfangen das "Signal" von Android und wandeln es in ein Enum um. Aktualisieren Sie nun den Inhalt der _updateView Methode zur Unterstützung von SdkState.WAIT und SdkState.LOGGED_IN Zustände, wie im folgenden Beispiel gezeigt:
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")
);
}
}Während SdkState.WAIT wird der Fortschrittsbalken angezeigt. Nach erfolgreicher Anmeldung zeigt die Anwendung die MAKE PHONE CALL Schaltfläche.
Starten Sie die Anwendung und klicken Sie auf die Schaltfläche mit der Aufschrift LOGIN AS ALICE. Die Schaltfläche MAKE PHONE CALL Schaltfläche sollte erscheinen, die einen anderen Zustand der Flutter App basierend auf der SdkState enum`). Ein Beispiel hierfür ist im folgenden Bild zu sehen:

Anrufen
Jetzt müssen wir eine Funktion zum Telefonieren hinzufügen. Öffnen Sie die main.dart Datei und aktualisieren Sie den Körper der _makeCall Methode wie unten gezeigt:
Future<void> _makeCall() async {
try {
await platformMethodChannel
.invokeMethod('makeCall');
} on PlatformException catch (e) {
print(e);
}
}Die obige Methode kommuniziert mit iOS kommunizieren, also müssen wir den Code in der AppDelegate Klasse ebenfalls aktualisieren. Fügen Sie makeCall Klauseln zu der switch Anweisung innerhalb der addFlutterChannelListener Methode:
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)
}
})
}Fügen Sie nun in der gleichen Datei die Eigenschaft onGoingCall hinzu, die definiert, ob und wann ein Anruf läuft:
var onGoingCall: NXMCall?HINWEIS: Derzeit speichert die
Client SDKkeine laufende Aufrufreferenz, daher müssen wir sie in derAppDelegateKlasse speichern. Wir werden sie später zum Beenden des Anrufs verwenden.
Fügen Sie nun in der gleichen Klasse makeCall Methode:
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)
}
}Die obige Methode setzt den Status der Flutter App auf SdkState.WAIT und wartet auf die Client SDK Antwort (Fehler oder Erfolg). Jetzt müssen wir die Unterstützung für beide Zustände hinzufügen (SdkState.ON_CALL und SdkState.ERROR) innerhalb der main.dart Datei hinzufügen. Aktualisieren Sie den Körper der _updateView Methode, um das Gleiche wie unten zu zeigen:
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")
);
}
}Jede Zustandsänderung führt zu einer Änderung der Benutzeroberfläche. Bevor ein Anruf getätigt wird, benötigt die Anwendung bestimmte Berechtigungen für die Nutzung des Mikrofons. Im nächsten Schritt werden wir die Funktionalität in das Projekt aufnehmen, um diese Berechtigungen anzufordern.
Berechtigungen anfordern
Die Anwendung muss auf das Mikrofon zugreifen können, also müssen wir den Zugriff auf das Mikrofon anfordern (Permission.microphone für Flutter ).
Öffnen Sie ios/Runner/info.plist Datei und fügen Sie Privacy - Microphone Usage Description Schlüssel mit Make a call Wert:

Wir haben bereits den permission_handler Paket zum Flutter Projekt hinzugefügt. Jetzt müssen wir am Anfang der main.dart Datei müssen wir das permission_handler Paket importieren, wie im folgenden Beispiel gezeigt:
import 'package:permission_handler/permission_handler.dart';Um die Anfrage für bestimmte Berechtigungen auszulösen, müssen wir die requestPermissions() Methode innerhalb der _CallWidgetState Klasse innerhalb der main.dart Datei hinzufügen. Fügen Sie also diese neue Methode innerhalb der Klasse hinzu:
Future<void> requestPermissions() async {
await [ Permission.microphone ].request();
}Die obige Methode wird die Berechtigungen mit permission_handler.
Ändern Sie in derselben Klasse den Körper der Klasse _makeCall Klasse so, dass vor dem Aufruf der Methode über den Methodenkanal Berechtigungen angefordert werden:
Future<void> _makeCall() async {
try {
await requestPermissions();
...
}Starten Sie die App und klicken Sie auf MAKE PHONE CALL um einen Anruf zu starten. Der Berechtigungsdialog wird angezeigt, und nachdem Sie die Berechtigungen erteilt haben, wird der Anruf gestartet.
Zur Erinnerung: Wir haben die Rufnummer bereits in der
NCCO
Der Status der Anwendung wird aktualisiert auf SdkState.ON_CALL und die Benutzeroberfläche wird aktualisiert:

Anruf beenden
Um den Aufruf zu beenden, müssen wir die Methode in der nativen iOS Anwendung mit platformMethodChannel. Innerhalb der main.dart Datei aktualisieren wir den Körper der _endCall Methode:
Future<void> _endCall() async {
try {
await platformMethodChannel.invokeMethod('endCall');
} on PlatformException catch (e) {}
}Die obige Methode kommuniziert mit iOSkommunizieren, also müssen wir den Code in der AppDelegate Klasse ebenfalls aktualisieren. Fügen Sie endCall Klauseln zu der switch Anweisung innerhalb der addFlutterChannelListener Methode:
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)
}
})
}
Fügen Sie nun in der gleichen Klasse die endCall Methode hinzu:
func endCall() {
onGoingCall?.hangup()
onGoingCall = nil
notifyFlutter(state: .loggedIn)
}Die obige Methode setzt den Status der Flutter App auf SdkState.WAIT und wartet auf die Antwort von Client SDKdie entweder ein Fehler oder ein Erfolg sein kann. Beide UI-Zustände werden bereits in der Flutter Anwendung (_updateView Methode).
Wir haben das Beenden des Anrufs durch Drücken der END CALL Schaltfläche in der Flutter Anwendungs-UI. Der Anruf kann jedoch auch außerhalb der Anwendung beendet werden. Flutter App beendet werden, z. B. indem der Anruf abgewiesen oder angenommen und später vom Anrufer (auf dem echten Telefon) beendet wird.
Um diese Fälle zu unterstützen, müssen wir den NexmoCallEventListener Listener zur Anrufinstanz hinzufügen und auf anrufspezifische Ereignisse warten.
In der Datei AppDelegares.swift Datei hinzufügen 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)
}
}Um den obigen Hörer zu registrieren, ändern Sie onSuccess Callback innerhalb der makeCall Methode:
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)
}
}Führen Sie die App aus und rufen Sie von der mobilen Anwendung aus eine physische Telefonnummer an.
Zusammenfassung
Wir haben die Anwendung erfolgreich erstellt. Dabei haben wir gelernt, wie man einen Anruf von einer mobilen Anwendung auf das Telefon mit Vonage tätigt Client SDK. Das komplette Projekt finden Sie auf GitHub. Dieses Projekt enthält zusätzlich den nativen Android-Code (android Ordner), der es uns ermöglicht, die App auch auf Android laufen zu lassen.
Um sich mit anderen Funktionalitäten vertraut zu machen, lesen Sie bitte andere Tutorials und Vonage Entwicklerzentrum.