400 likes | 536 Views
Integración nativa con html5. José Roberto ardila García 12 hit combo!. Porque es necesaria la integración nativa?. Hagamos un repaso de las características que nos ofrece PhoneGap Acelerómetro Cámara Brújula Acceso a contactos Archivos Geolocalización Media Network
E N D
Integración nativa con html5 José Roberto ardila García 12 hit combo!
Porque es necesaria la integración nativa? • Hagamos un repaso de las características que nos ofrece PhoneGap • Acelerómetro • Cámara • Brújula • Acceso a contactos • Archivos • Geolocalización • Media • Network • Notificaciones (alertas, sonidos, vibraciones).
Pero que ocurre si se necesita o aparece una nueva característica nueva o diferente en los dispositivos Android? • NFC • iBeacons (Comunicación vía Bluetooth) • Widgets • TextToSpeech • VoiceTyping • Reutilizar código o Activities que realizaban operaciones específicas y puntuales (por ejemplo enviar correos)…
Que ocurre si PhoneGap no ofrece soporte para ello…. • Llorar? • Esperar a que en algún momento phonegap ofrezca soporte para esas características? • Ensuciarse las manos y extender de alguna forma la funcionalidad de phonegap para dar soporte a las características deseadas…
PhoneGapPlugins • Por medio de los “plugins” es posible extender las funcionalidades de phonegap. • A través de los plugins es posible acceder a características nativas de los dispositivos • Phonegap utiliza ese concepto para acceder a las características nativas previamente mencionadas. • Los plugins son desarrollados en código nativo de la plataforma (en el caso de Android: java)
Entendiendo la estructura de plugins nativos de phonegap • Los plugin tienen 2 partes: una interfaz basada en JavaScript que puede accederse desde la aplicación PhoneGap (y que será utilizada en todas las plataformas) y su correspondiente clase nativa que realizará las operaciones necesarias en código nativo. • La interfaz en JavaScript invocará al código nativo utilizando el método Cordova.exec, el cual invocará a un método Execute presente en las clases nativas.
El método Cordova.exec • cordova.exec(successCallback, failureCallback, class, method, [arguments]); • successCallback: será la función que se quiera ejecutar cuando el resultado de la invocación sea satisfactorio. • failureCallback: será la función a ejecutar cuando el resultado de la invocación no sea satisfactorio.
El método Cordova.exec • cordova.exec(successCallback, failureCallback, class, method, [arguments]); • class: será el nombre de la clase de nuestro código nativo. • method: será el nombre de la acción que se va a tener en cuenta en el método "execute" de la clase anterior que queremos invocar. • [arguments]]: será un array, generalmente en formato JSON, donde se le pasan todos los parámetros de entrada al método invocado.
Creación de nuestro primer plugin • Creamos un nuevo proyecto PhoneGap (offline) y lo importamos a Eclipse: • $ cordovacreate C:\MyFirstPlugin com.unal.pluginsCustomPluginActivity • $cd C:\MyFirstPlugin • $cordovaplatformaddandroid
Creación de Nuestra Clase Nativa • Creamos una nueva clase “HelloPlugin” que extienda de org.apache.cordova.CordovaPlugin • En esta clase irán las operaciones nativas que necesitemos ejecutar
public boolean execute(String action, CordovaArgsargs, CallbackContextcallbackContext) throws JSONException • { • booleanvalidAction = true; • Log.d("Plugin ejecutandoacción:",action); • if (action.equals("nativeAction")) • { • callbackContext.success(args.getString(0)); • } • else • { • validAction= false; • } • returnvalidAction; • }
Registrar el nuevo plugin: • En nuestro archivo res/xml/config.xml registramos nuestro nuevo plugin, dentro de los tags “widget”. <featurename="HelloPlugin"> <paramname="android-package" value="com.unal.plugins.plugin.HelloPlugin" /> </feature>
<!DOCTYPE html> <html> <head> <title>Hola Plugin</title> </head> <body> <h1>Prueba del nuevo Plugin!</h1> <buttononclick="callNativePlugin('success');">Click para invocar al PluginNativo con SUCCESS!</button> <buttononclick="callNativePlugin('error');">Click para invocar al PluginNativo con ERROR!</button> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/HelloPlugin.js"></script> </body> </html> • Modificamos nuestro index.xml para usar nuestro nuevo plugin:
y de los callbacks correspondientes… functioncallNativePlugin( returnSuccess ) { HelloPlugin.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess ); } functionnativePluginResultHandler (result) { alert("SUCCESS: \r\n"+result ); } functionnativePluginErrorHandler (error) { alert("ERROR: \r\n"+error ); }
Creamos nuestro archivo HelloPlugin.js encargado de contener los métodos de ejecución del plugin nativo…. varHelloPlugin = { callNativeFunction: function (success, fail, resultType) { returncordova.exec( success, fail, "HelloPlugin", "nativeAction", [resultType]); } };
Creación de Una Nueva Clase NativaPara invocar una Agenda Nativa • Creamos una nueva clase “CalendarPlugin” que extienda de org.apache.cordova.CordovaPlugin • En esta clase irán las operaciones nativas que necesitemos ejecutar
publicclassCalendarPluginextendsCordovaPlugin { publicstatic final String ACTION_ADD_CALENDAR_ENTRY = "addCalendarEntry"; @Override publicbooleanexecute(Stringaction, JSONArrayargs, CallbackContextcallbackContext) throwsJSONException { try { if (ACTION_ADD_CALENDAR_ENTRY.equals(action)) {
Creación del Calendar nativo (con los parámetros traídos desde phonegap) • Ya que estamos trabajando de forma nativa podemos invocar un Activity externo de la misma forma que haríamos normalmente. • Utilizamos un intentIntent.ACTION_EDIT para crear la agenda. • Los parámetros que necesitamos para crear la agenda serán datos traídos desde phonegap. • Estos parámetros vendrán en formato JSON.
JSONObjectarg_object = args.getJSONObject(0); IntentcalIntent = new Intent(Intent.ACTION_EDIT) .setType("vnd.android.cursor.item/event") .putExtra("beginTime", arg_object.getLong("startTimeMillis")) .putExtra("endTime", arg_object.getLong("endTimeMillis")) .putExtra("title", arg_object.getString("title")) .putExtra("description", arg_object.getString("description")) .putExtra("eventLocation", arg_object.getString("eventLocation")); this.cordova.getActivity().startActivity(calIntent); callbackContext.success(); return true;
} • callbackContext.error("Invalidaction"); • return false; • } • catch(Exceptione) • { • System.err.println("Exception: " + e.getMessage()); • callbackContext.error(e.getMessage()); • return false; • } • }
Podemos agregar múltiples plugins nativos a una misma aplicación <featurename="HelloPlugin"> <paramname="android-package" value="com.unal.plugins.plugin.HelloPlugin" /> </feature> <featurename="CalendarPlugin"> <paramname="android-package" value="com.unal.plugins.plugin.CalendarPlugin" /> </feature>
Creamos un archivo llamado CalendarPlugin.js y una función createEvent: varcalendarPlugin = { createEvent: function(title, location, notes, startDate, endDate, successCallback, errorCallback) { cordova.exec( successCallback, errorCallback, 'CalendarPlugin', 'addCalendarEntry', [{"title": title, "description": notes, "eventLocation": location, "startTimeMillis": startDate.getTime(), "endTimeMillis": endDate.getTime() }] ); } }
functionaddToCal() { varstartDate = new Date("July 19, 2013 8:00:00"); varendDate = new Date("July 19, 2013 18:00:00"); var notes = “llegar a tiempo al evento(desde Android)"; vartitle = "PhoneGap Day"; varlocation = "Portland, OR"; var notes = “llegar a tiempo!"; varsuccess = function() { alert(“exito"); }; var error = function(message) { alert(“error! " + message); }; calendarPlugin.createEvent(title, location, notes, startDate, endDate, success, error); } • Con este método es que inicializamos los datos de nuestra agenda (este código también va en el archivo CalendarPlugin.js)
<!DOCTYPE html> <html> <head> <title>Hola Plugin</title> </head> <body> <h1>Prueba del nuevo Plugin!</h1> <buttononclick="callNativePlugin('success');">Click para invocar al PluginNativo con SUCCESS!</button> <buttononclick="callNativePlugin('error');">Click para invocar al PluginNativo con ERROR!</button> <buttononclick="addToCal();">Click para crear una agenda </button> <script type="text/javascript" src="js/CalendarPlugin.js"></script> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/HelloPlugin.js"></script> </body> </html> • Podemos agregar a nuestra página ya existente el nuevo plugin…
Agregar Text To Speech • Creamos una nueva clase “TTSPlugin” que extienda de org.apache.cordova.CordovaPlugin • En esta clase irán las operaciones nativas que necesitemos ejecutar • Este es un ejemplo de como utilizar datos que se reciben desde PhoneGap.
En esta ocasión utilizaremos 2 acciones una para iniciar el sistema TTS y otro para ejecutar la acción de conversión de texto a sonido, de ahí que declararemos las siguientes variables globales: public static final String ACTION_NEW_TTS_INIT = "textToSpeechInit"; public static final String ACTION_NEW_TTS_TALK = "textToSpeechTalk"; TextToSpeechttobj;
Debido a que las operaciones TTS son bastante exigente debemos utilizar multi-threading, esto nos obliga a que algunos parámetros tengan que ser declaradas como final: @Override public boolean execute(String action, final JSONArrayargs, final CallbackContextcallbackContext) throws JSONException {
if (ACTION_NEW_TTS_INIT.equals(action)) • { • cordova.getThreadPool().execute(new Runnable() { • publicvoid run() • { • if(ttobj == null) • { • ttobj=new TextToSpeech(cordova.getActivity().getApplicationContext(), • new TextToSpeech.OnInitListener() { • @Override • publicvoidonInit(int status) { • if(status != TextToSpeech.ERROR){ • ttobj.setLanguage(Locale.US); • } • } • }); • } • } • }); • return true; • }
elseif(ACTION_NEW_TTS_TALK.equals(action)) { cordova.getThreadPool().execute(new Runnable() { publicvoid run() { try { ttobj.speak(args.getString(0), TextToSpeech.QUEUE_FLUSH, null); callbackContext.success(); } catch(Exceptione) { callbackContext.error(e.getMessage()); } } }); return true; } else{ return false; }
<featurename="TTSPlugin"> <paramname="android-package" value="com.unal.plugins.plugin.TTSPlugin" /> </feature> • Agregamos nuestro plugin (en res/xml/config.xml) • y creamos un nuevo archivo JavaScript llamado TTSPlugin.js varTTSPlugin = { callTTSInitFunction: function (success, fail, resultType) { returncordova.exec( success, fail, "TTSPlugin", "textToSpeechInit", [resultType]); }, callTTSTalkFunction: function (success, fail, resultType) { returncordova.exec( success, fail, "TTSPlugin", "textToSpeechTalk", [resultType]); } };
functioncallTTSInitPlugin(returnSuccess) { TTSPlugin.callTTSInitFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess); } functioncallTTSTalkPlugin( returnSuccess ) { TTSPlugin.callTTSTalkFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess ); } functionnativePluginResultHandler (result) { alert("SUCCESS: \r\n"+result ); } functionnativePluginErrorHandler (error) { alert("ERROR: \r\n"+error ); } • Agregamos las funciones de callback y las que llamaremos de nuestro código:
var app = { // Application Constructor initialize: function() { this.bindEvents(); }, bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, onDeviceReady: function() { callTTSInitPlugin('inicia'); }, }; • Modificamos nuestro archivo index.js para que quede así (de esta forma inicializamos el sistema TTS al cargar la página):
Para facilitar la manipulación de datos, utilizaremos jquery, para esto descargaremos el archivo JavaScript de jquery desde: • http://jquery.com/download/ • y lo copiaremos en nuestra carpeta assets/www/js
<div id="landmark-1" onsubmit="callTTSTalkPlugin($('#title').val());"> <form> <label for="title">TTS:</label> <input id="title" name="title" type="text" /> <input type="submit" value="Click para TTS"> </form> </div> <script type="text/javascript" src="js/index.js"></script> <script type="text/javascript" src="js/TTSPlugin.js"></script> <script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript"> app.initialize(); </script> • Agregaremos a nuestro archivo index.html lo siguiente:
Agregar Text To Speech • Creamos una nueva clase “STTPlugin” que extienda de org.apache.cordova.CordovaPlugin • En esta clase irán las operaciones nativas que necesitemos ejecutar • Este es un ejemplo de como utilizar datos que se reciben desde PhoneGap.
public static final String ACTION_NEW_STT_TALK = "SpeechToTextTalk"; • CallbackContextcallbackContext; • protected static final intRESULT_SPEECH = 1; • @Override • public boolean execute(String action, JSONArrayargs, CallbackContextcallbackContext) throws JSONException • { • this.callbackContext= callbackContext; • if(ACTION_NEW_STT_TALK.equals(action)) • { • Intentintent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); • intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US"); • this.cordova.getActivity().startActivityForResult(intent, RESULT_SPEECH); • return true; • } • else • { • returnfalse; • } • }
publicvoidonActivityResult(intrequestCode, intresultCode, Intent data) { switch (requestCode) { case RESULT_SPEECH: if (resultCode == android.app.Activity.RESULT_OK && null != data) { ArrayList<String> text = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); callbackContext.success(text.get(0)); } else { //code launched in case of error Stringmessage=data.getStringExtra("result"); callbackContext.error(message); } break; default: break; } }