Archivi tag: xamarin

Weee! Xamarin Forms anche su web “grazie a” Ooui

Chi frequenta il mondo .NET e in particolare quello di Xamarin non può non conoscere Praeclarum, al secolo Frank A. Krueger, sviluppatore al limite del mitologico con un profilo pubblico Github che tra le altre cose annovera sqlite-net (libreria per usare Sqlite con Xamarin) e Continuous (IDE per iOS sviluppato in F#).
Ebbene il buon Frank da giugno dell’anno scorso sta lavorando a Ooui, libreria nuget con cui far girare applicazioni Xamarin Forms su un browser.

Il logo è una puzzola

Detta così potrebbe sembrare quasi una minaccia perché è cosa nota che Xamarin Forms non vada proprio del tutto a genio a molti sviluppatori, e il sottoscritto è tra questi, ma è anche innegabile lo sforzo della Microsoft di far evolvere e stabilizzare questa tecnologia, quindi ben venga l’apertura di nuovi filoni che possano aiutare a farla crescere.

Come è stata accolto Ooui nell’ambiente

La faccio breve: seppur sia ancora un progetto quanto meno acerbo, si è manifestato un certo entusiasmo. L’idea di riutilizzare su più piattaforme la stessa base di codice e di conoscenze fa festa. Un bell’articolo da leggere è quello di Telerik, dove l’autore cerca di spiegare i vari approcci e il perché non bisogna a vederla come una rinascita di Silverlight.

https://www.telerik.com/blogs/xamarin-forms-on-the-web

Molto interessante anche il contributo di Adam Pedley altro soggetto che non si può non conoscere se si lavora con Xamarin, in cui Adam spiega come percorrere l’ultimo miglio per far diventare la nostra applicazione web basata su Xamarin.Forms una Progressive Web App a tutti gli effetti aggiungendo manifest e webworker.

https://xamarinhelp.com/create-a-pwa-in-xamarin-forms-with-ooui-wasm/

Il mio esperimento


https://decimaltime.azurewebsites.net/

Un orologio. Decimale. C’è un motivo, e potete leggerlo nel readme del repository. L’orologio è anche tra gli esempi di Xamarin e tra quelli di Ooui, ma nel nostro ci sono un po’ di casi in più: mix di binding e non, immagine di sfondo, popup, libreria nuget per il calcolo delle date… un esempio abbastanza interessante su come trasformare velocemente un’applicazione mobile scritta con Xamarin Forms in webapp utilizzando Ooui.
Nel repository trovate l’applicazione iOS, quella Android (pubblicata anche su PlayStore), l’applicazione web basata su WebAssembly, e quella web ma con backend in cloud e web-socket. Quella sopra è la versione “non wasm”, avviando quella wasm si nota che a differenza dell’altra vengono scaricate tutte le dll e che non si apre alcuna web-socket perché gira tutto in-process all’interno del browser, ma la trasformazione dei componenti Forms in Html5 funziona allo stesso modo.

La versione basata su web socket…

… e quella che usa wasm

Se per qualche misterioso e irrazionale motivo vi piace l’idea dell’orologio decimale con calendario repubblicano sappiate che su Azure ho pubblicato anche delle API web, basate sulla stessa libreria usata nell’app Xamarin Forms.

À la guerre!

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

Le icone raster su Android sono una noia, viva le shape drawable

Chi sviluppa web, o mobile utilizzando strumenti “simil-web” come Titanium e Ionic, da tempo ha imparato a utilizzare asset vettoriali o font, così da rendere impeccabile la resa sui dispositivi con risoluzioni diverse e facilitare operazioni come la modifica dinamica dei colori.
Purtroppo nel mondo dello sviluppo Android si tende ancora a utilizzare icone raster; per la scalatura nelle varie risoluzioni c’è chi fa tutto a mano, chi utilizza script di varia natura in combinazione con ImageMagick e chi si serve di strumenti online come Android Asset Studio.

Su Android l’approccio migliore al momento sembra quello delle Shape Drawables, ovvero immagini vettoriali definite in xml secondo un determinato formato, funzionalità disponibile solo dalla versione 5 di Android (Lollipop), ma abilitabile anche nelle versioni precedenti abilitando la Support Library.

Segnalo un bell’articolo che spiega benissimo come abilitare l’utilizzo degli asset vettoriali anche sulle versioni pre-lollipop e le modifiche da fare per evitare errori abbastanza str.nzi che possono far perdere qualche ora. Con i dovuti adattamenti tutto ciò vale anche per chi (come me) utilizza Xamarin.

Creazione dell’asset vettoriale da icone material e da svg

Qui sotto ci sono i passi da fare, più o meno, per crearsi con Android Studio un’icona vettoriale utilizzabile in Android. Moltissime sono già presenti tra quelle precaricate (material design), ma è possibile anche generarsele a partire dai propri svg.

Creazione di asset vettoriale da Android Studio

Creazione di asset vettoriale da Android Studio

Selezione di una delle icone material già presenti

Selezione di una delle icone material già presenti

Definizione dei dettagli dell'icona scelta

Definizione dei dettagli dell’icona scelta

Importazione di un'immagine raster in Inkscape

Importazione di un’immagine raster in Inkscape

Ridimensionamento dell'immagine vettoriale

Ridimensionamento dell’immagine vettoriale

Vettorizzazione dell'icona raster

Vettorizzazione dell’icona raster

Modalità di vettorizzazione

Modalità di vettorizzazione

Allineamento del tracciato vettoriale nell'immagine

Allineamento del tracciato vettoriale nell’immagine

Errore in fase di importazione dell'icona vettoriale in Android Studio

Errore in fase di importazione dell’icona vettoriale in Android Studio

Correzione dell'xml

Correzione dell’xml

Anteprima dell'svg importato in Android Studio

Anteprima dell’svg importato in Android Studio

Il risultato: icona vettoriale in formato xml

Il risultato: icona vettoriale in formato xml