Creazione di un plugin per Apache Cordova
Di solito nello scegliere un framework per creare app mobile multipiattaforma ci si basa quasi esclusivamente sulla semplicità d’uso. In realtà la vera killer feature di questa tipologia di framework è un’altra: l’estendibilità attraverso plugin. Il motivo della centralità di questa caratteristica è presto detto: qualsiasi framework decideremo di utilizzare non potrà coprire tutte possibili funzionalità che ci mettono a disposizione gli SDK nativi. In questo post ci occuperemo di come creare un plugin Android e iOS per Apache Cordova: famoso framework per creazione di applicazioni ibride. Questo framework è alla base di di cui ho parlato in uno degli ultimi post.
Setup
Il primo passo per creare un nuovo plugin è quello di far sapere alla nostra applicazione Cordova dove poter trovare il plugin che andremo a sviluppare. Per fare questo modifichiamo il file fetch.json
all’interno della cartella plugins
come segue:
{ //...Altri plugin già presenti nell'applicazione "net.extrategy.cordova": { "source": { "type": "local", "path": "plugin-stub" } } }
net.extrategy.cordova
è l’id del nostro plugin. L’attributo source
indica che il plugin è locale al nostro progetto mentre path
ci dice che sarà presente nella cartella plugin-stub
.
Struttura di un plugin Cordova
Definizione
Tutte le proprietà di un plugin Cordova vengono definite all’interno del file plugin.xml
presente all’interno della root del plugin stesso. La configurazione base di un plugin è la seguente:
Stub Cordova Plugin Stub MIT e-xtrategy
Come potete vedere abbiamo definito un js-module
presente nel file stub.js
. Questi moduli rappresentano i bridge tra il mondo Cordova e il mondo nativo. L’utilizzo dell’elemento clobbers
ci permette di specificare a quale proprietà dell’oggetto window
sarà agganciato il nostro modulo. In questo caso infatti, per accedere alle funzionalità del modulo dovremmo utilizzare window.Stub
. Vediamo insieme il codice del nostro modulo: lo scopo del plugin sarà quello di effettuare due operazioni sulle stringhe, reverse e replicate.
module.exports = { reverse: function (input, successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "Stub", "reverse", [input]); }, replicate: function (input, successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "Stub", "replicate", [input]); } };
Come vedete ognuna delle funzioni non è altro che un wrapper della funzione cordova.exec
. Questa funzione è il cuore del bridge verso il nativo e accetta i seguenti parametri:
- Callback di success
- Callback di error
- Nome del modulo
- Azione da invocare
- Array di parametri
Android
Passiamo ora al primo dei due moduli nativi, quello per Android. Prima di analizzare il codice, vediamo insieme come cambia la configurazione all’interno del file config.xml
quando dobbiamo lavorare sulla piattaforma Google.
Come potete vedere dobbiamo definire nome e package della classe Java che comporrà il nostro modulo, di cui potete vedere il codice qui sotto:
package net.extrategy.cordova; import org.apache.cordova.*; import org.json.JSONArray; import org.json.JSONException; public class Stub extends CordovaPlugin { private String reverse(String input){ return new StringBuilder(input).reverse().toString(); } private String replicate(String input){ return input+input; } @Override public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException { String input = data.getString(0); if (action.equals("reverse")) { callbackContext.success(reverse(input)); return true; } else if (action.equals("replicate")) { callbackContext.success(replicate(input)); return true; }else { return false; } } }
Come vedete la parte Android del nostro plugin deve estendere la classe CordovaPlugin
e implementare il metodo execute
. Al suo interno il modulo mappa la action ricevuta in ingresso con i metodi reverse
e replicate
che implementano la vera business logic del modulo nativo.
iOS
Vediamo ora l’altra faccia delle medaglia, quella nativa iOS. In maniera analoga a quanto fatto in precedenza, partiamo dal file config.xml
:
Come potete vedere qui dobbiamo definire qual è il file di header e il suo relativo file di source. Analizziamo insieme il codice di entrambi i file:
Header
#import@interface Stub : CDVPlugin - (void) reverse:(CDVInvokedUrlCommand*)command; - (void) replicate:(CDVInvokedUrlCommand*)command; @end
Source
#import "Stub.h" @implementation Stub - (void)reverse:(CDVInvokedUrlCommand*)command { NSString* callbackId = [command callbackId]; NSString* input = [[command arguments] objectAtIndex:0]; NSMutableString *output = [NSMutableString string]; NSInteger charIndex = [input length]; while (charIndex > 0) { charIndex--; NSRange subStrRange = NSMakeRange(charIndex, 1); [output appendString:[input substringWithRange:subStrRange]]; } CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; [self success:result callbackId:callbackId]; } - (void)replicate:(CDVInvokedUrlCommand*)command { NSString* callbackId = [command callbackId]; NSString* input = [[command arguments] objectAtIndex:0]; NSString* output = [input stringByAppendingString:input]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; [self success:result callbackId:callbackId]; } @end
La cosa interessante da notare rispetto al modulo Android è la mancanza di boilerplate causata dal metodo execute
. Nel caso di iOS basta far sì che i metodi si chiamino esattamente come le action che ci vengono passate da cordova.exec
e il tutto funziona automaticamente.
Utilizzo
In questo prossimo esempio vediamo infine come utilizzare il nostro plugin.
Cordova Plugin stub Cordova plugin stub
Il risultato del nostro lavoro è il seguente:
Reverse di una stringa tramite un modulo nativo
Ora che abbiamo analizzato tutti gli elementi che compongono un plugin di Cordova possiamo desumerne il flusso di utilizzo:
- L’applicazione invoca uno dei metodi dell’oggetto
window.Stub
- Il modulo javascript invoca il metodo
cordova.exec
- Cordova invoca il modulo nativo Android o iOS
- Il risultato torna all’applicazione web tramite le callback
Conclusioni
Purtroppo l’estensione di Cordova tramite plugin è uno di quegli argomenti che non vengono mai trattati nei tutorial getting started e anche nella documentazione ufficiale viene solo accennato. Spero quindi che questa micro-introduzione all’argomento possa essere d’aiuto a tutti gli sviluppatori di applicazioni ibride. Chi vuole approfondire può trovare il codice di questo post su GitHub. Alla prossima.