https://a.storyblok.com/f/270183/39838/1b00632416/flutter_inapp-call-2_1200x600.png

Como fazer uma chamada do aplicativo para o celular usando iOS e Flutter

Publicado em April 1, 2021

Tempo de leitura: 11 minutos

Hoje vamos criar um iOS aplicativo usando Flutter e usaremos o Vonage Client SDK para fazer uma chamada de um aplicativo móvel para um telefone usando a Conversation API da Vonage. O aplicativo terá 3 telas (3 estados da interface do usuário):

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

Pré-requisitos

O código-fonte do nosso Flutter iOS aplicativo está disponível no GitHub.

Antes de começarmos a criar o Flutter aplicativo para o iOS dispositivo, precisamos nos preparar com os seguintes pré-requisitos:

  • Criar um objeto de controle de chamadas (NCCO)

  • Instale o Vonage CLI (anteriormente Nexmo CLI)

  • Configure o Vonage application

  • Instale o Flutter SDK

  • Crie o Flutter projeto

Aplicativo Vonage

Criar um NCCO

A Objeto de Controle de Chamadas (NCCO) é uma JSON matriz que usamos para controlar o fluxo de uma Voice API call.

O NCCO precisa ser público e acessível pela internet. Para isso, neste tutorial, usaremos o o GitHub Gist , que oferece uma maneira prática de hospedar a configuração. Vamos adicionar um novo gist:

  1. Acesse https://gist.github.com/ (precisamos estar conectados ao GitHub)

  2. Crie um novo gist com ncco.json como nome do arquivo

  3. Copie e cole o seguinte JSON objeto no gist:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "number": "PHONE_NUMBER"
            }
        ]
    }
]
  1. Substitua PHONE_NUMBER pelo seu número de telefone (The Vonage numbers are in the E.164 format, + e - não são válidos. Certifique-se de especificar o código do país ao inserir o número; por exemplo, EUA: 14155550100 e Reino Unido: 447700900001)

  2. Clique no Create secret gist botão

  3. Clique no Raw botão

  4. Anote a URL exibida no navegador; vamos usá-la na próxima etapa

Instalar o CLI do Vonage

O CLI da Vonage nos permite realizar diversas operações por meio da linha de comando. Se quisermos realizar tarefas como criar Applications, criar conversas, adquirir Numbers da Vonage e assim por diante, precisaremos instalar a CLI da Vonage.

O CLI da Vonage exige Node.js, portanto, precisaremos instalar o Node.js primeiro.

Para instalar a versão Beta da CLI com o npm, execute este comando:

npm install nexmo-cli@beta -g

Configure o Vonage CLI para usar o Vonage API Key e API Secret. Podemos obtê-las na página de configurações no Painel de Controle.

Execute o seguinte comando no terminal, substituindo API_KEY e API_SECRET pelos valores do Painel:

nexmo setup API_KEY API_SECRET

Configurar o aplicativo Vonage

  1. Crie o diretório do projeto. Execute o seguinte comando no terminal:

mkdir vonage-tutorial
  1. Navegue até o diretório do projeto:

cd vonage-tutorial
  1. Crie uma aplicação Vonage copiando e colando o comando abaixo no terminal. Certifique-se de alterar o valor do --voice-answer-url argumento, substituindo GIST-URL pela URL do gist da etapa anterior.

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

Anote o Application ID que é exibido no terminal quando o aplicativo é criado.

NOTA: Um arquivo oculto chamado .nexmo-app é criado no diretório do projeto e contém a chave Vonage Application ID e a chave privada. Um arquivo de chave privada chamado private.key também é criado na pasta atual.

Criar usuário

Cada participante é representado por um objeto de usuário e deve ser autenticado pelo Client SDK. Em um aplicativo de produção, normalmente armazenaríamos essas informações do usuário em um banco de dados.

Execute o seguinte comando para criar um usuário chamado Alice:

nexmo user:create name="Alice"

Gerar JWT

O JWT é usado para autenticar o usuário. Execute o seguinte comando no terminal para gerar um JWT para o usuário Alice. No comando a seguir, substitua o APPLICATION_ID pelo ID do aplicativo:

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

O comando acima define o prazo de validade do JWT para um dia a partir de hoje, que é o máximo.

Anote a JWT que geramos para Alice.

NOTA: Em um ambiente de produção, o aplicativo deve expor um endpoint que gere um JWT para cada solicitação do cliente.

Instale o Xcode

Abra a App Store e instale o Xcode.

Configuração do Flutter

Instalar o SDK do Flutter

Baixe e instale Flutter SDK.

Essa etapa dependerá de MacOS, Win, e Linux, mas, em geral, resume-se a baixar Flutter SDK para um determinado sistema operacional, extrair o Flutter SDK arquivo e adicionar a sdk\bin pasta à variável PATH . Instruções detalhadas para todas as plataformas podem ser encontradas aqui.

Felizmente, Flutter vem com uma ferramenta que nos permite verificar se SDK e todos os “componentes” necessários estão presentes e configurados corretamente. Execute este comando:

flutter doctor

Flutter Doctor verificará se Flutter SDK está instalado e se os demais componentes estão instalados e configurados corretamente.

Criar projeto no Flutter

Vamos criar um Flutter projeto usando o terminal:

flutter create app_to_phone_flutter

O comando acima cria app_to_phone_flutter uma pasta contendo o Flutter projeto.

Flutter O projeto contém ios pasta, que contém o iOS projeto; android pasta que contém o Android projeto; e web pasta que contém web projeto.

Abra o pubspec.yaml arquivo e adicione permission_handler dependência (logo abaixo de sdk: flutter):

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

A indentação é importante nos yaml arquivos; portanto, certifique-se de que permission_handler este esteja no mesmo nível de recuo que o flutter: item.

Agora execute este comando (o caminho é a raiz do Flutter projeto) para baixar a dependência acima:

flutter pub get

O comando acima também criará Podfile na ios subpasta. Abra ios\Podfile remova o comentário platform linha e atualize a versão da plataforma para 11:

platform :ios, '11.0'

No final do mesmo arquivo, adicione pod 'NexmoClient':

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

Abra app_to_phone_flutter/ios pasta no terminal e instale os pods:

pod install

O comando acima baixará todas as dependências necessárias, incluindo Flutter, o gerenciador de permissões e Client SDK.

Abrir Runner.xcworkspace no Xcode e execute o aplicativo para verificar se a configuração acima foi realizada corretamente.

Comunicação bidirecional entre o Flutter e o iOS

No momento, Client SDK não está disponível como um Flutter pacote; portanto, teremos que usar o Client SDK do cliente nativo do Android e nos comunicarmos entre iOS e Flutter usando o MethodChannel — dessa forma, Flutter serão chamados métodos do Android, iOS serão chamados Flutter métodos.

O código do Flutter será armazenado no lib/main.dart arquivo, enquanto iOS o código nativo será armazenado no ios/Runner/AppDelegate.swift arquivo.

Inicializar o aplicativo Flutter

Os aplicativos Flutter são desenvolvidos usando uma linguagem de programação chamada Dart.

Abra lib/main.dart arquivo e substitua todo o conteúdo pelo código a seguir:

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
}

O código acima contém CallWidget que será responsável por gerenciar o estado do aplicativo (fazer o login do usuário e gerenciar a chamada). A SdkState enumeração representa os possíveis estados do Vonage Client SDK. Essa enumeração será definida duas vezes — uma para o Flutter, usando Dart e outra para iOS usando Swift. O widget contém o _updateView método que alterará a interface do usuário com base no SdkState valor.

Execute o aplicativo a partir do Xcode:

Running the application from xcode

O Login as Alice botão deve ser exibido:

Logged out screen showing Login as Alice button

Tela de login

O Login as Alice botão está desativado; agora adicione onPressed um manipulador ao ElevatedButton para permitir o login:

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

Atualizar o corpo do _loginUser método para se comunicar com o código nativo e fazer o login do usuário:

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

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

Substitua o ALICE_TOKEN pelo JWT token que obtivemos anteriormente de Vonage CLI para autenticar o usuário Alice para o acesso à conversa. Flutter chamará o loginUser método e passará o token como argumento. O loginUser método está definido na MainActivity classe (chegaremos lá em um instante). Para chamar esse método a partir de Flutter , precisamos definir um MethodChannel. Adicione platformMethodChannel campo no topo da _CallWidgetState classe:

Adicione platformMethodChannel campo na parte superior da _CallWidgetState classe:

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

A com.vonage string representa o ID exclusivo do canal, ao qual também nos referiremos no iOS (AppDelegate classe). Agora precisamos lidar com essa chamada de método no iOS .

Aula ios/Runner/AppDelegate classe e vonageChannel propriedade que conterá a referência à FlutterMethodChannel:

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

Para monitorar chamadas de método originadas de Flutter método addFlutterChannelListener dentro da AppDelegate classe (mesmo nível do application ):

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

O método acima “traduz” as Flutter chamadas de método para métodos definidos na AppDelegate classe (a loginUser por enquanto).

E faltam os loginUser métodos dentro da mesma classe (vamos preencher o corpo em breve):

func loginUser(token: String) {

}

Agora adicione addFlutterChannelListener a chamada de método dentro do 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)
    }

O código já está pronto — depois de pressionar o Login As Alice botão, o aplicativo Flutter chamará o _loginUser método. Por meio do Flutter canal da plataforma, o método chamará o loginUser método definido na AppDelegate classe.

Execute o aplicativo a partir de Xcode para verificar se ele está sendo compilado.

Antes de podermos fazer o login do usuário, precisamos inicializar o Vonage SDK Client.

Inicializar o cliente

Abra AppDelegate classe e adicione a NexmoClient import no início do arquivo:

import NexmoClient

No mesmo arquivo, adicione client uma propriedade que conterá uma referência a Vonage Client.

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

...

Agora adicione initClient o método para inicializar o cliente:

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

Para chamar o initClient método a partir do application , precisaremos adicionar a initClient() linha conforme mostrado no exemplo abaixo:

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 a conversa, precisamos ter certeza de que o usuário fez o login corretamente. No AppDelegate arquivo, adicione um delegado para monitorar Vonage Client SDK mudanças no estado da conexão:

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 fim, o notifyFlutter método precisa ser adicionado à mesma classe:

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

Fazer login do usuário

Modificar loginUser o corpo do método para chamar login na instância do cliente:

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

Esse método nos permitirá fazer o login do usuário (Alice) usando o Client SDK para acessar a conversa.

Notificar o Flutter sobre a alteração no estado do Client SDK

Para notificar Flutter sobre quaisquer alterações no estado do Client SDK, precisaremos adicionar um enum para representar os estados do Client SDK. Já adicionamos a enumeração equivalente SdkState enum no main.dart arquivo. Adicione a seguinte SdkState enum, no final do MainActivity.kt arquivo:

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

Para enviar esses estados para Flutter (a partir do delegado acima), precisamos adicionar notifyFlutter um método na AppDelegate classe:

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

Observe que armazenamos o estado na enumeração, mas o estamos enviando como uma string.

Recuperar a atualização do estado do SDK pelo Flutter

Para recuperar atualizações de estado em Flutter precisamos monitorar as atualizações do canal de métodos. Abra main.dart o arquivo e adicione _CallWidgetState um construtor com um manipulador personalizado:

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

Dentro da mesma classe (_CallWidgetState) adicione o método manipulador:

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

Esses métodos recebem o “sinal” do Android e o convertem em uma enumeração. Agora, atualize o conteúdo do _updateView método para oferecer suporte SdkState.WAIT e SdkState.LOGGED_IN estados, conforme mostrado no exemplo abaixo:

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 a barra de progresso será exibida. Após o login bem-sucedido, o aplicativo exibirá o MAKE PHONE CALL botão.

Execute o aplicativo e clique no botão chamado LOGIN AS ALICE. O MAKE PHONE CALL deve aparecer o botão, que é outro estado do Flutter aplicativo com base na SdkState enum`). Um exemplo disso é mostrado na imagem abaixo:

Make a phone call UI state

Faça uma ligação

Agora precisamos adicionar a funcionalidade para fazer uma ligação telefônica. Abra o main.dart arquivo e atualize o corpo do _makeCall método conforme mostrado abaixo:

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

O método acima se comunicará com iOS portanto, precisamos atualizar o código na AppDelegate classe também. Adicione makeCall cláusulas à switch instrução dentro do 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("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

Agora, no mesmo arquivo, adicione a onGoingCall propriedade, que define se e quando uma chamada está em andamento:

var onGoingCall: NXMCall?

NOTA: Atualmente, o Client SDK não armazena a referência da chamada em andamento; por isso, precisamos armazená-la na AppDelegate classe. Vamos usá-la mais tarde para encerrar a chamada.

Agora, na mesma classe, adicione 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)
        }
    }

O método acima define o estado do Flutter aplicativo para SdkState.WAIT e aguarda a Client SDK resposta (erro ou sucesso). Agora precisamos adicionar suporte para ambos os estados (SdkState.ON_CALL e SdkState.ERROR) dentro do main.dart arquivo. Atualize o corpo do _updateView método para que fique igual ao exemplo abaixo:

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 mudança de estado resultará em uma modificação na interface do usuário. Antes de fazer uma chamada, o aplicativo precisa de permissões específicas para usar o microfone. Na próxima etapa, vamos adicionar ao projeto a funcionalidade necessária para solicitar essas permissões.

Solicitar permissões

The application needs to have access to the microphone, so we need to request access to the microphone (Permission.microphone para Flutter ).

Abra ios/Runner/info.plist o arquivo e adicione Privacy - Microphone Usage Description chave com o Make a call valor:

Setting add microphone permission

Já adicionamos o pacote permission_handler ao Flutter projeto. Agora, no início do main.dart arquivo, precisaremos importar o permission_handler pacote, conforme mostrado no exemplo abaixo:

import 'package:permission_handler/permission_handler.dart';

Para acionar a solicitação de determinadas permissões, precisaremos adicionar o requestPermissions() método dentro da _CallWidgetState classe dentro do main.dart arquivo. Portanto, adicione este novo método dentro da classe:

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

O método acima solicitará permissões usando permission_handler.

Na mesma classe, modifique o corpo da _makeCall classe para solicitar permissões antes de chamar o método por meio do canal de métodos:

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

Execute o aplicativo e clique MAKE PHONE CALL para iniciar uma chamada. A janela de permissão será exibida e, após conceder as permissões, a chamada será iniciada.

Lembrete: definimos o número de telefone anteriormente no NCCO

O status do aplicativo será atualizado para SdkState.ON_CALL e a interface do usuário será atualizada:

On call UI

Encerrar chamada

Para encerrar a chamada, precisamos acionar o método no iOS usando platformMethodChannel. Dentro do main.dart arquivo, atualize o corpo do _endCall método:

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

O método acima se comunicará com iOS, portanto, precisamos atualizar o código na AppDelegate classe também. Adicione endCall cláusulas à switch instrução dentro do 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)
            }
        })
    }

Agora, na mesma classe, adicione o endCall método:

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

O método acima define o estado do Flutter aplicativo para SdkState.WAIT e aguarda a resposta do Client SDK, que pode ser de erro ou sucesso. Ambos os estados da interface do usuário já são suportados pelo Flutter aplicativo (_updateView método).

Já abordamos como encerrar a chamada pressionando o END CALL botão na Flutter interface do aplicativo. No entanto, a chamada também pode ser encerrada fora do Flutter aplicativo; por exemplo, a chamada pode ser rejeitada ou atendida e, posteriormente, encerrada pelo destinatário (no telefone real).

Para dar suporte a esses casos, precisamos adicionar o NexmoCallEventListener ouvinte à instância da chamada e ficar atento aos eventos específicos da chamada.

No AppDelegares.swift arquivo, adicione 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 o ouvinte acima, modifique onSuccess o callback dentro do 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.onGoingCall?.setDelegate(self)
            self.notifyFlutter(state: .onCall)
        }
    }

Execute o aplicativo e faça uma ligação a partir do aplicativo móvel para um número de telefone físico.

Resumo

Conseguimos desenvolver o aplicativo com sucesso. Com isso, aprendemos a fazer uma ligação de um aplicativo móvel para um telefone usando o Vonage Client SDK. Para ver o projeto completo, acesse GitHub. Além disso, este projeto contém o código nativo do Android (android pasta), o que nos permite rodar esse aplicativo também no Android.

Para se familiarizar com outras funcionalidades, consulte outros tutoriais e o Centro de Desenvolvedores da Vonage.

Referências

Compartilhar:

https://a.storyblok.com/f/270183/384x384/8ae5af43bb/igor-wojda.png
Igor WojdaEx-funcionários da Vonage