lunes, 13 de mayo de 2013

Cordova y Phonegap ¿como crear Plugins?


Plugins en Phonegap

Los plugins en Phonegap (o Cordova) son el puente para conectar nuestra aplicación Phonegap con la plataforma nativa del dispositivo (ya sea Android, iOS, Blackberry, Windows Phone, etc.). Los plugins para lograrlo se componen de:
-una interface en Javascript común a todas las plataformas (en este ejemplo SamplePlug.js)
-la llamada desde el HTML (en este ejemplo, inserta en index.html)
-implementaciones nativas propias de cada plataforma (en este caso Android, el archivo Echo.java)
Árbol de directorios necesarios para los plugins de Cordova
Árbol de directorios necesarios para los plugins de Cordova
NB.- Este tutorial se basa en la documentación oficial de Cordova sobre la creación de plugins, aunque tratando de hacerla lo más sencilla y entendible posible. Debe señalarse también que el procedimiento de ceración de plugins es muy diferente desde la versión Cordova 2.2.

Interface en Javascript

La clave de la comunicación entre PhoneGap y el entorno nativo es la función cordova.exec:
exec(<successFunction>, <failFunction>, <service>, <action>, [<args>]);
Es decir:
cordova.exec(
function(winParam) {},
function(error) {},
“service”,
“action”,
[Opcional Arguments]
);
donde:
function(winParam) {} – La function a que se llama si la llamada exec culmina con éxito (admite parámetros)
function(error) {} - La function a que se llama si la llamada exec culmina sin éxito (admite parámetros)
“service” – El nombre del servicio a llamar en la parte nativa. Este servicio estará mapeado a una clase nativa.
“action” – El nombre de la acción a llamar. Este nombre lo recibe la clase nativa que recibe la llamada exec, y se mapea con un método de clase.
[/* arguments */] – Los diversos argumentos que deban pasarse al entorno native.
Siguiendo el ejemplo de echo de la pàgina de Cordova, debemos escribir esto en nuestro archivo .js (en el ejemplo que proponemos SamplePlug.js):
123456789
window.echo = function(str, callback) {
cordova.exec(
callback,
function(err) { callback('Nothing to echo.'); },
"Echo",
"echo",
[str]
);
};
Como vemos, se relaciona el plugin a window, específicamente a la función echo.  Aquí llamamos al servicio Echo, pidiendo la acción echo, y pasando un array de argumentos conteniendo el echo string, que es el parámetro que toma la window.echo function. El success callback que se pasa a exec es simplemente la función callback que toma window.echo. En el error, si la parte nativa nos devuelve un error callback, invocamos el callback y le pasamos una string por defecto.

Llamada desde el HTML

A este plugin, pues, lo llamaremos desde el html de esta manera:
123
window.echo("echome", function(echoValue) {
alert(echoValue == "echome"); // should alert true.
});
donde: enviamos un string “echome”, y la función que debe ir al callback.
Para verlo más claramente, este sería un ejemplo de index.html con llamada al procedimiento puente:
123456789101112131415161718192021222324
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no, width=device-width, target-densitydpi=device-dpi" />
<title>PhoneGap</title>
<script type="text/javascript" charset="utf-8" src="cordova-2.5.0.js"></script>
<script type="text/javascript" charset="utf-8" src="SamplePlug.js"></script>
<script type="text/javascript" charset="utf-8">
document.addEventListener("deviceready", onDeviceReady, false);
console.log("AQUI 1");
function onDeviceReady() {
window.echo("echome", function(echoValue) {
console.log("AQUI 2");
navigator.notification.alert(echoValue == "echome"); // should alert true.
});
}
</script>
</head>
<body>
 
</body>
</html>
view rawindex.htmlThis Gist brought to you by GitHub.
 

La clase Android

En este tutorial vamos a utilizar una llamada a código de Android como ejemplo. Sin embargo, en la página de la documentación oficial de Cordova sobre creación de pluginspueden accederse a ejemplos para el resto de plataformas.
Un plugin para PhoneGap-Android consiste en al menos una clase Java que extiende a la clase CordovaPlugin (ver este ejemplo de implementación de plugins para versiones de Cordova anteriores a 2.2), extendiendo, pues, alguno de sus métodos execute.

MAPEAR EL PLUGIN EN CONFIG.XML

El primer paso para la creación sería mapear el plugin en el proyecto Phonegap, para que la parte de Phonegap conozca la existencia de este neuvo plugin. Para ello, hay que introducir la siguiente línea en res/xml/config.xml:
<plugin name=”<service_name>” value=”<full_name_including_namespace>”/>
donde: El <service_name> o nombre servicio debe coincidir con el que se usa en la llamada exec de Javascript, y el value o valor debe coincidir con la ruta completa de la clase (package + clase). Esta sería la implementación en nuestro ejemplo:
Mapeo del plugin en el proyecto Cordova
Mapeo del plugin en el proyecto Cordova

LA CLASE ANDROID

El siguiente paso es ya crear la clase. Para ello nos situamos encima del package de neustra aplicación y, con el botón derecho, seleccionamos nueva Clase:
Crear una clase para Android
Crear una clase para Android
En la nueva clase debemos ponerle el nombre del plucgin al que llamamos(en este caso Echo) y especificar (a partir de Cordova 2.2) que heredamos de la superclase
org.apache.cordova.api.CordovaPlugin
Crear una clase para Android
Crear una clase para Android
Lo que se pasa al plugin a través de la función exec de javascript pasa a la clase execute de la clase java:
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (“beep”.equals(action)) {
this.beep(args.getLong(0));
callbackContext.success();
return true;
}
return false; // Returning false results in a “MethodNotFound” error. }
donde: se compara el valor de la acción llamada para ejecutar el método; se llama a un método privado que ejectua lo que tenga que ejecutar a nivel nativo, pasando los argumentos que haya, si los hay; y se devuelve true or false según haya o no tenido éxito el procedimiento. (Para un ejemplo más concreto de relación con el thread ui o no bloquaear el WebCore thread, mirar la documentación)
Esta sería la implementación del plugin de ejemplo:
123456789101112131415161718192021222324252627
package org.apache.cordova.plugin;
 
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
public class Echo extends CordovaPlugin {
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("echo")) {
String message = args.getString(0);
this.echo(message, callbackContext);
return true;
}
return false;
}
 
private void echo(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
view rawplugin.javaThis Gist brought to you by GitHub.
donde:
-Extendemos la clase CordovaPlugin
-Sobreescribimos el método execute() para recibir los mensajes de exec()
-Comparamos el nombre de la acción para lanzar el método (cualquier otra llamada dará error, devolviendo false, lo que el Javascript leerá como un error callback)
-Tomamos el mensaje: si es nulo, invocamos el callbackContext.error(), si no, el success. Si es correcto, se invoca la función success callback del javascript, pasando también el parámetro message a la función success callback en javascript.

No hay comentarios:

Publicar un comentario