Apache Cordova: Tips y notas para comenzar a crear apps web y móviles

Apache Cordova es un framework que nos permite desarrollar frontend multiplataforma insertando un webview en el entorno móvil y de escritorio, a continuación te comparto tips y notas, comandos, códigos importantes y explicaciones en qué situaciones emplearlos.

Requerimientos, instalación de Apache Cordova y creación de proyecto

Requerimientos para utilizar el framework y desarrollar apps Android:

Instalación de Apache Cordova, como comenté en el anterior listado en la primera viñeta, luego que instales NodeJS tendrás que descargar Cordova, en general te recomiendo visites la documentación https://cordova.apache.org/, aunque aquí te dejo los comandos:

npm install -g cordova

Si notas problemas para ejecutar este comando puede que sea debido a variables de entorno, normalmente la consola mostrará un error de comando no reconocido, de hecho como mencioné en la segunda viñeta de la lista anterior la configuración de variables de entorno va a ser algo bastante habitual para preparar este framework para móvil.

Si por otra parte no marco errores de desconocimiento de comandos y realizo la descarga de manera correcta podemos comenzar con nuestro primer proyecto, puedes leer la documentación https://cordova.apache.org/docs/en/latest/guide/cli/index.html, abrimos terminal y nos aseguramos de estar posicionados en el lugar donde tendremos todos nuestros proyectos Cordova.

cordova create carpetaProyecto com.example.miapp MiApp

He reescrito el comando para que podamos identificar mejor cada elemento que se creará.

Continuando en la terminal luego de que terminé de crear el proyecto, nos posicionamos en la carpeta.

cd carpetaProyecto

Vamos a añadir las plataformas browser y android, haciendo la espera en cada comando.

cordova platform add browser
cordova platform add android

Ejecutamos este comando para asegurarnos que estamos listos para desplegar web y móvil.

cordova requirements

El resultado nos permitirá interpretar si contamos con los requerimientos instalados, de ser así ya podemos comenzar a desarrollar.

En este punto ya no será necesario ejecutar los comandos anteriores siempre que queramos retomar el proyecto, abrimos en un editor de código la carpeta de nuestro proyecto y tenemos en cuenta que nuestro frontend está ubicado en la carpeta www, es muy importante no utilizar CDNs o librerías externas, en este caso tendremos que descargarlas y colocarlas en nuestra carpeta frontend, con fines de pruebas y exploración dejemos el index.html sin eliminar etiquetas, podemos comentar el style.css con la excepción de los scripts posicionados al final, el div que viene por default yo le aplico un style display none, si gustas puedes eliminarlo, solamente tienes que modificar el index.js para no mandar a llamar ese div y no suelte un error, evitemos a toda costa errores de consola, y colocar directamente JavaScript en el HTML por políticas de seguridad.

Uso del framework

Una vez que hemos realizado la instalación y exploración básica de Apache Cordova, ya podemos ir descargando y haciendo referencia a librerías, añadir HTML, añadir scripts y referenciarlos (Nada de JavaScript dentro del HTML), haremos despliegues web hasta tener una versión final, para ello cada cambio que hagamos debemos usar el comando:

cordova run browser

Si es algo lento te recomiendo trabajar el frontend con XAMPP, WAMPP, Apache o Nginx, respetando el index.html generado en Apache Cordova, cuando tengas una versión final trasladala al proyecto Apache Cordova y ejecuta en web.

Conexión de frontend y backend

En nuestro HTML comentamos la etiqueta meta Content-Security-Policy y añadimos esta nueva etiqueta:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; connect-src 'self' https://mitunnel.com; style-src 'self' 'unsafe-inline'; media-src *;">

Donde mitunnel.com deberás sustituirlo por tu hosting o si no cuentas con uno puedes optar precisamente por esa técnica, tunnels, que nos permitirá levantar backend en una URL temporal, tenemos las siguiente alternativas Cloudflared Tunnels https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/ mediante el comando:

winget install --id Cloudflare.cloudflared

Y ngrok https://ngrok.com/.

Si acaso vas a cargar vistas previas de imágenes a subir en lugar de usar la anterior meta Content-Security-Policy usa la siguiente:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval' blob:; img-src 'self' data: blob:; connect-src 'self' https://mitunnel.com; style-src 'self' 'unsafe-inline'; media-src * blob:;">

Para el tema Android es necesario el plugin cordova-plugin-advanced-http el cuál podemos agregar al proyecto:

cordova plugin add cordova-plugin-advanced-http

En nuestro proyecto nos vamos a platforms/android/app/src/main/AndroidManifest.xml y añadimos el siguiente atributo a la etiqueta application:

android:usesCleartextTraffic="true"

Push Notifications con cordova-plugin-firebasex

Firebase

Necesitamos crear a la par una proyecto en Firebase https://console.firebase.google.com/u/0/?hl=es-419, no partimos de ejemplos, empezamos con algo nuevo. Recomiendo consistencia en el uso de nombres: Proyecto Cordova hellotres, proyecto Firebase hellotres, si te guías de las documentaciones respectivas notarás donde usar camel y lower case, pero de momento tomamos como referencias ese ejemplo.

Una vez creado el proyecto, dentro de él nos vamos a la opción de Configuración > General, en ese apartado buscamos la sección Tus apps, nos encontraremos principalmente con las plataformas IOS, Android y Web, seleccionaremos Android.

Al seleccionar la plataforma Android, nos tocará colocar el nombre del package, el cual si no recordamos cuál es, podemos ubicarlo en nuestro proyecto Cordova en el archivo config.xml, realmente el paso 1 es el más importante, el paso 2 también lo es, pero si damos siguiente sin hacer nada, posteriormente podemos volver a descargar el google-services.json, que precisamente lo necesitamos en nuestro proyecto Cordova en platforms/android/app, cuidado con las limpiezas de proyectos (cordova clean), ya que puede borrar ese archivo, tengamos presente para volver a descargarlo en cada limpieza, los pasos 3 y 4 les damos siguiente sin ningún inconveniente, solo es información para las plataformas de desarrollo nativas.

En la anterior imagen apreciamos la gran ventaja de tener consistencia en los nombres de nuestros proyectos, se aprecia los datos Firebase paquete com.example.hellotres y nombre hellotres.

Si nos devolvemos al proyecto Configuración > General, en Tus apps, especificamente la app que creamos, nuevamente vemos la opción de descargar el google-services.json.

Cordova

Por un momento pausamos la configuración del proyecto Firebase y nos vamos al proyecto Cordova, necesitamos que el proyecto ya tenga el google-services.json en platforms/android/app, a día que hago la edición de este subtema Push Notifications, al hacer pruebas encuentro más conveniente descargar 2 plugins, dejo abajo los comandos.

cordova plugin add cordova-plugin-firebasex-core@latest
cordova plugin add cordova-plugin-firebasex-messaging@latest

Compilamos nuestra app, puede que en algunos casos existan problemas, recomiendo revisar que los nombres coincidan, que el google-services.json esté en platforms/android/app, también analizar el build con el argumento verbose.

cordova build android --verbose

Si todo fue bien, puede hacerse la instalación en emulador de la APK generada, antes de ejecutar damos los permisos para notificaciones de forma manual, una vez ejecutada a la par usamos el siguiente comando.

adb logcat | findstr Firebase

Si vemos que se detiene el log, volvemos a ejecutar ese comando, nos interesa encontrarnos con un log que diga refreshed token, copiamos la cadena de caracteres de en seguida, ya que nos servirá para hacer pruebas manuales.

Firebase y el servidor web (PHP)

En nuestra API debemos incluir la dependencia kreait/firebase-php, te dejo el comando composer, que debemos ejecutar dentro de una carpeta para descargar las librerías, para el ejemplo api/kreait-firebase-php.

composer require kreait/firebase-php

Volviendo a la raíz de la API, antes de los endpoints colocamos las siguientes líneas de código.

<?php

require_once "kreait-firebase-php/vendor/autoload.php";
$serviceAccountJson = json_decode('', true);
$firebase = (new Kreait\Firebase\Factory)->withServiceAccount($serviceAccountJson)->createMessaging();

En $serviceAccountJson, entre las comillas ”, va a ir nuestra clave privada, la cual podemos obtener en Firebase, volvemos a nuestro proyecto Firebase, en Configuración > Cuentas de servicio, nos aparecerán algunos ejemplos con otras tecnologías, aunque mis ejemplos son PHP no afecta que no aparezca porque solamente daremos clic en Generar nueva clave privada, generará un JSON, del cual extraemos el contenido para colocarlo en las comillas, cuidado porque se generará un nuevo archivo cada que pulsemos ese botón, a diferencia del google-service.json que siempre es el mismo de la app.

Colocada nuestra clave privada en las comillas ” mencionadas ya podremos enviar Push Notifications y es tan simple con las siguientes 2 líneas.

<?php

$message = array(
    "token" => "",
    "notification" => array(
        "title" => "",
        "body" => ""
    )
);

$firebase->send($message);

En esta parte podemos hacer pruebas manuales, designar un endpoint exclusivo para las pruebas, el refreshed token obtenido previamente lo colocamos en el arreglo en la propiedad token, la propiedad notification contiene otro arreglo que son las propiedades de la notificación, el título y el mensaje.

Cordova y el servidor web

En este punto será importante el desarrollo de técnicas que nos permita identificar nuestro firebase token para ya no recurrir a adb log cat, en javascript, en nuestro index.js, como descargue parcialmente los plugins de Firebasex, hago uso del módulo específico FirebasexMessaging, el token lo almaceno en el localStorage para que persista y pueda registrarlo más adelante, en mi caso nombro al item helloFBToken.

function fb() {
    decoradorObtenerFBToken()

    window.FirebasexMessaging.onTokenRefresh(function (token) {
        localStorage.setItem("helloFBToken", token)
    }, function (error) {
        // Error al refrescar el Firebase Token
    })

    window.FirebasexMessaging.onMessageReceived(function (message) {
        let mensaje = (message.body || "Sin mensaje")

        fbOnPushNotification(mensaje)
    })

    window.FirebasexMessaging.onNotificationOpen(function (notification) {
        let mensaje = (notification.body)
                ||    (notification.notification ? notification.notification.body : "Sin mensaje")

        fbOnPushNotification(mensaje)
    })
}

function obtenerFBToken() {
    window.FirebasexMessaging.getToken(function (token) {
        if (token) {
            console.log("Firebase Token", token)
            localStorage.setItem("helloFBToken", token)

            return
        }
    }, function (error) {
        // Error al obtener Firebase Token
    })
}

function decoradorObtenerFBToken() {
    window.FirebasexMessaging.hasPermission(function (granted) {
        if (!granted) {
            window.FirebasexMessaging.grantPermission(function () {
                obtenerFBToken()
            }, function (error) {
                // Error al solicitar permiso
            })

            return
        }

        obtenerFBToken()
    })
}

function esperarFirebasePlugin() {
    if (window.FirebasexMessaging) {
        console.log("FirebasePlugin disponible, obteniendo token...")
        fb()
    } else {
        console.log("FirebasePlugin aún no disponible, reintentando...")
        setTimeout(esperarFirebasePlugin, 1000)
    }
}

let fbOnPushNotification = function (mensaje) {
    alert(mensaje)
}

esperarFirebasePlugin()

Definimos una función que podemos redefinir en otras páginas dentro de nuestra app, para poder personalizar el que pasará cuando llegue una push y estemos en cierto módulo.

¿Qué sigue?

Registrar los tokens. El de cada dispositivo se almacenará en el localStorage, no necesariamente debe ir en una base de datos, pero es lo más optimo, ya sea en una tabla para que un usuario tenga multiples dispositivos o como mínimo en la misma tabla de usuarios en un campo.

$.post(API + "?registrarFBToken", {FBToken: localStorage.getItem("helloFBToken")})

Consultar los tokens. Cada que sea necesario enviar un push notification se aprovecha al máximo si están en base de datos, porque desde web cada que hagamos el movimiento específico que notificará consulta los tokens que corresponden.

<?php

foreach ($tokens as $token) {
    $message = array(
        "token" => $token,
        "notification" => array(
            "title" => "Nueva notificación",
            "body" => "Han eliminado un registro."
        )
    );

    $firebase->send($message);
}

Continua en edición.

Comments

No comments yet. Why don’t you start the discussion?

Deja tus comentarios