https://d226lax1qjow5r.cloudfront.net/blog/blogposts/building-an-app-to-phone-call-using-android-and-flutter/flutter_inapp-call_1200x600.png

Aufbau eines App-To-Phone-Anrufs mit Android und Flutter

Zuletzt aktualisiert am March 18, 2021

Lesedauer: 11 Minuten

Heute werden wir eine Android-Anwendung mit Flutter erstellen und das Vonage Client SDK verwenden, um einen Anruf von einer mobilen Anwendung zum Telefon zu tätigen. Die Anwendung wird 3 Bildschirme (3 UI-Status) haben:

UI states

Voraussetzungen

Der Quellcode ist verfügbar auf GitHub.

Bevor wir mit der Erstellung der Anwendung für unser Android-Gerät beginnen, müssen Sie die folgenden Voraussetzungen erfüllen:

  • Erstellen Sie ein Call Control Object (NCCO)

  • Installieren Sie die Vonage CLI

  • Einrichten einer Vonage-Anwendung

  • Installieren Sie das Flutter SDK

  • Ein Flutter-Projekt erstellen

Vonage-Anwendung

Ein NCCO erstellen

Ein Call Control Object (NCCO) ist ein JSON-Array, das wir zur Steuerung des Ablaufs eines Voice API-Aufrufs verwenden. Weitere Informationen zu NCCO finden Sie hier hier.

Das NCCO muss öffentlich und über das Internet zugänglich sein. Um dies zu erreichen, werden Sie in diesem Tutorium Folgendes verwenden GitHub Gist das eine bequeme Möglichkeit bietet, die Konfiguration zu hosten. Fügen wir einen neuen Gist hinzu:

  1. Besuchen Sie https://gist.github.com/ (Sie müssen bei Github eingeloggt sein)

  2. Erstellen Sie einen neuen Gist mit ncco.json dem als Dateinamen

  3. Kopieren Sie das folgende JSON-Objekt und fügen Sie es in die Gist ein:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "number": "PHONE_NUMBER"
            }
        ]
    }
]
  1. Ersetzen Sie PHONE_NUMBER durch unsere Telefonnummer (Vonage Numbers sind im E.164-Format https://developer.nexmo.com/concepts/guides/glossary#e-164-format'+' und '-' sind nicht gültig. Vergewissern Sie sich, dass wir bei der Eingabe unserer Numbers unsere Landesvorwahl angeben, z. B. US: 14155550100 und UK: 447700900001)

  2. Klicken Sie auf die Create secret gist Schaltfläche

  3. Klicken Sie auf die Raw Schaltfläche

  4. Notieren Sie sich die in unserem 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 die Erstellung von Applications, den Kauf von Vonage Numbers usw. durchführen wollen, müssen wir die Vonage CLI installieren.

Vonage CLI erfordert node.jsalso müssen wir zuerst node.js installieren, indem wir diese Anweisungen.

Um die Beta-Version der CLI mit NPM zu installieren, führen Sie diesen Befehl aus:

npm install @vonage/cli -g

Richten Sie die Vonage CLI so ein, dass sie unseren Vonage API-Schlüssel und unser API-Geheimnis verwendet. Seite Einstellungen im Dashboard.

Führen Sie den folgenden Befehl in einem Terminal aus und ersetzen Sie dabei api_key und api_secret durch unsere eigenen:

vonage config:set --apiKey=api_key --apiSecret=api_secret

Vonage-Anwendung einrichten

  1. Erstellen Sie unser Projektverzeichnis, falls Sie dies noch nicht getan haben, und führen Sie den folgenden Befehl im Terminal aus:

mkdir vonage-tutorial

2. Wechseln Sie in das Projektverzeichnis:

cd vonage-tutorial

3. Erstellen Sie eine Vonage-Anwendung, indem Sie den folgenden Befehl kopieren und in das Terminal einfügen Ändern Sie den Wert von --voice-answer-url Argument durch Ersetzen von GIST-URL durch die Gist-URL aus dem vorherigen Schritt ersetzen.

vonage apps:create "App to Phone Tutorial" --voice_event_url=https://example.com/ --voice_answer_url=GIST-URL

Notieren Sie sich die Anwendungs-ID, die bei der Erstellung unserer Anwendung in unserem Terminal ausgegeben wird.

HINWEIS: Eine Datei namens vonage_app.json wird in unserem Projektverzeichnis erstellt und enthält die neu erstellte Vonage-Anwendungs-ID und den privaten Schlüssel. Eine private Schlüsseldatei namens app_to_phone_tutorial.key wird ebenfalls erstellt.

Benutzer erstellen

Jeder Teilnehmer wird durch einen Benutzer Objekt repräsentiert und muss durch das Client SDK authentifiziert werden. 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

vonage apps:users:create Alice

JWT generieren

Das JWT wird zur Authentifizierung des Benutzers verwendet. Führen Sie den folgenden Befehl im Terminal aus, um ein JWT für den Benutzer zu erzeugen Alice.

Ersetzen Sie in dem folgenden Befehl die APPLICATION_ID durch die ID unserer Anwendung:

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

Mit dem obigen Befehl wird der Ablauf des JWT auf einen Tag ab jetzt festgelegt, was das Maximum darstellt.

Notieren Sie sich das JWT, das wir für Alice.

HINWEIS: In einer Produktionsumgebung sollte unsere Anwendung einen Endpunkt bereitstellen, der für jede Client-Anfrage ein JWT erzeugt.

Android Studio installieren

Herunterladen und installieren Android-Studio.

Flatter-Einrichtung

Flutter SDK installieren

Dieser Schritt variiert unter MacOS, Win und Linux, aber im Allgemeinen läuft es darauf hinaus, das Flutter-SDK für ein bestimmtes Betriebssystem herunterzuladen, die SDK-Datei zu extrahieren und den sdk\bin Ordner zur System-PATH-Variable hinzuzufügen. Eine detaillierte Anleitung finden Sie hier.

Glücklicherweise verfügt Flutter über ein Tool, mit dem wir überprüfen können, ob das SDK und alle erforderlichen "Komponenten" vorhanden und korrekt konfiguriert sind. Führen Sie diesen Befehl aus:

flutter doctor

Flutter Doctor verifiziert, ob das Flutter SDK installiert ist und andere Komponenten korrekt installiert und konfiguriert sind. Wenn Probleme erkannt werden, werden wir die Beschreibung und den Hinweis zur Behebung sehen.

Installieren Sie das Flutter-Plugin

Öffnen Sie Android-Studio, gehen Sie zu Preferences | plugins und installieren Sie Flutter- und Dart-Plugins vom Marktplatz.

Das Flutter-Plugin fügt eine neue Symbolleiste hinzu, die das Ausführen und Debuggen von Flutter-Anwendungen ermöglicht:

flutter-plugin-ui

Erstellen Sie das Flutter-Projekt

Sie werden ein Flutter-Projekt mit Android Studio erstellen.

  • Android Studio ausführen

  • Wählen Sie auf dem Begrüßungsbildschirm von Android Studio Create New Flutter project

create-new-flutter-project

  • Wählen Sie Flutter Application und klicken Sie Next

  • Geben Sie app_to_phone_flutter als Projektnamen ein, geben Sie Flutter SDK path ein und klicken Next

  • Wählen Sie Include Kotlin support for Android code und klicken Sie Finish

Beachten Sie, dass app_to_phone_flutter Ordner (Flutter-Projekt) enthältios den Ordner mit dem OS-Projekt und ios den Ordner mit dem iOS-Projekt enthält.

Schließen Sie das Android-Gerät oder den Emulator an und führen Sie die App aus, um zu überprüfen, ob alles wie erwartet funktioniert.

Zwei-Wege-Kommunikation Flutter/Android

Derzeit ist das Client SDK nicht als Flutter-Paket verfügbar, so dass wir Folgendes verwenden müssen Android-eigenes Client SDK verwenden und die Kommunikation zwischen Android und Flutter über Methoden-Kanal - auf diese Weise wird Flutter Android-Methoden aufrufen, Android wird Flutter-Methoden aufrufen.

Der Flutter-Code wird in der Datei lib/ain.dart Datei gespeichert, während der native Android-Code in der android/app/src/main/kotlin/com/example/app_to_phone_flutter/MainActivity.kt 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 einmal für Android mit Kotlin. Das Widget enthält die _updateView Methode, die das UI basierend auf dem SdkState Wert.

Starten Sie die Anwendung über die grüne Pfeilschaltfläche in der Flutter-Symbolleiste:

Run the app

Wir sollten die Login Alice Schaltfläche:

An example of the screen when the user is logged out

Anmeldebildschirm

Die Schaltfläche Login as Aice 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 erhalten haben, um den Benutzer zu authentifizieren Alice von Vonage CLI zu authentifizieren. Flutter wird die loginUser Methode auf und übergibt den token als Argument übergeben. Die loginUser Methode ist definiert in der MainActivity Klasse definiert ist (dazu kommen Sie gleich). Um diese Methode von Flutter aus aufzurufen, müssen wir eine MethodChannel. Fügen Sie das platformMethodChannel Feld am Anfang der _CallWidgetState Klasse:

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

Die com.vonage String steht für die eindeutige Kanal-ID, die wir auch im nativen Android-Code (MainActivity Klasse). Nun müssen wir diesen Methodenaufruf auf der nativen Android-Seite behandeln.

Öffnen Sie MainActivity Klasse. Beachten Sie, dass das Flutter-Plugin einen Hinweis anzeigt, dieses Android-Projekt in einer separaten Instanz von Android Studio (einem anderen Fenster) zu öffnen. Tun Sie dies, um eine bessere Code-Vervollständigung für das Android-Projekt zu erhalten:

Open In Android Studio

HINWEIS: Dies geschieht, weil das Flutter-Projekt aus dem Android-Projekt und dem iOS-Projekt besteht.

Um auf Methodenaufrufe zu lauschen, die von Flutter overide stammen configureFlutterEngine und fügen Sie addFlutterChannelListener Methodenaufruf innerhalb von configureFlutterEngine Methode:

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        addFlutterChannelListener()
    }

Nun fügen Sie addFlutterChannelListener und loginUser Methoden innerhalb der MainActivity Klasse (gleiche Ebene wie die obige configureFlutterEngine Methode):

private fun addFlutterChannelListener() {
        MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->

            when (call.method) {
                "loginUser" -> {
                    val token = requireNotNull(call.argument<String>("token"))
                    loginUser(token)
                    result.success("")
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    }

private fun loginUser(token: String) {
        Log.d("TAG", "login with token: $token")
}

Nach dem Ausführen der Anwendung sollten wir eine login with token... Meldung im Android Logcat sehen. Jetzt ist es an der Zeit, eine fehlende client.

Client SDK-Abhängigkeit hinzufügen

Fügen Sie ein benutzerdefiniertes Maven-URL-Repository zu unserer Gradle-Konfiguration hinzu. Fügen Sie den folgenden Maven-Block innerhalb des allprojects Blocks innerhalb der Projekt-Level build.gradle.kts Datei:

allprojects {
    repositories {
        google()
        jcenter()

        maven {
            url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local"
        }
    }
}

Fügen Sie nun die Client SDK-Abhängigkeit zum Projekt in der app\build.gradle Datei hinzu:

dependencies {
    // ...

    implementation 'com.nexmo.android:client-sdk:2.8.1'
}

In der gleichen Datei setzen Sie min Android SDK Version auf 23:

minSdkVersion 23

Führen Sie Sync project with Gradle Befehl in Android Studio, wie im folgenden Beispiel gezeigt:

Sync project with Gradle

Client initialisieren

Öffnen Sie MainActivity Klasse und fügen Sie die client Eigenschaft hinzu, die den Verweis auf den Nexmo-Client enthält:

private lateinit var client: NexmoClient

Jetzt hinzufügen initClient Methode hinzu, um den Client zu initialisieren:

private fun initClient() {
        client = NexmoClient.Builder().build(this)
    }

Zum Aufruf der initClient Methode von der bestehenden Methode configureFlutterEngine Methode aufzurufen, müssen wir die initClient() Zeile hinzufügen, wie im folgenden Beispiel gezeigt:

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
     super.configureFlutterEngine(flutterEngine)

    initClient()
    addFlutterChannelListener()
}

Anmeldung Der Benutzer

Ändern Sie login Methodenkörper zum Aufruf login auf der Client-Instanz aufzurufen:

private fun login(token: String) {
    client.login(token)
}

Dies ermöglicht uns, den Benutzer (Alice) mit Client SDK anzumelden.

Flutter über Client SDK Statusänderung benachrichtigen

Um Flutter über Änderungen am Zustand des SDKs zu informieren, müssen Sie enum hinzufügen, um die Zustände des Client SDK darzustellen. Sie haben bereits das entsprechende SdkState Enum in der main.dart Datei). Fügen Sie die folgendeSdkState enum, am Ende der Datei MainActivity.kt Datei:

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

Als nächstes müssen wir den Verbindungs-Listener hinzufügen und einige der SDK-Zustände auf SdkState enum. Ändern Sie den Körper der initClient Methode wie im folgenden Beispiel gezeigt:

private fun initClient() {
        client = NexmoClient.Builder().build(this)

        client.setConnectionListener { connectionStatus, _ ->
            when (connectionStatus) {
                ConnectionStatus.CONNECTED -> notifyFlutter(SdkState.LOGGED_IN)
                ConnectionStatus.DISCONNECTED -> notifyFlutter(SdkState.LOGGED_OUT)
                ConnectionStatus.CONNECTING -> notifyFlutter(SdkState.WAIT)
                ConnectionStatus.UNKNOWN -> notifyFlutter(SdkState.ERROR)
            }
        }
    }

Schließlich muss die notifyFlutter Methode in die MainActivity Klasse hinzugefügt werden:

private fun notifyFlutter(state: SdkState) {
        Handler(Looper.getMainLooper()).post {
            MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, "com.vonage")
                .invokeMethod("updateState", state.toString())
        }
    }

Beachten Sie, dass wir den Zustand im Enum speichern, ihn aber als String senden. Die Kommunikation mit Flutter findet auf dem main Thread, also müssen wir mit Handler verwenden, um den Thread zu wechseln. Die MethodChannel ruft die updateState Methode auf, die in der main.dart Datei definiert ist.

SDK-Status von Flutter abrufen

Um Statusaktualisierungen in Flutter abzurufen, müssen wir auf Aktualisierungen des Methodenkanals hören. Öffnen Sie main.dart Datei und fügen Sie diese beiden Methoden hinzu _CallWidgetState Klasse:

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

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.

HINWEIS: Beim Ändern von nativem Android-Code funktioniert Flutter Hot Reload nicht. Wir müssen die Anwendung anhalten und erneut ausführen.

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 dem SdkState enum`). Ein Beispiel hierfür ist im folgenden Bild zu sehen:

Make a phone call

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 requestPermissions();

      await platformMethodChannel
          .invokeMethod('makeCall');
    } on PlatformException catch (e) {
      print(e);
    }
  }

Die obige Methode wird mit Android kommunizieren, also müssen wir den Code in der MainActivity Klasse ebenfalls aktualisieren. Fügen Sie makeCall Klauseln zu when Anweisung innerhalb der addFlutterChannelListener Methode:

private fun addFlutterChannelListener() {
        MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, "com.vonage").setMethodCallHandler { call, result ->

            when (call.method) {
                "loginUser" -> {
                    val token = requireNotNull(call.argument<String>("token"))
                    login(token)
                    result.success("")
                }
                "makeCall" -> {
                    makeCall()
                    result.success("")
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    }

Fügen Sie nun in der gleichen Datei die Eigenschaft onGoingCall hinzu, die definiert, ob und wann ein Anruf läuft:

private var onGoingCall: NexmoCall? = null

HINWEIS: Derzeit speichert das Client SDK keine Referenz auf laufende Anrufe, daher müssen wir sie in der MainActivity Klasse speichern. Wir werden sie später verwenden, um den Anruf zu beenden.

Fügen Sie nun in der gleichen Datei makeCall Methode:

@SuppressLint("MissingPermission")
    private fun makeCall() {
        notifyFlutter(SdkState.WAIT)

        // Callee number is ignored because it is specified in NCCO config
        client.call("IGNORED_NUMBER", NexmoCallHandler.SERVER, object : NexmoRequestListener<NexmoCall> {
            override fun onSuccess(call: NexmoCall?) {
                onGoingCall = call
                notifyFlutter(SdkState.ON_CALL)
            }

            override fun onError(apiError: NexmoApiError) {
                notifyFlutter(SdkState.ERROR)
            }
        })
    }

Die obige Methode setzt den Status der Flutter-App auf SdkState.WAIT und wartet auf die Antwort des Client SDK (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 (Flutter) hinzufügen. Aktualisieren Sie den Körper der _updateView Methode, um das Gleiche wie unten darzustellen:

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 werden kann, benötigt die Anwendung bestimmte Berechtigungen zur Nutzung des Mikrofons. Im nächsten Schritt werden wir in unserem Projekt die Funktionalität hinzufügen, um diese Berechtigungen anzufordern.

Berechtigungen anfordern

Die Anwendung muss in der Lage sein, auf das Mikrofon zuzugreifen, also müssen wir die Erlaubnis von Android android.permission.RECORD_AUDIO Erlaubnis anfordern (Flutter nennt es Permission.microphone).

Zuerst müssen wir die permission_handler Paket hinzufügen. Öffnen Sie pubspec.yaml Datei und fügen Sie permission_handler: ^6.0.1+1 Abhängigkeit unter sdk: flutter:

dependencies:
  flutter:
    sdk: flutter

  permission_handler: ^6.0.1+1

Die Einrückung ist wichtig in yaml Dateien wichtig, stellen Sie also sicher, dass permission_handler auf der gleichen Einrückungsebene liegt wie der flutter: Element.

Führen Sie den folgenden Befehl im Terminal aus, um das neu hinzugefügte Flutter-Paket herunterzuladen:

flutter pub get

Am Anfang der Datei main.dart Datei, müssen Sie 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 Sie 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();
  }

Schließlich müssen wir noch zwei Berechtigungen (uses-permission Tags) innerhalb der app/src/main/AndroidManifest.xml Datei, oberhalb des application Tag:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<application
...

HINWEIS: android.permission.INTERNET Die Erlaubnis wird implizit von Android erteilt, so dass wir sie in Flutter nicht explizit anfordern müssen.

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.

Rest: wir haben die Telefonnummer bereits in NCCO definiert

Der Status der Anwendung wird aktualisiert auf SdkState.ON_CALL und die Benutzeroberfläche wird aktualisiert:

On call UI

Beenden Sie den Anruf

Um den Aufruf zu beenden, müssen wir die Methode in der nativen Android-Anwendung auslösen, indem wir platformMethodChannel. Innerhalb von main.dart der Datei update body der _endCall Methode:

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

Die obige Methode wird mit Android kommunizieren, also müssen wir den Code in der MainActivity Klasse. Fügen Sie endCall Klauseln zur when Anweisung innerhalb der addFlutterChannelListener Methode:

when (call.method) {
                "loginUser" -> {
                    val token = requireNotNull(call.argument<String>("token"))
                    login(token)
                    result.success("")
                }
                "makeCall" -> {
                    makeCall()
                    result.success("")
                }
                "endCall" -> {
                    endCall()
                    result.success("")
                }
                else -> {
                    result.notImplemented()
                }
            }

Fügen Sie nun in der gleichen Datei die endCall Methode:

private fun endCall() {
        onGoingCall?.hangup(object : NexmoRequestListener<NexmoCall> {
            override fun onSuccess(call: NexmoCall?) {
                onGoingCall = null
                notifyFlutter(SdkState.LOGGED_IN)
            }

            override fun onError(apiError: NexmoApiError) {
                notifyFlutter(SdkState.ERROR)
            }
        })
    }

Die obige Methode setzt den Status der Flutter-App auf SdkState.WAIT und wartet auf die Antwort des Client SDK, die entweder ein Fehler oder ein Erfolg sein kann. Beide Zustände der Benutzeroberfläche werden bereits in der Flutter-Anwendung unterstützt.

Sie haben das Beenden des Anrufs durch Drücken der END CALL Button in der Flutter-Anwendung beendet, jedoch kann der Anruf auch außerhalb der Flutter-Anwendung beendet werden, z.B. wird der Anruf abgewiesen oder angenommen und später vom Anrufer (auf dem echten Telefon) beendet.

Um diese Fälle zu unterstützen, müssen wir einen NexmoCallEventListener Listener zur Anrufinstanz hinzufügen und auf anrufspezifische Ereignisse warten.

Definieren Sie die callEventListener Eigenschaft am Anfang der MainActivity Klasse:

private val callEventListener = object : NexmoCallEventListener {
        override fun onMemberStatusUpdated(callMemberStatus: NexmoCallMemberStatus, callMember: NexmoCallMember) {
            if (callMemberStatus == NexmoCallMemberStatus.COMPLETED || callMemberStatus == NexmoCallMemberStatus.CANCELLED) {
                onGoingCall = null
            }
        }

        override fun onMuteChanged(mediaActionState: NexmoMediaActionState, callMember: NexmoCallMember) {}

        override fun onEarmuffChanged(mediaActionState: NexmoMediaActionState, callMember: NexmoCallMember) {}

        override fun onDTMF(dtmf: String, callMember: NexmoCallMember) {}
    }

Der onMemberStatusUpdated Rückruf informiert uns, dass der Anruf beendet ist.

Um den obigen Hörer zu registrieren, ändern Sie onSuccess Callback innerhalb der makeCall Methode:

onGoingCall = call
onGoingCall?.addCallEventListener(callEventListener)

Schließlich ändern Sie endCall Methode, um die Registrierung des callEventListener Hörer innerhalb von onSuccess Rückruf:

onGoingCall?.removeCallEventListener(callEventListener)
onGoingCall = null

Führen Sie die App aus, und wenn Sie diese Anleitung Schritt für Schritt befolgt haben, können Sie von unserer mobilen Anwendung aus einen Anruf an eine physische Telefonnummer tätigen.

Zusammenfassung

Sie haben die Anwendung erfolgreich erstellt. Damit haben wir gelernt, wie man mit dem Vonage Client SDK einen Anruf aus einer mobilen Anwendung auf das Telefon tätigt. Die vollständige Version finden Sie in diesem Projekt auf GitHub.

Um sich mit anderen Anwendungsfällen vertraut zu machen, lesen Sie bitte andere Tutorials und Vonage Entwicklerzentrum.

Referenzen

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/8ae5af43bb/igor-wojda.png
Igor WojdaVonage Ehemalige