
Como fazer uma chamada do aplicativo para o celular usando iOS e Flutter
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):

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(anteriormenteNexmo CLI)Configure o
Vonage applicationInstale o
Flutter SDKCrie o
Flutterprojeto
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:
Acesse https://gist.github.com/ (precisamos estar conectados ao GitHub)
Crie um novo gist com
ncco.jsoncomo nome do arquivoCopie e cole o seguinte
JSONobjeto no gist:
[
{
"action": "talk",
"text": "Please wait while we connect you."
},
{
"action": "connect",
"endpoint": [
{
"type": "phone",
"number": "PHONE_NUMBER"
}
]
}
]Substitua
PHONE_NUMBERpelo 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)Clique no
Create secret gistbotãoClique no
RawbotãoAnote 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 -gConfigure 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
Crie o diretório do projeto. Execute o seguinte comando no terminal:
mkdir vonage-tutorialNavegue até o diretório do projeto:
cd vonage-tutorialCrie uma aplicação Vonage copiando e colando o comando abaixo no terminal. Certifique-se de alterar o valor do
--voice-answer-urlargumento, substituindoGIST-URLpela 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-URLAnote 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 chaveVonage Application IDe a chave privada. Um arquivo de chave privada chamadoprivate.keytambé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_IDO 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
JWTpara 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 doctorFlutter 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_flutterO comando acima cria app_to_phone_flutter uma pasta contendo o Flutter projeto.
FlutterO projeto contémiospasta, que contém oiOSprojeto;androidpasta que contém oAndroidprojeto; ewebpasta que contémwebprojeto.
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+1A indentação é importante nos
yamlarquivos; portanto, certifique-se de quepermission_handlereste esteja no mesmo nível de recuo que oflutter:item.
Agora execute este comando (o caminho é a raiz do Flutter projeto) para baixar a dependência acima:
flutter pub getO 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 installO 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:

O Login as Alice botão deve ser exibido:

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 NexmoClientNo 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:

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 SDKnão armazena a referência da chamada em andamento; por isso, precisamos armazená-la naAppDelegateclasse. 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:

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:

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.