Porting da iPhone ad Android – plist

5 Apr

Il presente è solo il primo di una serie di articoli che cerca di mettere a fuoco i problemi pratici che devono essere affrontati da un soggetto che intenda portare in Android un’app inizialmente scritta per iOS; partiremo da un problema molto semplice che chiunque si troverà (più prima che poi) ad affrontare: lo storage di piccoli volumi di dati – tipicamente, di preferenze o di parametri di configurazione.

In iOS esiste una struttura specifica per questo genere di dati: la property list. Una property list (confidenzialmente, plist) è idealmente un dizionario, ovvero un insieme di coppie key-value, rappresentato per mezzo di un file XML conforme al DTD http://www.apple.com/DTDs/PropertyList-1.0.dtd. Questo strumento di organizzazione dei dati è molto comodo in quanto consente di avere nel campo value un oggetto complesso (un array, o un altro dictionary) rendendo ricorsiva la propria struttura.

Android mette a disposizione un formalismo XML analogo (ma ovviamente diverso) e una ricca scelta di API indirizzate proprio alla gestione di questo genere di informazione persistente. Queste API sono basate sulla classe android.contentSharedPreferences e su tutta una serie di GUI widgets già predisposti alla loro visualizzazione ed editazione. Sicuramente un set di API assai più specializzata della controparte iOS, che manca totalmente delle seconde. Tuttavia, la struttura di Android è “piatta”: l’oggetto più complesso associabile a una chiave è un semplice Set<String>.

Ecco perché nel portare un’applicazione da iOS ad Android uno sviluppatore può essere tentato di trasportare sulla nuova piattaforma le sue familiari property list. Le ragioni di questa tentazione sono:

1. Strutturazione dei dati versatile e potente
2. Semplicità d’uso: un solo file XML da gestire, condiviso tra le due piattaforme.
3. “Design reuse” delle classi di accesso e gestione delle plist

Portare le plist significa implementare in Java i meccanismi di serializzazione e deserializzazione delle stesse e fornire uno strumento di accesso ai suoi elementi. Nel seguito ci occuperemo solo della deserializzazione e dell’accesso, trascurando la funzionalità di aggiornamento e quindi di serializzazione.

Quello che serve per realizzare il porting delle property list è un parser XML SAX e uno strato che trasformi gli elementi XML nei POJO necessari per la nostra applicazione. Diciamo subito che il mapping tra le classi sarà realizzato secondo la seguente tabella:

iOS Android
NSDictionary java.util.HashMap
NSArray java.util.ArrayList
NSNumber java.lang.Integer
NSString java.lang.String
BOOL java.lang.Boolean
NSData java.lang.Object
NSDate java.util.String

Per la semplicità dello schema, e per il fatto che proviene da una plist effettivamente in esercizio, non ci occuperemo minimamente dei problemi di validazione del testo XML in input.

Per la nostra realizzazione, ci siamo serviti:

Trasformare una plist nell’object graph corrispondente è davvero semplice:
Partiamo dalla seguente plist:

una property list di esempio

Esempio tratto dall'app "Ricette al Contrario"

Ecco il codice necessario (e più che sufficiente!):

public static void main( String args[] )
{
    try {
        System.out.println( System.getProperty( "user.dir" ) );
        File plistFile = new File( "prefs.plist");
        InputStream fis = new FileInputStream( plistFile );
        XMLPropertyListConfiguration conf = new XMLPropertyListConfiguration( fis );
        HashMap plist = conf.getPlist();
        System.out.println( "plist has " + plist.size() + " elements" );
        Iterator it = plist.keySet().iterator();
        while( it.hasNext() )
        {
            String key = (String) it.next();
            Object hm = plist.get( key );
            System.out.println( "Key " + key + " object is:"
                + hm.getClass().getName());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Per ottenere l’intera plist, si deve invocare il metodo getPlist(); questo metodo restituisce sempre la HashMap di livello più alto. E’ anche possibile agganciare un livello qualsiasi della gerarchia. In tal caso si usa il metodo XMLPropertyListConfiguration.this.getConfiguration(String elemName).
Ad esempio:

 		XMLPropertyListConfiguration conf = new XMLPropertyListConfiguration( fis );
		Boolean b = (Boolean) conf.getConfigurationObject( "customSort" );
		System.out.println( "customsort is : " + b );

		b = (Boolean) conf.getConfigurationObject( "defaultIngredients.aglio" );
		System.out.println( "defaultIngredients.aglio is : " + b );


In definitiva, è un peccato rinunciare la potenza espressiva delle plist una volta effettuata la transizione nell’ambiente Android, tanto più che lo sforzo per ritrovarsela intatta è davvero minimo.

(Download della classe XMLPropertyListConfiguration)

Il presente è solo il primo di una serie di articoli che cerca di mettere a fuoco i problemi pratici che devono essere affrontati da un soggetto che intenda portare in Android un’app inizialmente scritta per iOS; partiremo da un problema molto semplice che chiunque si troverà (più prima che poi) ad affrontare: lo storage di piccoli volumi di dati – tipicamente, di preferenze o di parametri di configurazione.

In iOS esiste una struttura specifica per questo genere di dati: la property list. Una property list (confidenzialmente, plist) è idealmente un dizionario, ovvero un insieme di coppie key-value, rappresentato per mezzo di un file XML conforme al DTD http://www.apple.com/DTDs/PropertyList-1.0.dtd. Questo strumento di organizzazione dei dati è molto comodo in quanto consente di avere nel campo value un oggetto complesso (un array, o un altro dictionary) rendendo ricorsiva la propria struttura.

Android mette a disposizione un formalismo XML analogo (ma ovviamente diverso) e una ricca scelta di API indirizzate proprio alla gestione di questo genere di informazione persistente. Queste API sono basate sulla classe android.contentSharedPreferences e su tutta una serie di GUI widgets già predisposti alla loro visualizzazione ed editazione. Sicuramente un set di API assai più specializzata della controparte iOS, che manca totalmente delle seconde. Tuttavia, la struttura di Android è “piatta”: l’oggetto più complesso associabile a una chiave è un semplice Set<String>.

Ecco perché nel portare un’applicazione da iOS ad Android uno sviluppatore può essere tentato di trasportare sulla nuova piattaforma le sue familiari property list. Le ragioni di questa tentazione sono:

1. Strutturazione dei dati versatile e potente
2. Semplicità d’uso: un solo file XML da gestire, condiviso tra le due piattaforme.
3. “Design reuse” delle classi di accesso e gestione delle plist

Portare le plist significa implementare in Java i meccanismi di serializzazione e deserializzazione delle stesse e fornire uno strumento di accesso ai suoi elementi. Nel seguito ci occuperemo solo della deserializzazione e dell’accesso, trascurando la funzionalità di aggiornamento e quindi di serializzazione.

Quello che serve per realizzare il porting delle property list è un parser XML SAX e uno strato che trasformi gli elementi XML nei POJO necessari per la nostra applicazione. Diciamo subito che il mapping tra le classi sarà realizzato secondo la seguente tabella:

iOS Android
NSDictionary java.util.HashMap
NSArray java.util.ArrayList
NSNumber java.lang.Integer
NSString java.lang.String
BOOL java.lang.Boolean
NSData java.lang.Object
NSDate java.util.String

Per la semplicità dello schema, e per il fatto che proviene da una plist effettivamente in esercizio, non ci occuperemo minimamente dei problemi di validazione del testo XML in input.

Per la nostra realizzazione, ci siamo serviti:

Trasformare una plist nell’object graph corrispondente è davvero semplice:
Partiamo dalla seguente plist:

una property list di esempio

Esempio tratto dall'app "Ricette al Contrario"

Ecco il codice necessario (e più che sufficiente!):

public static void main( String args[] )
{
    try {
        System.out.println( System.getProperty( "user.dir" ) );
        File plistFile = new File( "prefs.plist");
        InputStream fis = new FileInputStream( plistFile );
        XMLPropertyListConfiguration conf = new XMLPropertyListConfiguration( fis );
        HashMap plist = conf.getPlist();
        System.out.println( "plist has " + plist.size() + " elements" );
        Iterator it = plist.keySet().iterator();
        while( it.hasNext() )
        {
            String key = (String) it.next();
            Object hm = plist.get( key );
            System.out.println( "Key " + key + " object is:"
                + hm.getClass().getName());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Per ottenere l’intera plist, si deve invocare il metodo getPlist(); questo metodo restituisce sempre la HashMap di livello più alto. E’ anche possibile agganciare un livello qualsiasi della gerarchia. In tal caso si usa il metodo XMLPropertyListConfiguration.this.getConfiguration(String elemName).
Ad esempio:

 		XMLPropertyListConfiguration conf = new XMLPropertyListConfiguration( fis );
		Boolean b = (Boolean) conf.getConfigurationObject( "customSort" );
		System.out.println( "customsort is : " + b );

		b = (Boolean) conf.getConfigurationObject( "defaultIngredients.aglio" );
		System.out.println( "defaultIngredients.aglio is : " + b );


In definitiva, è un peccato rinunciare la potenza espressiva delle plist una volta effettuata la transizione nell’ambiente Android, tanto più che lo sforzo per ritrovarsela intatta è davvero minimo.

(Download della classe XMLPropertyListConfiguration)

Annunci
%d blogger hanno fatto clic su Mi Piace per questo: