Archivi tag: mobile

Decompilare applicazioni Android di ogni genere, dal dispositivo ai sorgenti

Qualche tempo fa scrissi due righe su come utilizzare l’adb per andarsi a leggere le cartelle private di un’applicazione Android installata sul proprio dispositivo, cosa molto utile per esempio quando si vuole leggere i dati contenuti in un database sqlite.

Quest’oggi invece mi sono tolto la curiosità di provare a tirarmi giù dal telefono varie applicazioni – scritte nei modi più disparati – e “strucinare” un minimo al loro interno giusto per capire quali sono gli strumenti di sviluppo più sicuri.

File apk partendo da un’app installata su un telefono Android

Come già detto nell’altro articolo l’adb nient’altro è che un bridge tra dispositivo e macchina di sviluppo, e lo si può trovare nel percorso android-sdk/platform-tools/adb, dove “android-sdk” è il percorso di installazione dell’sdk Android (la posizione dipende da cosa si utilizza per sviluppare: Android Studio, Xamarin, Titanium, Ionic, …).

Utilizzando l’adb si può scaricare sulla propria macchina l’apk dell’applicazione che ci interessa con questi comandi:

adb shell pm list packages

adb shell pm path com.boh.nonso

adb pull /data/app/com.boh.nonso-2.apk path

Il primo elenca tutte le applicazioni installate, con il secondo si ottiene il path di quella che ci interessa e con il terzo la si scarica.

Listato con tutte le applicazioni installate sul dispositivo

“Esplorazione” dell’apk

Qui si va sul difficile… è sufficiente rinominare il file sostituendo l’estensione “apk” con “zip” e scompattare lo zip.

Studio dei sorgenti dell’applicazione

La fase più complessa principalmente perché l’applicazione potrebbe essere stata sviluppata nei modi più disparati.
Uno strumento utile è sicuramente il Dex2Jar, che come dice il nome permette di convertire il/i file .dex in dei .jar.
Quest’attrezzo però non va molto d’accordo con l’osx, e per farlo funzionare potrebbe essere necessario lavorare un po’ di martello e Stackoverflow, per esempio togliendo la cartella dove si trova il dex2jar dalla quarantena con xattr -rd com.apple.quarantine path.
Una volta dati i permessi di esecuzione allo script d2j-dex2jar.sh basterà eseguirlo e andare a prendere il file generato all’interno della directory del’applicativo:
sh d2j-dex2jar.sh -f apk_path

I file .dex

Qualunque sia lo strumento utilizzato per sviluppare l’applicazione almeno un file .dex c’è sempre, ma non è detto che il codice contenuto al suo interno sia significativo. Se infatti l’applicazione non è stata scritta nativamente in Java (o c++) il .dex serve solo come container/ponte per l’applicazione vera e propria, che potrebbe essere stata sviluppata in Javascript, C#, …
Un file .dex c’è ma non è detto che sia da solo; questo accade quando l’applicazione è stata compilata utilizzando il MultiDex per superare l’infame limite dei 65536 metodi della piattaforma Android.

Decompilazione dei .jar

Una volta ottenuti i jar, ovvero degli archivi contenenti i file .class (classi Java compilate), decompilarli per ottenere il codice Java originario è un gioco da ragazzi, ed è sufficiente aprirli con un decompilatore Java come Java Decompiler.

Senza aver studiato i vari casi nel dettaglio devo dire che tra tutti il sistema apparentemente più difficile da crackare sembra quello di Titanium, che minimizza e cripta il codice javascript originario inserendolo in delle HashMap contenute all’interno del codice java autogenerato dall’sdk di Titanium.

Applicazione scritta in Xamarin, decompilazione delle DLL

Se l’applicazione è stata sviluppata con Xamarin, ovvero scritta in C#, il codice contenuto nel file jar non è molto significativo; all’interno dell’apk però ci sono le dll che possono essere decompilate facilmente con un decompilatore .NET come ILSpy.

Libreria scritta con Xamarin e decompilata con ILSpy


Il processo di decompilazione potrebbe non essere perfetto, e infatti alcuni dettagli si perdono. Per esempio ILSpy non sembra (ancora) in grado di riconoscere le stringhe ottenute con un nameof sulle proprietà di un oggetto, o le stringhe scritte con sintassi $"{code}" (che vengono tradotte con delle string.format), ma per lo più si tratta di zucchero sintattico introdotto nelle ultime versioni del .NET mentre il grosso viene interpretato esattamente così com’era stato scritto originariamente.

Su reverse engineering ed offuscamento

La reverse engineering non è mai vista di buon occhio e, salvo rari casi come lo studio di sistemi esistenti al fine di garantirne l’interoperabilità con altri, è più o meno proibita.
Di certo quelli descritti sommariamente qui sopra sono esercizi molto utili a fini didattici e che in alcuni casi possono aiutarci a scovare bug in strumenti che utilizziamo tutti i giorni, quindi conoscere un po’ queste tematiche è cosa buona e giusta. Inoltre è bene sapere che il nostro lavoro potrebbe essere studiato con grande facilità da malintenzionati e/o concorrenti al fine di danneggiarci o copiare il nostro lavoro, ed è qui che entrano in gioco tutta una serie di buone pratiche su cosa includere o no all’interno della nostra applicazione.

L’offuscamento del codice è argomento controverso senza risposte precise, e in rete si possono trovare moltissime discussioni sull’argomento e vari strumenti per ciascun linguaggio.
In generale a mio avviso non conviene farci affidamento se è vostra intenzione proteggere delle password o rendere incomprensibile il codice di applicazioni molto famose per evitare che dei cracker trovino eventuali vulnerabilità, perché non esiste offuscamento che regga contro il tempo e la pazienza di pirati informatici degni di questo nome.
Al contrario potreste aver sviluppato un’applicazione che deve funzionare offline e al cui interno ci sono soluzioni avanzate e che vi danno un vantaggio competitivo su eventuali concorrenti; in questo caso può aver senso sviluppare tutte le “logiche di calcolo” in una libreria a parte e offuscare solo quella in modo da renderne più difficile lo studio e l’utilizzo da parte di malintenzionati… che poi magari uno sta a pagare per un offuscatore, a rallentare tutta la catena di deploy, a rischiare di inserire bug dovuti all’offuscamento, e il repository con il codice è accessibile via web da molti utenti con password deboli, o ancora più comune si pagano gli sviluppatori come degli operai di basso livello e li si lascia partire con la conoscenza o peggio con i sorgenti, ma questa è un’altra storia.

Xamarin.UITest: il nome inganna, ci si può testare (quasi) tutto

Al recente Xamarin Day di Roma l’MVP Massimo Bonanni ci ha parlato dello Xamarin UITest, framework basato su Calabash per la scrittura e l’automazione di test di accettazione nel mondo dello sviluppo mobile.
Niente di nuovo sotto il sole, se non che in precedenza mi ero fatto ingannare troppo facilmente dall’apparentemente elevato costo del servizio in cloud e non avevo approfondito.

Detto che su GitHub ci sono molti esempi di utilizzo, e che io stesso in un progetto al lavoro ho preso “fortemente spunto” dall’app sviluppata per Xamarin Evolve 2016, riporto qui un mio piccolo esperimento fatto con un’applicazione sviluppata in Titanium. Ebbene sì, il framework è stato sviluppato dal team di Xamarin, ma può essere usato per automatizzare il processo di test su ogni applicazione mobile per Android e iOS. Per Windows non ancora, e la cosa può far sorridere considerato chi è il nuovo padrone di Xamarin, ma magari un giorno colmeranno la lacuna.
Per intenderci, funziona con tutte le tecnologie, ma ha senso usarlo soltanto con quelle che renderizzano componenti nativi: Android, iOS, Xamarin, Titanium, React Native, Native Script, … con i framework ibridi basati su Cordova/Phonegap questo approccio è sbagliato perché tutta l’applicazione gira all’interno di una webview.

Esperimento con Appcelerator Titanium

L'albero degli elementi in un'applicazione Titanium, visualizzato tramite repl

L’albero degli elementi in un’applicazione Titanium visualizzato tramite repl

Quello sopra è l’albero degli elementi in una delle maschere dell’applicazione, così come Titanium l’ha generato a runtime. Gli elementi ci sono tutti, ma scriverci sopra dei test non è sempre banale perché non sempre ci sono degli id a cui poter fare riferimento e a volte bisogna ripiegare sul contenuto testuale. Mmmmm.

Quando si crea un progetto di tipo Xamarin.UITest Xamarin Studio genera in automatico una coppia di file, l’AppInitializer.cs e il Tests.cs. Naturalmente saremo poi liberi di modificare la struttura del nostro progetto come preferiamo (vedi l’app di Xamarin Evolve), ma in quei due file ci sono comunque tutti gli elementi di cui abbiamo bisogno per partire.

public class AppInitializer
{
    public static IApp StartApp(Platform platform)
    {
        if (platform == Platform.Android)
        {
            return ConfigureApp
                .Android
                .ApkFile ("/Users/m.piccotti/src/ti_eatevolution/build/android/bin/Eat Evolution.apk")
                .EnableLocalScreenshots()
                .StartApp();
        }

        return ConfigureApp
            .iOS
            //.AppBundle ("../../../iOS/bin/iPhoneSimulator/Debug/XamarinForms.iOS.app")
            .StartApp();
    }
}
[TestFixture(Platform.Android)]
//[TestFixture(Platform.iOS)]
public class Tests
{
    IApp app;
    Platform platform;

    public Tests(Platform platform)
    {
        this.platform = platform;
    }

    [SetUp]
    public void BeforeEachTest()
    {
        app = AppInitializer.StartApp(platform);
    }

    [Test]
    public void AppWorks()
    {
        //app.Repl();

        Func<AppQuery, AppQuery> title = (arg) => arg.Marked("Eat Evolution");
        Func<AppQuery, AppQuery> barFofoGarden = (arg) => arg.Marked("Bar Fofo Garden");
        Func<AppQuery, AppQuery> filtersButton = (arg) => arg.Class("ActionMenuItemView").Marked("Filters");

        // 1 - info page
        app.WaitForElement(title);
        app.Screenshot("1 - info page");
        Assert.IsNotNull(app.Query("JOIN US OR RECOMMEND").First().Text);

        app.TapCoordinates(100, 300);

        // 2 - list
        app.WaitForElement(barFofoGarden);
        app.Screenshot("2 - list");

        app.Tap(barFofoGarden);

        // 3 - Fofo Garden detail
        app.WaitForElement(barFofoGarden);
        app.Screenshot("3 - Fofo Garden detail");
        Assert.IsNotNull(app.Query("Bar Fofo Garden").First().Text);

        app.TapCoordinates(100, 100);
        app.WaitForElement(barFofoGarden);
        app.Tap(filtersButton);

        // 4 - filters screen
        app.WaitForElement(x => x.Marked("Confirm"));
        app.Screenshot("4 - filters screen");
        Assert.IsNotNull(app.Query("Confirm").First().Text);
        Assert.IsNotNull(app.Query("Cancel").First().Text);

        app.Back();
    }
}

Ora… chi è un po’ pratico di test automatici di unità potrebbe rimanere inorridito al vedere quell’unico metodo AppWorks; certo sarebbe bello se ogni asserzione potesse essere verificata isolatamente, il problema è che questi test sono più lenti di quanto si possa immaginare, e i servizi cloud si pagano a ore. In sostanza entro certi limiti può aver senso anche una robaccia come quella sopra.

Il log generato dal test

Il log generato dal test

Per la cronaca quelle sotto sono le schermate catturate dal test.

Giusto un giretto tra le altre piattaforme

Che tutto avrebbe funzionato anche con le altre tecnologie concorrenti di Xamarin e Titanium non avevo dubbi, ma un giro di prova ho preferito farlo comunque. Sotto potete vedere i miei esperimenti fatti con le applicazioni demo delle varie piattaforme.

Il tree in un'applicazione Native Script

Il tree in un’applicazione Native Script

Per qualche ragione che non ho avuto voglia di approfondire con React Native l’applicazione è esplosa, come se il bridge tra l’applicazione di test e quella da testare non abbia funzionato. Il comando tree richiamato con il repl (strumento utilizzabile da cli) ha visualizzato comunque l’albero degli elementi della schermata rossa.

Il tree in un'applicazione React Native

Il tree in un’applicazione React Native

Il tentativo con Ionic 2 l’ho fatto solo a scopo didattico, per vedere la famosa WebView. Teoricamente si può interagire con l’applicazione a furia di TapCoordinates, ma il test risultante sarebbe così fragile che non ha proprio senso perderci tempo. Per le applicazioni ibride basate su html tanto vale usare Protractor.

Il tree in un'applicazione Ionic 2

Il tree in un’applicazione Ionic 2

Conclusioni

Xamarin.UITest è una figata.

PRO:

  • È possibile interagire con il dispositivo mentre il test automatico è in atto, sia fisicamente che attraverso il repl
  • Con il comando tree da riga di comando si può visualizzare la struttura reale della propria applicazione così com’è stata renderizzata sul dispositivo, cosa che può tornare molto utile
  • Funziona su Android e iOS.
  • Con Xamarin Test Recorder si può registrare il proprio test andando poi a modificarne il codice
  • Il test in cloud è utile non solo per testare automaticamente su molti dispositivi diversi, ma anche per fare test specifici quando ci vengono segnalati dei bug su un dispositivo particolare che non abbiamo a disposizione
  • L’interfaccia web dei test in cloud è spaziale, ci da un sacco di informazioni anche sulle performance ed è possibile fare degli screenshot mirati in presenza di errori e non solo

CONTRO:

  • Non funziona su Windows
  • Il test recorder funziona solo per Android ed è stabile solo per Visual Studio
  • L’esecuzione dei test è lenta da far schifo
  • Il test in cloud costa un occhio della testa anche nella versione Newbie

Debug e profilazione di un’applicazione Titanium (e non solo) su Android Studio

Di recente mi è capitato di dover fare un po’ di profilazione di un’applicazione mobile scritta con Titanium per Android, principalmente per accertarmi dell’assenza di memory leaks in alcuni punti.
Su iOS è facile, perché Xcode mette a disposizione tutto il necessario (tempo fa scrissi un articoletto al riguardo), su Android non avevo mai provato.

Avevo notato che aprendo Android Studio e usando l’applicazione in oggetto sul logcat (console dei log) di Android Studio veniva sparato l’output, ma sul fronte RAM e CPU era tutto fermo.
È stato sufficiente mettere a true il flag android:debuggable sul file tiapp.xml e come per magia riavviando l’applicazione e selezionandola sull’Android Monitor i diagrammi sull’utilizzo delle risorse hanno preso vita.
Questa cosa funziona con tutte le applicazioni in cui si può abiltare il flag debuggable sul manifest Android, quindi per esempio anche usando Xamarin.

Il flag incriminato

Il flag incriminato

I pannelli sull'utilizzo delle risorse

I pannelli sull’utilizzo delle risorse

Per completezza aggiungo un articolo sulla documentazione di Titanium che spiega come ricercare i memory leaks su iOS e Android, ma senza menzionare l’opzione Android Studio.
https://wiki.appcelerator.org/display/guides2/Managing+Memory+and+Finding+Leaks#ManagingMemoryandFindingLeaks-MonitoringallocationsonAndroid

Niente di trascendentale ma magari qualcun altro non aveva mai provato.

Appcelerator Titanium, licenza indie e sviluppo enterprise

È passato poco più di un mese da quando Jeff Haynie ha annunciato in pompa magna le grandi novità in casa Appcelerator.
Una di queste – la “monetizzazione” dell’sdk Titanium da parte dell’azienda – non è stata accolta con grande entusiasmo, e qualche giorno dopo andando a leggere sul loro sito il dettaglio delle licenze mi sono allarmato leggendo queste parole: “You may choose to purchase multiple Indie plans, but the users of these seats cannot see or share work with one another”.

Dicitura alquanto preoccupante che spiega le limitazioni della licenza Indie

Dicitura alquanto preoccupante che spiega le limitazioni della licenza Indie


Quel “share work” mi ha fatto preoccupare un po’, perché è vero che come utilizzatore precedente ho diritto a una licenza indie gratuita e permanente, ma è altrettanto vero che lavoro in un’azienda insieme ad altra gente, e lì per lì ci ho visto nero. Un mio tweet al veleno ha attirato l’attenzione di Ricardo Alcocer (Director of Developer Relations and Training), il quale preoccupato si è affrettato a chiarire i miei dubbi spiegandomi che “the Indie account will not allow you to share app’s backend data with other Indie developers”. In pratica a detta sua l’unico limite sarebbe stato nella condivisione di backend e analytics tra utenti non registrati come parte di un’unica organizzazione.

Il test con il doppio account

L’altro giorno finalmente mi è arrivato l’invito per utilizzare in anteprima la versione 4.0 (ancora alla RC2) con l’account registrato a nome dell’azienda, e dal momento che avevo già un invito sul mio account personale sono riuscito a fare i test di lavoro con più account sullo stesso progetto. Ho quindi importato uno dei progetti sviluppati in azienda con l’account aziendale, ho fatto qualche test e poi sono uscito da Appcelerator Studio eseguendo il login seguente con il mio account personale, per vedere cosa sarebbe successo.

…e quando invece si esegue il login con un account diverso da quello con cui si è registrata l’app

…e quando invece si esegue il login con un account diverso da quello con cui si è registrata l’app

…e quando invece si esegue il login con un account diverso da quello con cui si è registrata l’app

…e quando invece si esegue il login con un account diverso da quello con cui si è registrata l’app


Aprendo il tiapp.xml si nota il messaggio di warning in cui si spiega che l’applicazione è associate a un’organizzazione di cui non si fa parte e in cui si consiglia di farsi aggiungere in tale organizzazione… facendo pagare a quell’organizzazione delle (costose) licenze Team o Enterprise.

In Appcelerator controllano e registrano tutto

Il problema vero non è tanto il non aver accesso ai servizi web di Appcelerator, quanto che lanciando l’applicazione l’sdk fallisce il processo di build: Application not registered. In pratica a ogni creazione di una nuova applicazione (o importazione di un’applicazione esistente) viene generato un guid univoco che viene associato all’appid, e sulla console web dell’utente (o meglio dell’azienda correntemente selezionata dallo sviluppatore) compare una coppia di applicazioni: quella mobile (Titanium) e l’Arrow DB.
Se si prova ad avviare l’applicazione e sui server Appcelerator all’organizzazione di cui fa parte lo sviluppatore non è associata un’applicazione con quel guid, il processo di build fallisce.

"Application not registered"

“Application not registered”


Il punto è che a ciascuna licenza Indie sono associate due entità: lo sviluppatore e l’organizzazione di cui questo fa parte. La creazione/importazione di un’app da parte di uno sviluppatore fa sì che all’organizzazione correntemente selezionata venga associata questa nuova applicazione, identificata da un guid univoco. Ciascuno sviluppatore può far parte di più organizzazioni, ma un’organizzazione Indie non può aver al suo interno più di uno sviluppatore.
Fregati?

Come fare se in azienda si hanno più licenze Indie e non si vuole pagare

Detto che Titanium è ancora su GitHub e lo si può compilare come spiegato sulla documentazione, ma anche che su questo repository non ci saranno più informazioni relative a tags e release varie, è chiaro che da San Francisco per rimpinguare le casse non puntano tanto agli sviluppatori indipendenti sprovvisti di un account (che probabilmente punteranno ad altre tecnologie più economiche), quanto a quella galassia di piccole software house che hanno scelto per le loro applicazioni quella che era la più promettente tecnologia gratuita in grado di non far sentire troppo la mancanza del nativo. E che potrebbero farsi ingolosire anche dai migliori servizi cloud e assistenza delle versioni Team e Enterprise rispetto alla Indie.

Il controllo messo in piedi da quelli di Appcelerator sulle applicazioni sviluppate con il loro sdk è abbastanza lasco e non limita più di tanto. Probabilmente hanno preferito non infierire troppo, fatto sta che una soluzione c’è: basta organizzarsi in modo da poter cambiare velocemente il guid associato all’applicazione (nel tiapp.xml) al cambiare dello sviluppatore.

Il nodo è nel guid (ultima riga)

Il nodo è nel guid (ultima riga)

Se in azienda non ci sono altri sviluppatori destinati alla piattaforma Titanium è sufficiente utilizzare sempre lo stesso account, per lo sviluppo e per rilasciare l’applicazione. Qualora si debba lavorare in parallelo sullo stesso progetto è invece meglio fare in modo che chi ha un account personale registri le applicazioni sul quale lavorerà sulla propria console Appcelerator, e implementi un meccanismo di sostituzione veloce dei guid. Lasciando l’account “aziendale” libero per rilasciare l’applicazione o per eventuali sviluppatori sprovvisti di un account Indie.

Registrazione di un applicazione già esistente su un diverso account

Il modo migliore che mi è venuto in mente è quello di creare una nuova applicazione – vuota – utilizzando la CLI, e assegnandole appid e nome uguale a quella che si sta cercando di “clonare”.
Apriamo la console, portiamoci su una cartella vuota creata per l’occasione e digitamo appc new --id APP_ID --name APP_NAME, con APP_ID uguale all’appid dell’app, e APP_NAME uguale al suo nome.
appcelerator-new-app
Questo è il modo più veloce di creare un’applicazione vuota, e oltre al riempimento della directory con i file della nuova applicazioni ci ritroveremo anche con la coppia di applicazioni Titanium/Arrow sulla console web. Per qualche motivo sconosciuto dalla console non si possono (ancora) eliminare le applicazioni Arrow, ma a leggere in rete sembra che presto colmeranno questa lacuna.
appcelerator-online-console

Sostituzione “on-demand” del guid

Una volta creata la nuova applicazione “copia” dell’originale possiamo anche buttarla via, perché l’unica cosa che ci interessa è il guid generato.
Il mio consiglio è quello di creare – all’interno dell’applicazione – una cartella con un file .sh per ogni account Indie che avete, e all’interno di questi mettere un comando che sostituisca il guid originale (quello registrato sull’account “aziendale”) con quello associato all’account Indie personale, e disponibile per la copia sulla console web di quest’ultimo.
In bash un modo per sostituire una stringa all’interno di un file è questo:
sed -i "" 's/ORIGINAL_GUID/REPLACED_GUID/' ../tiapp.xml

Ogniqualvolta si avrà bisogno di usare il proprio account Indie personale basterà eseguire il login con questo e poi lanciare il file .sh che metterà le cose in regola con quelli di Appcelerator. Naturalmente il nostro progetto è sotto git, quindi far ritornare il guid corretto dentro il tiapp.xml della nostra app è questione di un git reset.

Ispezionare le cartelle private di un’app Android

La concorrenza: iOS

Quando si sviluppa un’applicazione per iOS controllare i dati della propria app su filesystem è tutt’altro che un problema, perché è possibile ispezionare i dati di ogni applicazione installata (in test) su ciascun simulatore, semplicemente con il Finder.
Il percorso di questi file è cambiato tra la versione 7 e la 8 di iOS, e ora i file si trovano su ~/Library/Developer/CoreSimulator/Devices/_DEVICE_UDID_/data/Container/Data/Application/_APPLICATION_ID_/....
Purtroppo gli id dei dispositivi e delle applicazioni sono delle sequenze di numeri e lettere tutt’altro che parlanti, ma basta capire come con Xcode è possibile ispezionare questi codici, o meglio ancora che è sufficiente stampare sul log della propria applicazione i percorsi interi e poi andarseli a guardare, e i dati delle nostre applicazioni mobile non avranno più segreti.

Il robottino verde è più timido

Quando si passa ad Android le cose si fanno più complicate. Per cominciare i dati possono essere salvati nella directory privata data/data/appid o in aree per così dire “pubbliche” ma sempre in cartelle con lo stesso nome dell’appid, che possono trovarsi nella root o in /Android/. E’ importante scegliere bene dove salvare i dati, perché quelli più “strategici” dovrebbero essere protetti il più possibile, mentre altri più di pubblico dominio sarebbe meglio lasciarli accessibili anche da applicazioni terze, per offrire maggiori funzionalità.
Detto che il similatore classico di Android è indegno di essere paragonato a quello di iOS, con l’arrivo di Genymotion anche gli sviluppatori Android si sono ritrovati con una valida alternativa ai dispositivi fisici, ma in questo caso l’accesso ai dati è più problematico rispetto a iOS.

Accesso fisico ai file da un dispositivo o da Genymotion

A differenza dei dispositivi Apple quando si parla di Android i file manager non sono utopia ma vengono installati di default o è possibile comunque scaricarsene di buoni senza spendere un centesimo.

Uno dei tanti file manager (gratuiti) su Android

Uno dei tanti file manager (gratuiti) su Android


Su Genymotion sarebbe possibile installare i Google play services per poi scaricarsi qualunque app presente sul market, ma se abbiamo bisogno solo di un file manager qualunque ce n’è già uno preinstallato.
Il file manager preinstallato su Genymotion

Il file manager preinstallato su Genymotion


Fin qui tutto semplice, e per prendere i file senza tanti giri strani è sufficiente condividerli, ad esempio con Dropbox. Ma come fare per andare a sficcanasare tra i file privati e/o a copiarsi tutti i file dell’app?

ADB, ovvero il ponte

ADB è un tool presente nell’sdk di Android con cui è possibile fare tante cose carine, tra cui copia di file, backup, esecuzione di query sui db sqlite delle varie app e chi più ne ha più ne metta.
L’eseguibile dell’Android Debug Bridge si chiama “adb” e lo si può trovare nella platform-tools interna alla directory di installazione dell’sdk Android.
L’sdk di Android può essere ovunque perché dipende da chi o cosa l’ha installato, ma in genere sta in:
/Users/username/Library/Android/sdk/ (Mac)
C:\Users\username\AppData\Local\Android\sdk (Windows)
perché questi sono i percorsi di default quando si installa Android Studio.

Alcuni comandi e limitazioni varie

Con l’adb si può:

  • visualizzare la lista dei dispositivi/simulatori disponibili: ./adb devices
  • collegarsi alla shell di un dispositivo/simulatore per eseguire operazioni su file system: ./adb -s device shell
  • una volta che si è dentro la shell si possono visualizzare le app installate: ls data/data

… e tante altre cose. Ma la cosa che ha me è servita di più è la creazione di un backup dell’app, perché purtroppo succede che la documentazione dell’sdk che stiamo utilizzando sia fallace e ci induca a utilizzare percorsi sbagliati per salvare e caricare i nostri database… e lo scaricarmi in locale una copia dell’applicazione è stato illuminante in questo senso.
Purtroppo se il dispositivo a cui ci colleghiamo è ancora “integro” (non ci siamo collegati con l’utente root) alcune operazioni ci saranno proibite per mancanza di permessi. Peccato.

Backup dei dati di un’applicazione

Stabilito che in uno dei dispositivi collegati e accesi (telefono o simulatore) c’è un’app con appid uguale a it.blabla.boh, per farne il backup è sufficiente eseguire il comando:
./adb backup -noapk it.blabla.boh
Appena eseguito sul dispositivo/simulatore viene richiesta una conferma con eventuale inserimento di password.

La richiesta di conferma (e password) all'esecuzione del comando di backup

La richiesta di conferma (e password) all’esecuzione del comando di backup


Il risultato è la creazione di un file backup.ab dentro la cartella platform-tools. Questo file è abbastanza rognoso, ma per decomprimerlo senza grandi patemi esiste un programmino chiamato Android Backup Extractor (abe) che può essere scaricato da qui e il cui progetto si può trovare su GitHub.
Il file creato da adb backup

Il file creato da adb backup


La decompressione del file .ab in un .tar (a sua volta decomprimibile normalmente) è cosa (in teoria) semplice:
java -jar abe.jar unpack backup.ab backup.tar [password]

A volte funziona tutto, a volte l’abe va in errore non si sa il perché. Potrebbe dipendere dalla versione di Android installata sul dispositivo/simulatore, a me con la 4.3 è andata liscia, ma quando ci ho riprovato su un altro computer non ce l’ho fatta… Il file .ab comunque può essere decompresso anche in altri modi, se così non ce la fate buona ricerca.

Draw 9-patch: le immagini auto-adattanti di Android

Qualche tempo fa – dopo mesi di sviluppo multi-piattaforma su Titanium per una sola piattaforma (iOS) – finalmente mi è capitato di dover mettere mano anche al lato verde dello sviluppo mobile, quello della piattaforma Android.

Su un progetto mi è stato mostrato un tool presente solo su Android per generare immagini auto-adattanti al contenuto e al contenitore – il Draw 9-patch – utilizzato in un progetto per generare l’immagine “splash” dell’applicazione. Ora finalmente mi sono ricordato che mi ero detto di approfondire un po’ la cosa, e ho notato che non c’è molta documentazione al riguardo (almeno in italiano), quindi eccomi qui.

La “tecnologia”

Quelli di Google non hanno badato a spese per progettare e realizzare questo formato di file… si tratta infatti di una semplice immagine png con estensione .9.png, e contenente delle righe nere all’interno del file.
Sviluppando in nativo questi immagini devono essere piazzate dentro la directory res/drawable, utilizzando Titanium invece vanno dentro assets/android.

Esempio di immagine 9-patch

Esempio di immagine 9-patch


Sui lati dell’immagine si possono tracciare delle righe nere (solid) di un pixel, ciascuna delle quali ha un significato. Quelle sui bordi superiore e sinistro definiscono la/le superfici che possono essere “stirate” (stretched), mentre sulla destra e sotto si possono (opzionalmente) tracciare le righe che definiscono le aree che possono essere riempite – adattandone le dimensioni – con del contenuto, come ad esempio testo o altre icone.
I bordi superiore e sinistro sono fondamentali quando si vogliono creare degli splash screen adattivi, quelli destro e inferiore al contrario servono soltanto se l’immagine che si sta creando serve da sfondo per pulsanti o contenitori, all’interno dei quali si dovranno inserire testo e/o altre immagini.
Questi bordi, presenti nell’immagine “sorgente”, saranno poi naturalmente eliminati dall’immagine risultante.

Da notare come l’intersezione dei bordi superiore e sinistro, e quella dei bordi inferiore e destro formino delle superfici, superfici che chiaramente non possono essere “negative”. Queste immagini possono quindi adattarsi soltanto aumentando di dimensione, e non scaleranno mai più dell’immagine originaria, che deve quindi essere considerata come caso “più piccolo”.

Il tool Android fornito con l’SDK

All’interno dell’SDK di Android, e più precisamente nella directory sdk/tools, si può trovare il potentissimo strumento per gestire questi tipi di file. Su Windows si lancia con il bat draw9patch.bat.
Draw9patch - Tool
Trattasi di un eseguibile java che prende in ingresso un file png e – attraverso opportuni trascinamenti dei bordi – permette di definire quali aree sono adibite allo “stretching” (stiramento) e quali al “filling” (riempimento).

Senza scomodare tool sconosciuti: Gimp

Stiamo lavorando con un’immagine png, nessuno ci vieta quindi di utilizzare il nostro editor di immagini preferito, nel mio caso Gimp.
Draw9patch - Gimp
Se decidiamo di utilizzare un editor, qualunque esso sia, bisogna però fare attenzione che questo non aggiunga artefatti, trasparenze non volute o anti-aliasing che possano “rompere” le convenzioni del 9-patch Android. Una volta modificata l’immagine forse conviene quindi andare a testarla su dispositivi diversi per verificare che il risultato sia sempre quello atteso.

Test su emulatore Genymotion

Test su emulatore Genymotion

Profilare con Xcode, alla ricerca di memory leaks e non solo

Chi fa il nostro mestiere prima o poi deve affrontare dei problemi di memoria… che la si perda a causa di stress e del passare degli anni, o si scriva programmi che si affidano ad allocazione/deallocazione automatica, prima o poi tutti abbiamo problemi con questo prezioso strumento.

Il caso peggiore: memory leak in applicazione web Java

Tempo fa lavorando ad un grosso progetto web sviluppato in Java (JSF2) ci ritrovammo a metterci le mani nei capelli a causa di qualche memory leaks che rendevano per così dire “poco scalabile” la nostra applicazione. Allora usammo l’Eclipse Memory Analyzer MAT, strumento molto potente e ben fatto che permette di analizzare lo heap di qualunque applicazione Java.
Su un’applicazione web certi problemi possono essere devastanti, mentre in programmi che girano localmente su macchine provviste di parecchia RAM spesso nemmeno ci si rende conto che il nostro programma sta lentamente mangiando tutta la memoria senza rilasciarla, finché va in crash. Se però questa cosa succede di rado, e in quelle poche occasioni stavamo facendo operazioni parecchio onerose, spesso nemmeno ci facciamo caso e/o facciamo finta di niente.
Memory Leak - Comic

Memory leak?

Se non siete uno degli ultimi due personaggi della vignetta dovreste sapere a grandi linee di che si tratta, ma nel dubbio cerco di spiegarlo in poche parole: un programmatore ha sbagliato qualcosa e tra le righe di codice c’è qualche operazione che occupa memoria senza rilasciarla al termine.
Se non si programma in C raramente ci si deve preoccupare di allocare e deallocare la memoria manualmente, perché quasi tutti i linguaggi gestiscono la memoria autonomamente, allocandola ad ogni nostra dichiarazione di variabile, e facendola liberare da un garbage collector. Il GC è un processo demone che scansiona l’area di memoria dove risiedono gli oggetti e le variabili creati dal nostro programma ed elimina quelli rimasti per così dire “isolati”, ovvero che non sono più referenziati da nessuno o che sono collegati solo a oggetti non referenziati da parti “vive” dell’applicazione. In presenza di GC i memory leak sono rari perché il GC a differenza nostra non si dimentica di liberare la memoria, ma a volte proprio non ce la fa a causa di strutture mal progettate che generano riferimenti “eterni” a variabili che credevamo temporanee, e in questi casi sono dolori.

Tipico grafico di un'applicazione affetta da memory leaks, lo heap si riempe e boom

Tipico grafico di un’applicazione affetta da memory leaks

Analisi della memoria su Xcode

Sviluppando in nativo su iOS non so quanto spesso capiti di dover profilare l’applicazione alla ricerca di problemi di memoria, ma parlando di Titanium io personalmente ho dovuto preoccuparmene in più di un’occasione. Il Mac è un prodotto del demonio, però Xcode fornisce alcuni validi strumenti che in questi frangenti tornano molto utili. Vediamo come profilare un’applicazione alla ricerca di problemi di memoria e di prestazioni.

Aprendo un progetto Xcode ci si trova di fronte la finestra delle impostazioni generali, e qui dobbiamo definire le impostazioni di deploy. Generalmente la versione di iOS e il tipo di dispositivo.
IOS Profiling 1
Scegliamo la destinazione del nostro test, tra eventuali dispositivi collegati al Mac e simulatori del tipo selezionato al passo precedente. Fatto questo dobbiamo ricompilare il progetto. Considerato che stiamo per fare una profilazione, tanto vale fare il “Build for > profiling”, e al termine avviamo la profilazione con “Profile”.
IOS Profiling 2
Selezioniamo il tipo di template che più si adatta alle nostre esigenze o creiamo un template contenente tutte le metriche che ci interessano.
IOS Profiling 5
Nella schermata che si apre, quando siamo pronti, premiamo il tasto di registrazione e l’applicazione inizia a girare mandando dati agli strumenti di diagnostica scelti.
In cima all’elenco possiamo leggere istante per istante i dati generali i utilizzo della memoria, e subito sotto quali sono i tipi di oggetti che contribuiscono in maggior misura a saturare la nostra cara RAM. Il diagramma parla più di tutti, se questo inizia lentamente ad assomigliare ad una sega inclinata verso l’alto sono cazz… problemi.
IOS Profiling 6
Se certe parti del flusso del programma sono sospette e volete vedere in dettaglio come cambia l’utilizzo della memoria facendo una determinata operazione non serve segnarsi i numeri sul foglio ma possiamo usare l’utilissimo pulsante “Mark generation”. Questo serve a scattare un’istantanea di un certo punto, istantanee che possono poi essere confrontate per vedere come cambia l’utilizzo della memoria tra queste diverse “generazioni” (e quali oggetti rimangono in memoria).
Nel mio caso la memoria rimane stabile e decresce alla chiusura di alcune finestre parecchio pesanti. Se in certi punti pensate ci siano dei memory leak ma i “buchi sul tubo” sono troppo piccoli da rilevare potete prendere un trapano e allargare il buco… basta aggiungere delle immagini o in generale blob pesanti in variabili sospette per vedere meglio la RAM che se ne va.
IOS Profiling 7

Sviluppo per iOS su Titanium

Se stiamo sviluppando con Titanium probabilmente Xcode lo conosciamo molto poco, eppure nella vostra cartella del progetto (sotto build/iphone) ci dovrebbe essere un file .xcodeproj. Apritelo e vi ritroverete con il progetto Xcode che potete maneggiare e lanciare a piacimento

La cartella del progetto iOS generato da Titanium

La cartella del progetto iOS generato da Titanium

Senza scomodare Xcode

Certi strumenti sono molto potenti e possono aiutarvi molto, ma se siete dei romantici e preferite migliorare le prestazioni del vostro programma basandovi solo sull’intuito potete comunque usare la finestra di Monitoraggio delle attività di OSX. Ogni programma lanciato nel simulatore iPad/iPhone è un processo a se stante, e potete quindi tenere sempre sott’occhio la memoria che questo utilizza.

Monitorare il processo spesso è sufficiente

Monitorare il processo spesso è sufficiente

Intuito, Xcode, oscilloscopio, qualunque mezzo decidiate di usare l’importante è che ogni tanto verifichiate la stabilità e la non eccessiva onerosità dei vostri programmi. Alcuni utenti non sono molto comprensivi – giustamente – quando l’applicazione si rallenta in modo esagerato con il passare del tempo o peggio scompare dalla loro vista all’improvviso.

Titanium Studio e GIT, integrato (a volte) è meglio

Sviluppatori: ognuno con le sue convinzioni e il suo credo

Gli sviluppatori mobile con Titanium si dividono in due scuole di pensiero: chi utilizza Titanium Studio e chi preferisce usare un ide meno pompato e la console. Io appartengo ancora alla prima categoria, principalmente perché mi districo male tra molte finestre e preferisco avere sempre tutto sotto controllo mentre lavoro. L’idea di passare a Sublime o Atom in combinazione eventuale con strumenti esterni mi ha tentato, ma ancora non ho raccolto gli stimoli sufficienti.

Il problema è che Titanium non è il solo strumento che contribuisca a dividerci in caste, perché anche GIT non scherza. I puristi conoscono tutti i comandi con relativi parametri a memoria e utilizzano soltanto la console, i pigri/smemorati come me si affidano a strumenti un po’ più “smart” e ricorrono alla console solo in casi di emergenza o come esercizio di memoria. Personalmente io uso alternativamente la console, il plugin integrato nell’ide e SourceTree, un gestore di repository GIT veramente ben fatto.

SourceTree, e GIT non sarà più così ostico

SourceTree, e GIT non sarà più così ostico

La I di IDE sta per “Integrated”…

Fatte queste distinzioni è ora di arrivare al dunque: perché questo articolo? Il punto è che non sarebbe male utilizzare nel proprio ambiente di sviluppo un plugin che ci aiuti ad avere sempre sotto controllo tutte le modifiche fatte ai nostri sorgenti. Eclipse ha degli showview integrati (History e Synchronize) con cui poter vedere lo storico e lo stato attuale delle modifiche, ma in Titanium questi non funzionano con GIT. Infatti l’ide Titanium Studio ha un suo plugin per GIT (com.aptana.git), che però si integra malissimo con Eclipse e secondo me è praticamente inutile.

Come guardare il dettaglio dei plugin installati

Come guardare il dettaglio dei plugin installati

Aptana Git, per la serie: meglio soli che mal accompagnati

Aptana Git, per la serie: meglio soli che mal accompagnati


L’amato/odiato Eclipse ha un suo plugin per gestire decentemente il repository GIT (EGit), ma non viene fornito con Titanium Studio e fa a cazzotti con quello installato di default.
Il mio consiglio è quindi quello di disabilitare il plugin di Aptana e utilizzare EGit, e ora vi mostro come fare.

Installazione e utilizzo di EGit su Titanium Studio

Punto 1: Per prima cosa conviene dire a Eclipse di non utilizzare più il plugin di Aptana per gestire i nuovi progetti GIT aggiunti nel workspace. Questa cosa la si fa dalla pagina delle preferenze di Eclipse.

Disabilitazione di Aptana Git per i nuovi progetti

Disabilitazione di Aptana Git per i nuovi progetti

Punto 2: Se volete usare su Eclipse un plugin non fornito di default (in questo caso EGit) bisogna installarcelo. La procedura è sempre la stessa e ne avevo parlato in modo un po’ più dettagliato su un precedente articolo (a proposito di SVN su Eclipse).

Installazione di EGit

Installazione di EGit

Punto 3: Nel caso abbiate già dei progetti che utilizzano GIT come VCS all’interno del vostro workspace questi continueranno a usare il vecchio plugin. Scollegateli da esso e fate in modo che usino il nuovo plugin.

Disconnessione di progetti esistenti da Aptana Git

Disconnessione di progetti esistenti da Aptana Git

Connessione di EGit ai progetti git precedentemente scollegati da Aptana Git

Connessione di EGit ai progetti git precedentemente scollegati da Aptana Git

Il Synchronize di Eclipse, uno dei miei strumenti preferiti del mio IDE preferito

Eclipse ha molte funzioni, ma una delle mie preferite e indipendenti dal VCS utilizzato (GIT, SVN, …) è la view Synchronize, che mostra l’elenco dei file modificati rispetto al repository (e all’origin nel caso del GIT) e da la possibilità di modificarli facilmente con una finestra di comparazione. Funzione fondamentale in un ambiente di sviluppo integrato degno di questo nome.
Titanium - Synchronize

Conclusioni

Si può usare un ide o qualunque editor di testo in combinazione con tool esterni, l’importante è avere sempre sotto mano tutte le funzioni di cui si ha bisogno. Titanium Studio per usare un eufemismo non è che sia proprio performante, ma è basato su quel mostro di configurabilità ed estendibilità che è Eclipse, conviene quindi sfruttare al meglio le sue peculiarità installando all’occorrenza ciò che manca.

TiShadow: un hack che (il più delle volte) può far risparmiare un sacco di tempo

Lo sviluppo mobile è una rogna, perché sul mercato ci sono un’infinità di dispositivi e svariate piattaforme e ogni singolo utente si aspetta di poter usare ciascuna applicazione di cui sente parlare.
Quando uno degli obiettivi è raggiungere più pubblico possibile la strada dello sviluppo multi-piattaforma offre varie alternative, ciascuna con i suoi punti di forza e le sue debolezze. Appcelerator Titanium è una di queste.

Compilazione e deploy a ogni modifica, ovvero come girarsi i pollici per la metà del tempo

Quasi in ogni contesto di sviluppo si deve affrontare l’enorme spreco di tempo dovuto a compilazione e deploy delle proprie applicazioni su dispositivi/simulatori, e Titanium non fa eccezione. O almeno non la faceva fino a un paio di anni fa.
Nel 2012 in Australia devono essersi stancati di aspettare il compilatore, e si sono inventati un hack: TiShadow. Il nome non rende molto bene l’idea, si tratta di un infrastruttura basata su un’applicazione mobile che funge da container (di applicazioni sviluppate con Titanium), un’applicazione server che ha il compito di iniettare il nostro codice all’interno del container, e una serie di comandi per console (CLI).

Un'immagine vale più di mille parole

Un’immagine vale più di mille parole


L’utilizzo in se non è complicato, e nemmeno capirne il funzionamento, ma è uno strumento ancora non così diffuso anche perché nei primi passi si può sbattere in alcuni spigoli e rimanere scoraggiati.

Distribuzione ed esecuzione paralleli su più dispositivi

Come è facile intuire stiamo parlando di strumenti sviluppati in Javascript per il Javascript, ecco quindi che spunta fuori npm e l’installazione consiste semplicemente nell’installazione di un modulo NodeJS, e ogni passaggio richiede l’utilizzo della linea di comando.

Installazione di TiShadow

npm install -g tishadow
(per un doveroso approfondimento sui moduli NodeJS leggete qui)
Una volta installato l’apposito modulo globale tutta una serie di comandi diventano disponibili da console.

Creazione dell’applicazione TiShadow

Andiamo quindi a creare una directory per la nostra applicazione, spostiamoci al suo interno, e lanciamo il comando per la creazione dell’app:
tishadow app -d ./
Fatto questo nella directory corrente comparirà un’applicazione Titanium installabile su tutte le piattaforme e contenente i moduli più comunemente usati. Quest’applicazione deve contenere tutto il necessario per il funzionamento della nostra app, perché sarà lei che ospiterà il pacchetto della nostra applicazione, o meglio tutto il contenuto della directory /app. Come potete vedere osservando la struttura di un progetto Titanium i moduli, i plugin, e soprattutto i file tiapp.xml e il manifest sono esterni alla directory app, è importante quindi andare ad aggiungere eventuali moduli non già presenti nell’installazione di TiShadow, e andare a “completare” il tiapp.xml della nuova applicazione ombra inserendovi gli eventuali moduli aggiunti e correggendo appid, version e altre informazioni che potrebbero essere importanti per il buon funzionamento della nostra app.

Deploy dell’applicazione ombra sui dispositivi

L’applicazione “ombra” creata al passo precedente deve essere installata sui nostri dispositivi (o simulatori) in cui dobbiamo testare la nostra applicazione mobile.
Se ad esempio vogliamo provare la nostra applicazione su un simulatore di Motorola Moto X creato con Genymotion sarà sufficiente utilizzare il CLI di Titanium con il comando:
ti build -p android -T emulator --device-id "Motorola Moto X - 4.3 - API 18 - 720x1280"
Questo passo in linea di principio è sufficiente farlo una volta, o almeno solo quando facciamo modifiche “sostanziali” alla nostra applicazione (come aggiunta di moduli o upgrade dell’sdk), perché poi l’applicazione TiShadow rimarrà sul nostro dispositivo/simulatore.

L'applicazione "ombra" TiShadow sul simulatore Genymotion

L’applicazione “ombra” TiShadow sul simulatore Genymotion


L’applicazione TiShadow è disponibile per lo scaricamento anche sull’Android Market, ma se ne sconsiglia vivamente l’utilizzo in favore dell’installazione vista sopra, perché non è chiaro quale sia la sua versione e non avremo modo di mettere le mani al suo interno (ad esempio per modificare il tiapp.xml o per aggiungere moduli).
TiShadow sul market. Ora dimenticatela.

TiShadow sul market. Ora dimenticatela.

Lancio del server TiShadow e connessione dell’applicazione ombra

Una volta installata e lanciata l’applicazione “container”, ci ritroveremo di fronte a una richiesta di connessione a un server…

Quale server TiShadow ?

Quale server TiShadow ?


Facendo un rapido riavvolgimento fino all’inizio dell’articolo potete vedere che avevo nominato un’applicazione server. Questa è una delle parti fondamentali del modulo TiShadow, e per lanciarla è sufficiente digitare:
tishadow server
Si possono specificare vari parametri ma niente di fondamentale. L’applicazione server si mette in ascolto su una porta (la 3000 di default), e aspetta che delle applicazioni client TiShadow vi si connettano così da stabilire un collegamento attraverso il quale iniettare la nostra applicazione.
Inseriamo quindi l’IP della nostra macchina sulla maschera di login dell’app TiShadow e lasciamo che i due attori si connettano.
Ripetiamo questo passaggio per ogni altro dispositivo/simulatore in cui vogliamo testare la nostra applicazione.

Esecuzione della nostra applicazione

Arrivati a questo punto dobbiamo solo posizionarci nella directory della nostra applicazione e dire a TiShadow di eseguirla:
tishadow run
Per magia ci ritroveremo con la nostra applicazione distribuita su ogni dispositivo/simulatore collegato al server.
Anche questo comando dispone di vari parametri, ad esempio con tishadow @ run il deploy è automatico ad ogni salvataggio… una manciata di secondi per un deploy a caldo su dispositivi multipli.
È doveroso specificare che spesso le cose si “incastrano” e c’è da riavviare server e/o client e/o fare qualche aggiustamento, fatto sta che lo strumento è di una potenza devastante.

Unit-test con TiShadow

Ipotizziamo per un momento che chi sta leggendo sia abituato a lavorare soltanto su una piattaforma e abbia una macchina abbastanza veloce da non trarre troppo giovamento da deploy a caldo e distribuzione parallela su più dispositivi, può trarre comunque giovamento da TiShadow? Una domanda scritta in questo modo presuppone una risposta affermativa, specialmente dopo aver letto il titolo, e infatti la risposta è sì.
Ci sono un sacco di moduli e librerie per eseguire test automatici di unità in Javascript, ma farli funzionare con Titanium non è sempre così semplice. TiShadow ci aiuta perché integra al suo interno la libreria Jasmine, e una volta scritte le specifiche nella consueta forma describe-it e inserite nella directory app_main_directory/spec il gioco è fatto.

describe(&quot;Spec description&quot;, function(){
  it(&quot;Test description&quot;, function(){
    expect(true).toBe(true);
  });
});

Non serve installare moduli o includere librerie, perché è già tutto dentro TiShadow. Basta descrivere le nostre specifiche come nell’esempio sopra, inserirle in file terminanti con il suffisso “_spec.js” e includere questi file nella directory “spec”. L’esecuzione dei test consiste in due parole:
tishadow spec

Conclusioni

La lentezza delle procedure di deploy è un problema sentito, specialmente nell’ambito dello sviluppo mobile. Forse meno sentito ma non meno importante è l’argomento dei test automatici. Su Titanium entrambi i problemi sono più o meno risolti da TiShadow, un modulo ancora ignoto a molti forse anche a causa del nome enigmatico.
Speriamo che questo breve articolo serva a fare un po’ di luce sull’argomento e a dissipare le ombre che molti vedono aleggiare su Titanium.

A mali estremi estremi rimedi: Xcode e la visualizzazione del log sui dispositivi iOS

I neofiti dello sviluppo mobile a volte rimangono sorpresi dalla varietà e dall’alto numero di errori che si manifestano quando si va a rilasciare la propria app. Generalmente su iOS grazie all’uniformità dei dispositivi non si hanno grossi problemi, ma in certe occasioni capita comunque di imprecare a lungo.

Qualche giorno fa improvvisamente la mia applicazione ha smesso di avviarsi sul dispositivo. Sul simulatore andava tutto liscio, e i certificati sembravano tutti a posto, ma dall’oggi al domani non c’era più verso di farla avviare sull’iPad. Dopo qualche ora di maledizioni alla Apple e alla sua politica nazifascista di gestione dei certificati, ho avuto la “brillante” idea di guardare i log del dispositivo, operazione tutt’altro che difficile ma che non capita di dover fare spesso.
Ebbene leggendo il log trovai l’errore immediatamente, avevo solamente scritto male la require di un modulo CommonJS, inserendo una lettera minuscola dove andava maiuscola. Nessun problema sul simulatore ma sul dispositivo questa piccola svista mandava in crash l’interprete Javascript.
Tutto bene quel che finisce bene… e velocemente.

Per chi di voi non sapesse di cosa sto parlando, vi basti sapere che Xcode nel menù Window ha una voce Devices che permette di mettere le mani su tutti i dispositivi connessi al vostro Mac, compresi i simulatori.

I dispositivi sul menù di Xcode

I dispositivi sul menù di Xcode

Dalla finestra dei dispositivi non sono solo i log di questi ultimi ad essere accessibili, ma anche le cartelle di proprietà delle varie app (container).

Log dei dispositivi e container delle applicazioni

Log dei dispositivi e container delle applicazioni

Dulcis in fundo, se vi piace mettere le mani all’interno dei file delle applicazioni usando il Finder ma navigando nelle directory dei simulatori vi capita di perdervi tra quella ventina di identificatori alfanumerici indistinguibili, ricordate che dalla schermata dei dispositivi è anche possibile ottenere l’identificatore associato a ogni simulatore, così da andare a colpo sicuro in quel marasma di caratteri e numeri. I dispositivi virtuali si trovano tutti all’interno di /Users/username/Library/Developer/CoreSimulator/Devices, da lì in avanti ci vuole la bussola.