
Hacer llamadas de aplicación a teléfono con iOS y Flutter
Tiempo de lectura: 11 minutos
Hoy crearemos una iOS aplicación con Flutter y utilizaremos Vonage Client SDK para realizar una llamada desde una aplicación móvil al teléfono utilizando la Conversation API de Vonage. La aplicación tendrá 3 pantallas (3 estados de interfaz de usuario):

Requisitos previos
El código fuente de nuestra Flutter iOS está disponible en GitHub.
Antes de empezar a crear la Flutter aplicación para el iOS dispositivo, tendremos que prepararnos con los siguientes requisitos previos:
Crear un objeto de control de llamada (OCNC)
Instale el
Vonage CLI(anteriormenteNexmo CLI)Configurar el
Vonage applicationInstale el
Flutter SDKCrear el
Flutterproyecto
Aplicación de Vonage
Crear una OCN
A bjeto de control de llamada (OCN) es un JSON array que utilizamos para controlar el flujo de un Voice API call.
El sitio NCCO necesita ser público y accesible por internet. Para lograr esto, en este tutorial vamos a utilizar GitHub Gist que proporciona una forma conveniente de alojar la configuración. Vamos a añadir un nuevo gist:
Ir a https://gist.github.com/ (tenemos que estar registrados en Github)
Cree un nuevo gist con
ncco.jsoncomo nombre de archivoCopia y pega el siguiente
JSONen el gist:
[
{
"action": "talk",
"text": "Please wait while we connect you."
},
{
"action": "connect",
"endpoint": [
{
"type": "phone",
"number": "PHONE_NUMBER"
}
]
}
]Sustituya
PHONE_NUMBERpor tu número de teléfono (Los números de Vonage están en formato E.164,+y-no son válidos. Asegúrate de especificar el código de país al introducir el número, por ejemplo, US: 14155550100 y Reino Unido: 447700900001)Haga clic en el botón
Create secret gistbotónHaga clic en el botón
RawbotónToma nota de la URL que aparece en el navegador, la utilizaremos en el siguiente paso
Instalar Vonage CLI
El CLI de Vonage nos permite realizar muchas operaciones usando la línea de comandos. Si queremos realizar tareas como crear aplicaciones, crear conversaciones, comprar números de Vonage, etc., necesitaremos instalar la CLI de Vonage.
La CLI de Vonage requiere Node.jspor lo que necesitaremos instalar Node.js primero.
Para instalar la versión Beta de la CLI con npm, ejecute este comando:
npm install nexmo-cli@beta -gConfigura el Vonage CLI para utilizar el Vonage API Key y API Secret. Podemos obtenerlos de la página de configuración en el Panel de control.
Ejecute el siguiente comando en el terminal, sustituyendo API_KEY y API_SECRET por los valores del Panel de control:
nexmo setup API_KEY API_SECRET Configurar aplicación de Vonage
Cree el directorio del proyecto. Ejecute el siguiente comando en el terminal:
mkdir vonage-tutorialCambie al directorio del proyecto:
cd vonage-tutorialCrea una aplicación de Vonage copiando y pegando el siguiente comando en el terminal. Asegúrate de cambiar el valor de
--voice-answer-urlsustituyendoGIST-URLpor la URL gist del paso anterior.
nexmo app:create "App to Phone Tutorial" --capabilities=voice --keyfile=private.key --voice-event-url=https://example.com/ --voice-answer-url=GIST-URLAnote el Application ID que aparece en el terminal cuando se crea la aplicación.
NOTA: Se crea un archivo oculto llamado
.nexmo-appen el directorio del proyecto y contendrá el archivoVonage Application IDy la clave privada. También se crea un archivo de clave privada llamadoprivate.keyen la carpeta actual.
Crear usuario
Cada participante está representado por un Usuario y debe ser autenticado por el objeto 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:
nexmo user:create name="Alice" Generar JWT
La dirección 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 la aplicación:
nexmo jwt:generate sub=Alice exp=$(($(date +%s)+86400)) acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}' application_id=APPLICATION_IDEl comando anterior establece la expiración del JWT a un día a partir de ahora, que es el máximo.
Tome nota del JWT que generamos para Alice.
NOTA: En un entorno de producción, la aplicación debe exponer un endpoint que genere un archivo
JWTpara cada solicitud del cliente.
Instalar Xcode
Abrir AppStore e instalar Xcode.
Configuración de Flutter
Instalar el SDK de Flutter
Descargar e instalar Flutter SDK.
Este paso variará en MacOS, Winy Linuxpero, en general, se reduce a descargar Flutter SDK para un sistema operativo determinado, extraer el archivo Flutter SDK y añadir la carpeta sdk\bin a la variable PATH del sistema. Encontrará instrucciones detalladas para todas las plataformas aquí.
Afortunadamente, Flutter viene con una herramienta que nos permite verificar si SDK y todos los "componentes" necesarios están presentes y configurados correctamente. Ejecute este comando:
flutter doctorFlutter Doctor verificará si Flutter SDK está instalado y otros componentes están instalados y configurados correctamente.
Crear proyecto Flutter
Crearemos un Flutter proyecto utilizando el terminal:
flutter create app_to_phone_flutterEl comando anterior crea app_to_phone_flutter que contiene el proyecto Flutter proyecto.
FlutterEl proyecto contieneiosque contiene el proyectoiOSproyecto;androidcarpeta que contiene elAndroidproyecto; ywebcarpeta que contienewebproyecto.
Abra el pubspec.yaml y añada la dependencia permission_handler dependencia (justo debajo de sdk: flutter):
dependencies:
flutter:
sdk: flutter
permission_handler: ^6.0.1+1La sangría es importante en los archivos
yamlasí que asegúrese de quepermission_handleresté en el mismo nivel de sangría que el elementoflutter:elemento.
Ahora ejecute este comando (la ruta es la raíz del proyecto Flutter proyecto) para descargar la dependencia anterior:
flutter pub getEl comando anterior también creará Podfile en la subcarpeta ios subcarpeta. Abra ios\Podfile descomente platform y actualice la versión de la plataforma a 11:
platform :ios, '11.0'Al final del mismo archivo añada pod 'NexmoClient':
target 'Runner' do
use_frameworks!
use_modular_headers!
pod 'NexmoClient'Abra la carpeta app_to_phone_flutter/ios en el termnal e instale los pods:
pod installEl comando anterior descargará todas las dependencias necesarias, incluyendo Flutterel gestor de permisos y Client SDK.
Abrir Runner.xcworkspace en Xcode y ejecute la aplicación para verificar que la configuración anterior se ha realizado correctamente.
Comunicación bidireccional Flutter/iOS
Actualmente Client SDK no está disponible como paquete Flutter por lo que tendremos que utilizar Client SDK nativo de Android y comunicarnos entre iOS y Flutter utilizando MethodChannel - de esta manera, Flutter llamará a los métodos de Android, iOS llamará a métodos Flutter métodos.
El código de Flutter se almacenará en el archivo lib/main.dart mientras que el código iOS código nativo se almacenará en el ios/Runner/AppDelegate.swift 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 enum representa los posibles estados de Vonage Client SDK. Este enum se definirá dos veces - una para el Flutter utilizando Dart y otra para iOS usando Swift. El widget contiene el método _updateView que cambiará la interfaz de usuario en función del valor de SdkState valor.
Ejecute la aplicación desde el menú Xcode:

El botón Login as Alice debe aparecer:

Pantalla de inicio de sesión
El botón Login as Alice 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);
}
}Sustituya el ALICE_TOKEN por el JWT que obtuvimos anteriormente de Vonage CLI para autenticar al usuario Alice para el acceso a la conversación. Flutter llamará al método loginUser y pasará el token como argumento. El método loginUser está definido en la clase MainActivity (llegaremos a ella más adelante). Para llamar a este método desde Flutter tenemos que definir un método MethodChannel. Añadir platformMethodChannel en la parte superior de _CallWidgetState la clase:
Añada platformMethodChannel en la parte superior de _CallWidgetState 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 al que también haremos referencia en el código nativo iOS nativo (AppDelegate class). Ahora tenemos que manejar esta llamada de método en el nativo iOS nativo.
Abra ios/Runner/AppDelegate y la propiedad vonageChannel que contendrá la referencia a la clase FlutterMethodChannel:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var vonageChannel: FlutterMethodChannel?
...Para escuchar las llamadas a métodos procedentes de Flutter añada el método addFlutterChannelListener dentro de la clase AppDelegate (al mismo nivel que el método application anterior):
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)
}
})
}El método anterior "traduce" las Flutter a métodos definidos en la clase AppDelegate (la clase loginUser por ahora).
Y faltan los loginUser métodos dentro de la misma clase (rellenaremos el cuerpo pronto):
func loginUser(token: String) {
}Ahora añade addFlutterChannelListener dentro del método application método:
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
addFlutterChannelListener()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}El código está en su lugar - después de pulsar el botón Login As Alice la aplicación Flutter llamará al método _loginUser método A través del canal Flutter el método llamará al método loginUser definido en la clase AppDelegate clase.
Ejecute la aplicación desde Xcode para asegurarte de que se está compilando.
Antes de que seamos capaces de iniciar la sesión de usuario tenemos que inicializar el archivo Vonage SDK Client.
Inicializar cliente
Abra la clase AppDelegate y añada NexmoClient import en la parte superior del archivo:
import NexmoClientEn el mismo archivo añada client que contendrá una referencia a Vonage Client.
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var vonageChannel: FlutterMethodChannel?
let client = NXMClient.shared
...Ahora añade el método initClient para inicializar el cliente:
func initClient() {
client.setDelegate(self)
}Para llamar al método initClient desde el método application existente, tendremos que añadir la línea initClient() como se muestra en el siguiente ejemplo:
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
initClient()
addFlutterChannelListener()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}Antes de permitir la conversación necesitamos saber que el usuario se ha identificado correctamente. En el archivo AppDelegate añade un delegado para escuchar Vonage Client SDK cambios de estado de la conexión:
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)
}
}
}Por último, el método notifyFlutter a la misma clase:
func client(_ client: NXMClient, didReceiveError error: Error) {
notifyFlutter(state: .error)
}
} Iniciar sesión del usuario
Modificar loginUser el cuerpo del método para llamar login en la instancia del cliente:
func loginUser(token: String) {
self.client.login(withAuthToken: token)
}Este método nos permitirá iniciar la sesión del usuario (Alice) utilizando el método Client SDK para acceder a la conversación.
Notificación a Flutter del cambio de estado del Client SDK
Notificar Flutter de cualquier cambio en el estado de Client SDKtendremos que añadir un enum que represente los estados del Client SDK. Ya hemos añadido el equivalente SdkState en el archivo main.dart equivalente. Añade el siguiente SdkState enum, al final del MainActivity.kt archivo:
enum SdkState: String {
case loggedOut = "LOGGED_OUT"
case loggedIn = "LOGGED_IN"
case wait = "WAIT"
case onCall = "ON_CALL"
case error = "ERROR"
}Para enviar estos estados a Flutter (del delegado anterior) necesitamos añadir el método notifyFlutter en la clase AppDelegate clase:
func notifyFlutter(state: SdkState) {
vonageChannel?.invokeMethod("updateState", arguments: state.rawValue)
}Observe que almacenamos el estado en el enum, pero lo estamos enviando como una cadena.
Recuperar la actualización del estado del SDK por Flutter
Para recuperar las actualizaciones de estado en Flutter tenemos que escuchar las actualizaciones del canal del método. Abra el archivo main.dart y añade el constructor _CallWidgetState con un manejador personalizado:
_CallWidgetState() {
platformMethodChannel.setMethodCallHandler(methodCallHandler);
}Dentro de la misma clase (_CallWidgetState) añade el método handler:
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 convierten 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 .
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 app basado en el SdkState enum`). Un ejemplo de esto se muestra en la siguiente imagen:

Hacer una llamada
Ahora tenemos que añadir la funcionalidad para hacer una llamada telefónica. Abra el archivo main.dart y actualiza el cuerpo del método _makeCall como se muestra a continuación:
Future<void> _makeCall() async {
try {
await platformMethodChannel
.invokeMethod('makeCall');
} on PlatformException catch (e) {
print(e);
}
}El método anterior se comunicará con iOS por lo que tenemos que actualizar el código en la clase AppDelegate también. Añadir makeCall a la sentencia switch dentro de addFlutterChannelListener del método:
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)
}
})
}Ahora, en el mismo archivo, añada la propiedad onGoingCall que define si una llamada está en curso y cuándo:
var onGoingCall: NXMCall?NOTA: Actualmente el
Client SDKno almacena la referencia de llamada en curso, por lo que tenemos que almacenarla en la claseAppDelegateclase. La utilizaremos más adelante para finalizar la llamada.
Ahora en la misma clase añade makeCall método:
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)
}
}El método anterior establece el estado de la Flutter aplicación a SdkState.WAIT y espera la respuesta Client SDK respuesta (error o éxito). Ahora necesitamos añadir soporte para ambos estados (SdkState.ON_CALL y SdkState.ERROR) dentro del archivo main.dart del archivo. 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 provocará 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 el proyecto para solicitar estos permisos.
Solicitar permisos
La aplicación necesita poder acceder al micrófono, por lo que tenemos que solicitar acceso al micrófono (Permission.microphone para Flutter ).
Abra ios/Runner/info.plist y añada Privacy - Microphone Usage Description clave con Make a call valor:

Ya hemos añadido el permission_handler al proyecto Flutter proyecto. Ahora, en la parte superior del archivo main.dart tendremos que 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, tendremos 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();
}El método anterior solicitará permisos utilizando permission_handler.
En la misma clase, modifica el cuerpo de la clase _makeCall para solicitar permisos antes de llamar al método a través del canal de métodos:
Future<void> _makeCall() async {
try {
await requestPermissions();
...
}Ejecute la aplicación y pulse MAKE PHONE CALL para iniciar una llamada. Aparecerá el diálogo de permisos y, tras conceder los permisos, se iniciará la llamada.
Recordatorio: hemos definido el número de teléfono anteriormente en la sección
NCCO
El estado de la aplicación se actualizará a SdkState.ON_CALL y se actualizará la interfaz de usuario:

Finalizar llamada
Para finalizar la llamada necesitamos activar el método en la aplicación nativa iOS nativa mediante platformMethodChannel. Dentro del archivo main.dart actualizamos el cuerpo del método _endCall del método:
Future<void> _endCall() async {
try {
await platformMethodChannel.invokeMethod('endCall');
} on PlatformException catch (e) {}
}El método anterior se comunicará con iOSpor lo que tenemos que actualizar el código en la clase AppDelegate también. Añade las cláusulas endCall a la sentencia switch dentro del método addFlutterChannelListener método:
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)
}
})
}
Ahora en la misma clase añade el endCall método:
func endCall() {
onGoingCall?.hangup()
onGoingCall = nil
notifyFlutter(state: .loggedIn)
}El método anterior establece el estado de la Flutter aplicación a SdkState.WAIT y espera la respuesta del método Client SDKque puede ser de error o de éxito. Ambos estados de la interfaz de usuario ya están soportados en la aplicación Flutter aplicación (_updateView ).
Hemos gestionado la finalización de la llamada pulsando el botón END CALL en la Flutter de la aplicación. Sin embargo, la llamada también puede finalizar fuera de la aplicación. Flutter por ejemplo, la llamada será rechazada o contestada, y más tarde finalizada por el destinatario de la llamada (en el teléfono real).
Para soportar estos casos tenemos que añadir el NexmoCallEventListener a la instancia de llamada y escuchar los eventos específicos de la llamada.
En el archivo AppDelegares.swift archivo añada 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)
}
}Para registrar el listener anterior modifique onSuccess callback dentro de makeCall del método:
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)
}
}Ejecute la aplicación y realice una llamada telefónica desde la aplicación móvil a un número de teléfono físico.
Resumen
Hemos creado la aplicación con éxito. Al hacerlo hemos aprendido cómo hacer una llamada desde una aplicación móvil al teléfono usando Vonage Client SDK. Para ver el proyecto completo consulta GitHub. Este proyecto contiene además el código nativo de Android (android ) que nos permite ejecutar esta aplicación también en Android.
Para familiarizarse con otras funcionalidades, consulte otros tutoriales y Centro de desarrollo de Vonage.