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

Creación de una llamada de aplicación a teléfono con Android y Flutter

Publicado el March 18, 2021

Tiempo de lectura: 12 minutos

Hoy vamos a crear una aplicación para Android utilizando Flutter y utilizaremos Vonage Client SDK para realizar una llamada desde una aplicación móvil al teléfono. La aplicación tendrá 3 pantallas (3 estados de UI):

UI states

Requisitos previos

El código fuente está disponible en GitHub.

Antes de empezar a crear la aplicación para nuestro dispositivo Android, tendrás que prepararte con los siguientes requisitos previos:

  • Crear un objeto de control de llamada (OCNC)

  • Instalar la CLI de Vonage

  • Configurar una aplicación de Vonage

  • Instalar el SDK de Flutter

  • Crear un proyecto Flutter

Aplicación de Vonage

Crear una OCN

Un objeto de control de llamada (NCCO) es una matriz JSON que utilizamos para controlar el flujo de una llamada Voice API. Puede encontrar más información sobre NCCO aquí.

La OCN tiene que ser pública y accesible por Internet. Para conseguirlo, en este tutorial utilizarás GitHub Gist que proporciona una forma conveniente de alojar la configuración. Vamos a añadir un nuevo gist:

  1. Ir a https://gist.github.com/ (tienes que haber iniciado sesión en Github)

  2. Crear un nuevo gist con ncco.json como nombre de archivo

  3. Copia y pega el siguiente objeto JSON en el gist:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "number": "PHONE_NUMBER"
            }
        ]
    }
]
  1. Sustituye PHONE_NUMBER por nuestro número de teléfono (los números de Vonage están en formato E.164 https://developer.nexmo.com/concepts/guides/glossary#e-164-formatlos signos '+' y '-' no son válidos. Asegúrese de especificar nuestro código de país al introducir nuestro número, por ejemplo, US: 14155550100 y UK: 447700900001)

  2. Haga clic en el botón Create secret gist botón

  3. Haga clic en el botón Raw botón

  4. Toma nota de la URL que aparece en nuestro navegador, la utilizaremos en el siguiente paso

Instalar Vonage CLI

El CLI de Vonage nos permite realizar muchas operaciones en la línea de comandos. Si queremos realizar tareas como crear aplicaciones, comprar números de Vonage, etc., necesitaremos instalar la CLI de Vonage.

Vonage CLI requiere node.jspor lo que necesitaremos instalar node.js primero usando estas instrucciones.

Para instalar la versión Beta del CLI con NPM ejecuta este comando:

npm install @vonage/cli -g

Configure la CLI de Vonage para utilizar la clave y el secreto de la API de Vonage. página de configuración en el panel.

Ejecuta el siguiente comando en un terminal, sustituyendo api_key y api_secret por los nuestros:

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

Configurar aplicación de Vonage

  1. Crear nuestro directorio de proyecto si aún no lo ha hecho, ejecute el siguiente comando en nuestro terminal:

mkdir vonage-tutorial

2. Cambie al directorio del proyecto:

cd vonage-tutorial

3. Crea una aplicación de Vonage copiando y pegando el siguiente comando en el terminal Asegúrate de cambiar el valor de --voice-answer-url sustituyendo GIST-URL por la URL gist del paso anterior.

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

Anote el ID de la aplicación que aparece en nuestro terminal cuando se crea nuestra aplicación.

NOTA: se crea un archivo llamado vonage_app.json en el directorio de nuestro proyecto y contiene el nuevo ID de aplicación de Vonage y la clave privada. También se crea un archivo de clave privada llamado app_to_phone_tutorial.key también se crea.

Crear usuario

Cada participante está representado por un Usuario y debe ser autenticado por el Client SDK. En una aplicación de producción, normalmente almacenaríamos esta información de usuario en una base de datos.

Ejecute el siguiente comando para crear un usuario llamado Alice

vonage apps:users:create Alice

Generar JWT

El JWT se utiliza para autenticar al usuario. Ejecute el siguiente comando en el terminal para generar un JWT para el usuario Alice.

En el siguiente comando sustituya el APPLICATION_ID por el ID de nuestra aplicación:

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/**": {}
    }
}'

El comando anterior establece la caducidad del JWT en un día a partir de ahora, que es el máximo.

Anote el JWT que generamos para Alice.

NOTA: En un entorno de producción, nuestra aplicación debe exponer un endpoint que genere un JWT para cada petición del cliente.

Instalar Android Studio

Descargar e instalar Android Studio.

Configuración de Flutter

Instalar el SDK de Flutter

Este paso variará en MacOS, Win y Linux, pero en general, se reduce a descargar el SDK de flutter para un sistema operativo determinado, extraer el archivo SDK y añadir la carpeta sdk\bin a la variable PATH del sistema. Encontrará instrucciones detalladas aquí.

Afortunadamente, flutter viene con una herramienta que nos permite verificar si el SDK y todos los "componentes" requeridos están presentes y configurados correctamente. Ejecute este comando:

flutter doctor

Flutter Doctor verificará si Flutter SDK está instalado y otros componentes están instalados y configurados correctamente. Si se detectan problemas, veremos la descripción y una sugerencia para solucionarlos.

Instalar el plugin Flutter

Abrir Android Studiovaya a Preferences | plugins e instala los plugins Flutter y Dart desde el marketplace.

El plugin Flutter añadirá una nueva barra de herramientas que permite ejecutar y depurar la aplicación Flutter:

flutter-plugin-ui

Crear el proyecto Flutter

Creará un proyecto Flutter utilizando Android Studio.

  • Ejecutar Android Studio

  • En la pantalla de bienvenida de Android Studio seleccione Create New Flutter project

create-new-flutter-project

  • Seleccione Flutter Application y haga clic en Next

  • Introduzca app_to_phone_flutter como nombre del proyecto, introduzca Flutter SDK path y haga clic en Next

  • Seleccione Include Kotlin support for Android code y haga clic en Finish

Tenga en cuenta que app_to_phone_flutter (proyecto flutter) contieneios que contiene el proyecto OS y ios que contiene el proyecto iOS.

Conecta el dispositivo Android o el emulador y ejecuta la aplicación para verificar que todo funciona como se espera.

Comunicación bidireccional Flutter/Android

Actualmente, Client SDK no está disponible como un paquete de Flutter, por lo que tendremos que utilizar Client SDK nativo de Android y comunicarnos entre Android y Flutter utilizando MethodChannel - de esta forma, Flutter llamará a los métodos de Android, y Android llamará a los métodos de Flutter.

El código de Flutter se almacenará en el archivo lib/ain.dart mientras que el código nativo de Android se almacenará en el archivo android/app/src/main/kotlin/com/example/app_to_phone_flutter/MainActivity.kt archivo.

Aplicación Init Flutter

Las Applications de Flutter se construyen utilizando un lenguaje de programación llamado Dart.

Abra el archivo lib/main.dart y sustituya todo el contenido por el siguiente código:

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
}

El código anterior contiene custom CallWidget que se encargará de gestionar el estado de la aplicación (registro del usuario y gestión de la llamada). El enum SdkState representa los posibles estados de Vonage Client SDK. Este enum será definido dos veces - uno para Flutter usando Dart y otro para Android usando Kotlin. El widget contiene el método _updateView que cambiará la interfaz de usuario en función del valor SdkState el valor.

Ejecute la aplicación con el botón de flecha verde de la barra de herramientas de Flutter:

Run the app

Deberíamos ver el botón Login Alice botón

An example of the screen when the user is logged out

Pantalla de inicio de sesión

El botón Login as Aice está desactivado, así que ahora añade onPressed al botón ElevatedButton para permitir el inicio de sesión:

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

Actualizar el cuerpo de _loginUser para comunicarse con el código nativo y acceder al usuario:

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

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

Sustituye el ALICE_TOKEN con el token JWT, que obtuvimos anteriormente, para autenticar al usuario Alice desde la CLI de Vonage. Flutter llamará al método loginUser y pasará el token como argumento. El método loginUser definido en la clase MainActivity (lo verás en un momento). Para llamar a este método desde Flutter tenemos que definir un método MethodChannel. Añade el campo platformMethodChannel en la parte superior de _CallWidgetState la clase:

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

La cadena com.vonage string representa el identificador único del canal que también referenciaremos en el código nativo de Android (MainActivity class). Ahora tenemos que manejar esta llamada de método en el lado nativo de Android.

Abra MainActivity clase. Tenga en cuenta que el plugin Flutter muestra una sugerencia para abrir este proyecto Android en una instancia separada de Android Studio (otra ventana). Hágalo para tener una mejor finalización de código para el proyecto Android:

Open In Android Studio

NOTA: Esto ocurre porque el proyecto Flutter está formado por el proyecto Android y el proyecto iOS.

Para escuchar las llamadas a métodos originadas en Flutter sobreescribe configureFlutterEngine y añadir addFlutterChannelListener llamada de método dentro de configureFlutterEngine método:

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

        addFlutterChannelListener()
    }

Ahora añade addFlutterChannelListener y loginUser dentro de la clase MainActivity (al mismo nivel que el método configureFlutterEngine anterior):

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")
}

Después de ejecutar la aplicación deberíamos ver login with token... en Android Logcat. Ahora es el momento de crear un client.

Añadir dependencia de Client SDK

Añade un repositorio Maven URL personalizado a nuestra configuración de Gradle. Añade el siguiente bloque maven dentro del bloque allprojects dentro del archivo build.gradle.kts del proyecto:

allprojects {
    repositories {
        google()
        jcenter()

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

Ahora añada la dependencia Client SDK al proyecto en el archivo app\build.gradle archivo:

dependencies {
    // ...

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

En el mismo archivo establece min versión de Android SDK a 23:

minSdkVersion 23

Ejecute el comando Sync project with Gradle en Android Studio, como se muestra en el siguiente ejemplo:

Sync project with Gradle

Inicializar cliente

Abra la clase MainActivity y añada la propiedad client que contendrá la referencia al cliente Nexmo:

private lateinit var client: NexmoClient

Ahora añade el método initClient para inicializar el cliente:

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

Para llamar al método initClient desde el método configureFlutterEngine existente, tendremos que añadir la línea initClient() como se muestra en el siguiente ejemplo:

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

    initClient()
    addFlutterChannelListener()
}

Iniciar sesión El usuario

Modificar login el cuerpo del método para llamar login en la instancia del cliente:

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

Esto nos permitirá registrar al usuario (Alice) utilizando Client SDK.

Notificación a Flutter del cambio de estado del Client SDK

Para notificar a Flutter cualquier cambio en el estado del SDK, tendrás que añadir enum para representar los estados del Client SDK. Ya has añadido el equivalente SdkState enum en el archivo main.dart archivo). Añade el siguienteSdkState enum, al final del MainActivity.kt archivo:

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

A continuación, tenemos que añadir el listener de conexión y mapear algunos de los estados del SDK a SdkState enum. Modifica el cuerpo del método initClient como se muestra en el siguiente ejemplo:

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)
            }
        }
    }

Por último, el método notifyFlutter a la clase MainActivity clase:

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

Observa que almacenamos el estado en el enum, pero lo estamos enviando como una cadena. La comunicación con Flutter se produce en el main por lo que necesitamos usar Handler para cambiar de hilo. El MethodChannel llamará al método updateState definido en el archivo main.dart archivo.

Recuperar el estado del SDK por Flutter

Para recuperar las actualizaciones de estado en Flutter tenemos que escuchar las actualizaciones del canal de métodos. Abra el archivo main.dart y añade estos dos métodos dentro de _CallWidgetState de la clase:

_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');
    }
  }

Estos métodos reciben la "señal" de Android y la convierte en un enum. Ahora actualiza el contenido del método _updateView para que admita SdkState.WAIT y SdkState.LOGGED_IN states, como se muestra en el siguiente ejemplo:

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")
      );
    }
  }

Durante SdkState.WAIT se mostrará la barra de progreso. Después de iniciar sesión con éxito, la aplicación mostrará el botón MAKE PHONE CALL botón .

NOTA: Al modificar el código nativo de Android Flutter hot reload no funcionará. tenemos que detener la aplicación y ejecutarla de nuevo.

Ejecute la aplicación y haga clic en el botón LOGIN AS ALICE. Debería aparecer el botón MAKE PHONE CALL que es otro estado de la aplicación Flutter basado en la función SdkState enum`). En la siguiente imagen se muestra un ejemplo:

Make a phone call

Hacer una llamada

Ahora tenemos que añadir la funcionalidad para hacer una llamada telefónica. Abre el archivo main.dart y actualiza el cuerpo del método _makeCall como se muestra a continuación:

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

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

El método anterior se comunicará con Android por lo que tenemos que actualizar el código en MainActivity también. Añadir makeCall a la sentencia when dentro del método addFlutterChannelListener del método:

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()
                }
            }
        }
    }

Ahora, en el mismo archivo, añada la propiedad onGoingCall que define si una llamada está en curso y cuándo:

private var onGoingCall: NexmoCall? = null

NOTA: Actualmente el Client SDK no almacena la referencia de la llamada en curso, por lo que tenemos que almacenarla en la clase MainActivity que utilizaremos más adelante para finalizar la llamada.

Ahora en el mismo archivo añade makeCall método:

@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)
            }
        })
    }

El método anterior establece el estado de la aplicación Flutter en SdkState.WAIT y espera la respuesta del Client SDK (error o éxito). Ahora tenemos que añadir soporte para ambos estados (SdkState.ON_CALL y SdkState.ERROR) dentro del archivo main.dart (Flutter). Actualizar el cuerpo del método _updateView para que muestre lo mismo que a continuación:

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")
      );
    }
  }

Cada cambio de estado dará lugar a una modificación de la interfaz de usuario. Antes de realizar una llamada, la aplicación necesita permisos específicos para utilizar el micrófono. En el siguiente paso, vamos a añadir la funcionalidad en nuestro proyecto para solicitar estos permisos.

Solicitar permisos

La aplicación necesita poder acceder al micrófono, por lo que tenemos que solicitar el permiso de Android android.permission.RECORD_AUDIO (Flutter lo llama Permission.microphone).

En primer lugar, tenemos que añadir el permission_handler paquete. Abra el archivo pubspec.yaml y añade la dependencia permission_handler: ^6.0.1+1 dependencia bajo sdk: flutter:

dependencies:
  flutter:
    sdk: flutter

  permission_handler: ^6.0.1+1

La sangría es importante en los archivos yaml así que asegúrese de que permission_handler esté en el mismo nivel de sangría que el elemento flutter: elemento.

Ejecute el siguiente comando en el terminal para descargar el paquete Flutter recién añadido:

flutter pub get

En la parte superior del archivo main.dart deberá importar el paquete permission_handler como se muestra en el siguiente ejemplo:

import 'package:permission_handler/permission_handler.dart';

Para activar la solicitud de determinados permisos, tendrá que añadir el método requestPermissions() dentro de la clase _CallWidgetState dentro del archivo main.dart archivo. Así que añade este nuevo método dentro de la clase:

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

Por último, tenemos que añadir dos permisos (uses-permission tags) dentro del archivo app/src/main/AndroidManifest.xml encima de la etiqueta application tag:

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

<application
...

NOTA: android.permission.INTERNET el permiso lo concede implícitamente Android, por lo que no tenemos que solicitarlo en Flutter explícitamente.

Ejecute la aplicación y pulse MAKE PHONE CALL para iniciar una llamada. Aparecerá el cuadro de diálogo de permisos y, una vez concedidos, se iniciará la llamada.

Resto: hemos definido el número de teléfono anteriormente en NCCO

El estado de la aplicación se actualizará a SdkState.ON_CALL y se actualizará la interfaz de usuario:

On call UI

Finalizar la llamada

Para finalizar la llamada necesitamos lanzar el método en la aplicación nativa de Android usando platformMethodChannel. Dentro de main.dart cuerpo de actualización del _endCall del método:

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

El método anterior se comunicará con Android por lo que tenemos que actualizar el código en la clase MainActivity clase. Añadir endCall a la sentencia when dentro del método addFlutterChannelListener método:

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()
                }
            }

Ahora en el mismo archivo añade el endCall método:

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)
            }
        })
    }

El método anterior establece el estado de la aplicación Flutter en SdkState.WAIT y espera la respuesta del Client SDK, que puede ser de error o de éxito. Ambos estados de UI ya están soportados en la aplicación Flutter.

Se ha gestionado la finalización de la llamada pulsando el botón END CALL en la interfaz de usuario de la aplicación Flutter; sin embargo, la llamada también puede finalizar fuera de la aplicación Flutter, por ejemplo, la llamada será rechazada o contestada y posteriormente finalizada por el receptor de la llamada (en el teléfono real).

Para soportar estos casos tenemos que añadir NexmoCallEventListener a la instancia de llamada y escuchar los eventos específicos de la llamada.

Defina la propiedad callEventListener en la parte superior de la clase MainActivity clase:

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) {}
    }

La dirección onMemberStatusUpdated callback nos informa de que la llamada ha finalizado.

Para registrar el listener anterior modifique onSuccess callback dentro de makeCall del método:

onGoingCall = call
onGoingCall?.addCallEventListener(callEventListener)

Por último, modifique el método endCall para anular el registro del callEventListener listener dentro de onSuccess callback:

onGoingCall?.removeCallEventListener(callEventListener)
onGoingCall = null

Ejecute la aplicación y, si ha seguido este tutorial paso a paso, podrá realizar una llamada telefónica desde nuestra aplicación móvil a un número de teléfono físico.

Resumen

Has creado la aplicación con éxito. Al hacerlo, hemos aprendido a realizar una llamada telefónica desde una aplicación móvil al teléfono usando Vonage Client SDK. Para ver la versión completa, consulta este proyecto en GitHub.

Para familiarizarse con otros casos de uso, consulte otros tutoriales y Centro para desarrolladores de Vonage.

Referencias

Compartir:

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