https://d226lax1qjow5r.cloudfront.net/blog/blogposts/make-and-receive-phone-calls-in-android-apps-with-nexmo-in-app-voice-and-firebase-dr/Nexmo-FIrebase-Android-App-Voice.png

Hacer y recibir llamadas telefónicas en aplicaciones Android con Firebase

Publicado el May 20, 2021

Tiempo de lectura: 7 minutos

Con Nexmo In-App Voicepuede realizar y recibir llamadas telefónicas fácilmente con Nexmo Stitch Android SDK y la tecnología WebRTC. En este tutorial le mostraremos cómo hacer una aplicación Android simple que puede hacer llamadas telefónicas salientes y recibir llamadas telefónicas entrantes. Esta funcionalidad podría ser utilizada donde los clientes quieren hacer y recibir llamadas al servicio al cliente, sin salir de la aplicación.

Para poner en marcha la aplicación, utilizaremos Funciones Firebase para alojar la aplicación NCCO y devolver un JWT para que los usuarios inicien sesión.

Para seguir con esta entrada del blog, debes tener algún conocimiento de JavaScript y ser capaz de construir una aplicación Android usando Kotlin.

Antes de empezar

Hay algunas cosas que necesitarás antes de empezar.

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Configure la función Firebase.

En primer lugar, vamos a querer crear un nuevo directorio para nuestro proyecto de funciones Firebase y para almacenar nuestros archivos de configuración.

mkdir firebase-functions-nexmo-in-app-calling cd firebase-functions-nexmo-in-app-calling

Ahora que se ha creado un nuevo directorio, podemos seguir las for proporcionadas por Firebase y crear un nuevo proyecto.

npm install -g firebase-tools firebase login firebase init functions

Para este proyecto elegí utilizar JavaScript en lugar de TypeScript.

Si como yo, no pudiste crear un proyecto de función firebase desde la línea de comandos puedes visitar la Consola Firebase para crear un nuevo proyecto, y luego ejecutar firebase use --add desde la línea de comandos.

Editar las funciones Firebase

Puedes ver la versión final de los métodos que usaremos para las Funciones Firebase en el repo de esta demo en GitHub. En resumen necesitamos tres endpoints:

  1. Una URL de respuesta que albergará la OCNC

  2. Una URL de eventos para capturar eventos de la Voice API

  3. Una URL para devolver un JWT con el que los usuarios puedan iniciar sesión

Para editar las funciones Firebase, tendremos que editar el archivo index.js en el nuevo directorio functions/ que firebase creó después de ejecutar firebase init functions

Empecemos por el método Respuesta

exports.answer = functions.https.onRequest((request, response) => {
  //use the `to` query parameter that Nexmo gives us to make a call.
  //if `to` is null, then we are receiving a call.
  var to = request.query.to
  var from = request.query.from

  var ncco = [];

  if (to) {
    ncco.push(
      {
        action: "talk",
        text: "Thank you for calling, you are now being connected."
      },
      {
        "action": "connect",
        "from": functions.config().nexmo.from_number,
        "endpoint": [
          {
            "type": "phone",
            "number": `${to}`
          }
        ]
      }
    )
  } else {
    ncco.push(
      {
        action: "talk",
        text: "You are being connected to the Customer."
      },
      {
        "action": "connect",
        "from": from,
        "endpoint": [
          {
            "type": "app",
            "user": "Customer"
          }
        ]
  
      })
  }
  response.json(ncco);
});

Dado que Voice API de Nexmo utiliza una URL de respuesta por aplicación, podemos mostrar dinámicamente la OCNC para aceptar una llamada entrante si el parámetro de consulta to es nulo. Si el parámetro to parámetro de consulta es no null, entonces mostraremos la NCCO para hacer una llamada saliente.

Nuestro punto final para proporcionar un JWT a los usuarios es bastante sencillo. Usaremos la librería biblioteca Nexmo Node para generar un JWT. Para usar la librería necesitaremos instalar el paquete.

#Asegúrate de estar en el directorio /functions donde están los archivos package.json e index.js npm install nexmo

Después de instalar la biblioteca, puede asegurarse de que todo funciona correctamente inspeccionando el archivo package.json archivo. Debería tener este aspecto:

"dependencies": {
    "firebase-admin": "~5.12.1",
    "firebase-functions": "^1.0.3",
    "nexmo": "^2.3.2"
  }

Una vez instalada la librería Nexmo Node, podemos utilizarla en el endpoint jwt de la siguiente forma para devolver un fichero válido user_jwt.

exports.jwt = functions.https.onRequest((request, response) => {
    response.json({
      user_jwt: Nexmo.generateJwt("private.key", {
        application_id: functions.config().nexmo.application_id,
        sub: "Customer",
        exp: new Date().getTime() + 86400,
        acl: adminAcl
      })
    });
});

Ahora que hemos creado nuestras funciones Firebase, crearemos una aplicación Vonage.

Despliegue de la función Firebase

Ahora que las Funciones Firebase han sido escritas, podemos desplegar el proyecto Firebase. Después de desplegar las Funciones, Firebase nos dará las URLs para nuestros puntos finales de respuesta y eventos. Podemos usar estas URLs para crear nuestra aplicación de Vonage.

#Asegúrate de estar en el directorio firebase-functions-nexmo-in-app-calling/ que creamos al principio de este tutorial firebase deploy --only functions

✔ funciones[respuesta]: Operación de creación exitosa. URL de la función (respuesta): https://your-project-name.cloudfunctions.net/answer ✔ funciones[evento]: Operación de creación exitosa. Función URL (evento): https://your-project-name.cloudfunctions.net/event ✔ functions[jwt]: Operación de creación exitosa. Función URL (jwt): https://your-project-name.cloudfunctions.net/jwt

Configura la aplicación de Vonage.

Para crear una aplicación, primero instala la CLI de Vonage globalmente con este comando:

npm install @vonage/cli -g

Luego, configura la CLI con tu clave y secreto de API de Vonage. Puedes encontrar esta información en el Panel del desarrollador.

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

Ahora usaremos la respuesta y la URL del evento que Firebase nos proporcionó en la sección anterior.

# Ensure you're in the firebase-functions-nexmo-in-app-calling/ directory we created at the beginning of this tutorial
vonage apps:create 
✔ Application Name … ruling_narwhal
✔ Select App Capabilities › Voice
✔ Create voice webhooks? … yes
✔ Answer Webhook - URL … https://your-project-name.cloudfunctions.net/answer
✔ Answer Webhook - Method › POST
✔ Event Webhook - URL … https://your-project-name.cloudfunctions.net/event
✔ Event Webhook - Method › POST
✔ Allow use of data for AI training? Read data collection disclosure - https://help.nexmo.com/hc/en-us/articles/4401914566036 … no
Creating Application... done
Application Name: ruling_narwhal

Tu clave privada se guarda en el directorio de funciones que has creado. La clave tendrá el mismo nombre que tu proyecto.

Registra el ID de la aplicación y guarda la clave privada en el directorio "funciones". Te recomiendo que añadas las etiquetas your_private_key_name.key y .nexmo-app con tus credenciales a tu directorio .gitignore.

Siguiendo las mejores prácticas, vamos a almacenar algunas variables de entorno Firebase configurar a través de la CLI firebase. Los documentos de Firebase contienen una sobre la configuración del entorno.

Ahora necesitamos almacenar el ID de la aplicación de Vonage en la configuración de firebase a través de la CLI de firebase.

firebase functions:config:set nexmo.application_id="aaaaaaaa-bbbb-cccc-dddd-0123456789ab"

Nota: Firebase requiere que las claves de las variables de configuración estén en minúsculas, por lo que usaremos snake case para los nombres de nuestras variables.

Si lo deseas, puedes cargar la cadena de claves privadas que se encuentra en el archivo .nexmo-app de tu aplicación de Vonage como una variable de configuración de firebase en lugar de subir el archivo completo a las funciones de firebase. your_private_key_name.key completo a las funciones de firebase.

Vincule un número de teléfono y un usuario a nuestra aplicación

Ahora que nuestras funciones han sido escritas, necesitamos comprar un número para que nuestros usuarios puedan hacer llamadas salientes desde ese número y recibir llamadas entrantes en su aplicación Android cada vez que alguien marque ese número. También tenemos que vincular el número a nuestra aplicación de Vonage.

Puedes alquilar un número de Vonage utilizando el siguiente comando (reemplazando el código de país por tu código). Por ejemplo, si estás en EE. UU., reemplaza GB por US:

vonage numbers:search US vonage numbers:buy [NUMBER] [COUNTRYCODE]

Ahora vincula el número a tu aplicación:

vonage apps:link --number=VONAGE_NUMBER APP_ID

Configurar el proyecto Android

Si desea ver el proyecto terminado para nuestra aplicación Android puede ver el código fuente en GitHub.

Primero necesitamos añadir las librerías necesarias. Vamos a utilizar Nexmo Stitch Android SDK, Retrofit y Retrofit's Moshi Converter.

dependencies {
  implementation 'com.nexmo:stitch:1.8.0'
  implementation 'com.squareup.retrofit2:retrofit:2.4.0'
  implementation "com.squareup.retrofit2:converter-moshi:2.4.0"
}

Utilizaremos Retrofit para hacer una GET al endpoint JWT de la función Firebase que Firebase CLI nos proporcionó.

//FirebaseFunctionService.kt
interface FirebaseFunctionService {
    @GET("jwt")
    fun getJWT(): Call<UserJWT>
}


//RetrofitClient.kt
var retrofitClient = Retrofit.Builder()
        .baseUrl("https://your-project-name.cloudfunctions.net/")
        .addConverterFactory(MoshiConverterFactory.create())
        .build()

var retrofitService = retrofitClient.create<FirebaseFunctionService>(FirebaseFunctionService::class.java)

Añadir la actividad de inicio de sesión

Una vez configurado Retrofit, podemos utilizarlo para recuperar un JWT desde el punto final de la función JWT Firebase en el archivo LoginActivity. Aquí mostraré el camino feliz cuando recuperamos el JWT del usuario y lo usamos para iniciar sesión en el SDK Android de Nexmo Stitch. El diseño de esta Actividad está disponible en GitHub.

class LoginActivity : BaseActivity(), RequestHandler<User>, Callback<UserJWT> {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        loginBtn.setOnClickListener {
            login()
        }
    }

    private fun login() {
        showProgress(true)
        retrofitService.getJWT().enqueue(this)
    }

    //Successfully retrieved a JWT from the Firebase Function endpoint
    override fun onResponse(call: Call<UserJWT>?, response: Response<UserJWT>?) {
        val jwt = response?.body()?.user_jwt
        client.login(jwt, this)
    }

    //User successfully logged in with the Nexmo Stitch SDK
    override fun onSuccess(result: User?) {
        goToCallActivity()
    }

}

Añadir la actividad de llamada

Añadiremos un diseño sencillo para introducir números de teléfono, iniciar y finalizar llamadas telefónicas. El diseño para esta actividad está disponible en GitHub. Como antes mostraré el camino feliz de hacer y recibir una llamada.

class CallActivity : BaseActivity(), RequestHandler<Call> {
    private var currentCall: Call? = null
    private lateinit var client: ConversationClient

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        client = Stitch.getInstance(this).conversationClient

        attachIncomingCallListener()
        callControlBtn.setOnClickListener { callPhone() }
    }

    private fun attachIncomingCallListener() {
        //Listen for incoming calls
        client.callEvent().add({ incomingCall ->
            logAndShow("answering Call")
            //Answer an incoming call
            incomingCall.answer(object : RequestHandler<Void> {
                override fun onError(apiError: NexmoAPIError) {
                    logAndShow("Error answer: " + apiError.message)
                }

                override fun onSuccess(result: Void) {
                    currentCall = incomingCall
                    attachCallStateListener(incomingCall)
                    showHangupButton()
                }
            })
        })
    }

    private fun attachCallStateListener(incomingCall: Call) {
        //Listen for incoming member events in a call
        val callEventListener = ResultListener<CallEvent> { message ->
            logAndShow("callEvent : state: " + message.state + " .content:" + message.toString())
        }
        incomingCall.event().add(callEventListener)
    }


    private fun callPhone() {
        val phoneNumber = phoneNumberInput.text.toString()

        client.callPhone(phoneNumber, object : RequestHandler<Call> {
            override fun onError(apiError: NexmoAPIError) {
                logAndShow("Cannot initiate call: " + apiError.message)
            }

            override fun onSuccess(result: Call) {
                currentCall = result
                showHangupButton()

                when (result.callState) {
                    Call.CALL_STATE.STARTED -> logAndShow("Started")
                    Call.CALL_STATE.RINGING -> logAndShow("Ringing")
                    Call.CALL_STATE.ANSWERED -> logAndShow("Answered")
                    else -> logAndShow("Error attaching call listener")
                }

            }
        })
    }

}

Como puede ver, el SDK de Nexmo Stitch se encarga del trabajo duro de realizar y responder llamadas telefónicas.

¿Cómo funciona?

Recibir una llamada telefónica

Cuando un usuario realice una llamada telefónica al número que hemos comprado en la sección anterior, Nexmo buscará la NCCO en nuestra URL de respuesta en https://your-project-name.cloudfunctions.net/answer . El NCCO tendrá el siguiente aspecto:

[  
   {  
      "action":"talk",
      "text":"You are being connected to the Customer."
   },
   {  
      "action":"connect",
      "endpoint":[  
         {  
            "type":"app",
            "user":"Customer"
         }
      ]
   }
]

Esta OCN dirigirá la llamada al usuario "Cliente" que creamos en nuestra aplicación con el SDK de Stitch. La aplicación se encargará de responder la llamada adjuntando el Call Listener en attachIncomingCallListener() En aras de la simplicidad, vamos a responder automáticamente la llamada, pero usted podría implementar una interfaz de usuario y la lógica para permitir al usuario responder o reject() la llamada.

Llamar por teléfono

Si el usuario decide hacer una llamada, lo manejaremos en el método callPhone() método. Por ejemplo, si nuestro método fue llamado así:

client.callPhone("14155550100", callback)

A continuación, el client.callPhone(phoneNumber, callback) método en el Nexmo Stitch Android SDK utilizará la API de Stitch para hacer GET una solicitud a su url de respuesta https://your-project-name.cloudfunctions.net/answer con los siguientes parámetros de consulta:

?from=16625461410\ &to=14155550100\ &conversation_uuid=CON-4e977dab-2abc-42b5-bf64-d468d4763e54\ &uuid=0666edbe58077d826944a7c1913da2b0

Podemos utilizar el parámetro to para devolver dinámicamente una NCCO que indique a Nexmo a qué número de teléfono debe llamar. La API de Stitch verá la siguiente respuesta NCCO:

[  
   {  
      "action":"talk",
      "text":"Thank you for calling, you are now being connected."
   },
   {  
      "action":"connect",
      "from":"12013753230",
      "endpoint":[  
         {  
            "type":"phone",
            "number":"14155550100"
         }
      ]
   }
]

En este caso, el from es el número que hemos alquilado a Nexmo y establecido como el nexmo.from_number con las variables de configuración de Firebase. El valor en number en el endpoint array es el número al que nuestro usuario quiere llamar.

Pruébelo usted mismo

El repositorio de este proyecto de ejemplo contiene el código fuente tanto de las funciones Firebase como de la aplicación de ejemplo para Android. Clona el proyecto para comprobarlo.

¿Y ahora qué?

Ahora que ha aprendido a hacer y recibir llamadas telefónicas con Nexmo In-App Voice también puedes aprender más sobre In-App Messaging (Mensajería In-App).

Para obtener información más detallada sobre el SDK para Android de Nexmo Stitch, puede leer la documentación del SDK en línea.

Nuestro Voice API también ofrece otras posibilidades más allá de la simple conexión y recepción de llamadas. Visite nuestra documentación para obtener más información sobre la grabación de llamadas, la reproducción de secuencias de audio en las llamadas y mucho más.

Compartir:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Chris GuzmanAntiguos alumnos de Vonage

Chris es Developer Advocate en Nexmo, donde ayuda a los desarrolladores a utilizar su plataforma global de comunicaciones. Cuando no está en conferencias, se le puede encontrar vagando por el mundo.