Ionic 2: prime impressioni

Nel mondo frontend da qualche settimana si parla sempre più spesso di Angular2, nuova versione del famosissimo framework di Google. Ad oggi siamo alla 2.0-rc5 e ci stiamo avvicinando alla versione 2.0 final. Parallelamente il team di Ionic sta portando avanti i lavori su Ionic 2, basato per l’appunto su Angular2. Di Ionic abbiamo già parlato in precedenza, ma per chi non ne avesse mai sentito parlare Ionic è un framework basato su Apache Cordova e AngularJS che vi permette di creare applicazioni mobile utilizzando tecnologie web.

Questo post non sarà una guida introduttiva. Non avrebbe senso in questo momento in cui il framework non è ancora stabile (siamo alla 2.0-beta11 e la final uscirà in concomitanza con l’uscita di Angular2). Ci occuperemo invece di analizzare alcune differenze strutturali tra la versione 1.X e la versione 2.0, che sicuramente non verranno stravolte prima della prossima versione stabile.

Navigazione

Secondo chi vi scrive, la navigazione tra le “pagine” è uno dei punti deboli di Ionic. Questo è uno schema degli elementi che formano il sistema di navigazione attuale di un’applicazione creata con questo framework.

Ionic Navigation System

Ionic Navigation System

Come vediamo gli elementi sono due. Il primo è ui-router, libreria che è diventata uno standard de facto nelle applicazioni AngularJS. Sopra a questo sistema Ionic ha creato il service $ionicHistory che permette di gestire le transition e una cache delle view per aumentare le performance. Ionic 2 avrebbe potuto utilizzare @angular/router, il pacchetto ufficiale di Angular2 per la gestione delle rotte. Invece ha optato per una soluzione completamente differente. Prima di tuffarci nel codice per capire come è stato affrontato questo argomento, analizziamo il flusso di navigazione delle normali applicazioni mobile. Se volessimo schematizzare (e semplificare) al massimo, il flusso di navigazione di un’app è uno stack di viste.

Schema di uno stack

Quando apriamo un’app ci troviamo in una home, cliccando ci muoviamo in una nuova vista (push), premendo “back” torniamo alla vista precedente (pop). In un’app mobile, anche se ibrida, gli URL sono praticamente inutili. Ad un’app mobile non è richiesto di essere RESTful, quindi sforzarsi di utilizzare un sistema simile a quello delle web applications classiche non solo è errato ma credo che sia anche dannoso per il design del codice.

Ionic 2 quindi utilizza un provider apposito per gestire la navigazione, chiamato NavController. Questo provider ha pochi metodi tra cui, per l’appunto, push e pop. Vediamolo subito in azione con un esempio, una piccola applicazione con un elenco di utenti e una view di dettaglio. Iniziamo la nostra analisi dalla lista.

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

import { Users } from '../../providers/users/users.service';

import { DetailPage } from '../detail/detail';

@Component({
  templateUrl: 'build/pages/list/list.html',
  providers:[Users]
})
export class ListPage {
  userList: any;

  constructor(private navCtrl: NavController, private users: Users) {
    this.userList = users.list();
  }

  onItemClick(user) {
    this.navCtrl.push(DetailPage, {
      user
    });
  }
}

Come vedete quando viene invocato il metodo onItemClick uso il NavController per far apparire la view DetailPage, inoltre le passo come parametro l’utente di cui si vuole visualizzare il dettaglio. Passiamo ora al codice del dettaglio.

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';

@Component({
  templateUrl: 'build/pages/detail/detail.html'
})
export class DetailPage {
  user: any;

  constructor(private navCtrl: NavController, private navParams: NavParams) {
    this.user = navParams.get('user');
  }

  goBack(){
    this.navCtrl.pop();
  }
}

Come vedete qui invece utilizzo pop per tornare indietro. Altra cosa molto interessante da notare è che grazie al provider NavParams posso ricevere l’utente corrente che mi è stato inviato dalla view precedente. Rispetto ad un’applicazione gestita tramite URL è un grosso passo avanti in quanto posso ricevere dati complessi. Nel sistema di rotte di Ionic 1.X avrei dovuto ricavare l’id dell’utente dalla rotta e caricarlo da un service in qualche modo.

Il nuovo ionic serve

Il nuovo ionic serve

Ionic Native

Altra novità è l’accesso alle feature del dispositivo. In Ionic 1.X si consiglia l’utilizzo di ngCordova, wrapper AngularJS dei plugin di cordova più famosi. Il progetto è sempre mantenuto dal team di Ionic, ma nello stub base di Ionic questo progetto non viene inserito. Di conseguenza molti sviluppatori alle prime armi utilizzano direttamente Apache Cordova creando un codice poco leggibile, o per lo meno poco Angular-style. Anche nella nuova versione l’accesso al dispositivo è riservato ad un progetto separato chiamato Ionic Native, ma questa volta il pacchetto viene installato automaticamente all’avvio di un nuovo progetto. Ionic Native non è legato ne ad Ionic, ne ad Angular2. Ma può essere utilizzato in qualsiasi progetto Apache Cordova che supporti Ecmascript6. Vediamo subito un’utilizzo di alcuni dei plugin disponibili.

@Component({
  templateUrl: 'build/pages/home/home.html'
})
export class HomePage {

  private pos;
  private watchGeolocation;
  private watchThreeDeeTouch;
  private isThreeDeeAvailable;
  private threeDeeData;
  private imageUrl;
  private watchAcceleration;
  private acceleration;

  constructor(private platform: Platform) {
    this.threeDeeData = {};
    this.pos = {};
    this.imageUrl = "http://www.e-xtrategy.net/wp-content/themes/ex2011/images/logo-extrategy-new.png";

    platform.ready().then(() => {
      this.watchGeolocation = Geolocation.watchPosition().subscribe((pos) => {
        this.pos = pos;
      });

      ThreeDeeTouch.isAvailable().then(isAvailable => {
        this.isThreeDeeAvailable = isAvailable;
        if(isAvailable){
          this.watchThreeDeeTouch = ThreeDeeTouch.watchForceTouches().subscribe((data) => {
            this.threeDeeData = data;
          });
        }
      });

      this.watchAcceleration = DeviceMotion.watchAcceleration().subscribe((acceleration: AccelerationData) => {
        this.acceleration = acceleration;
      });
    });
  }

  openActionSheet() {
    ActionSheet.show({
      'title': 'What do you want to do?',
      'buttonLabels': ['Destroy the world','Save the world'],
      'addCancelButtonWithLabel': 'Cancel'
    }).then((buttonIndex) => {
      console.log(buttonIndex);
    });
  }

  startCamera() {
    const options = {
      quality: 50,
      sourceType: Camera.PictureSourceType.CAMERA,
      encodingType: Camera.EncodingType.JPEG
    };

    Camera.getPicture(options).then((imageData) => {
      this.imageUrl = imageData;
    });
  }

  ngOnDestroy(){
    this.watchGeolocation.unsubscribe();
    this.watchAcceleration.unsubscribe();
    if(this.watchThreeDeeTouch){
      this.watchThreeDeeTouch.unsubscribe();
    }
  }
}

Come potete vedere gli oggetti che vengono utilizzati a comando (come la fotocamera) utilizzano le Promise, mentre tutti i comandi che sono in ascolto del sistema (come il gps) utilizzando gli stream di RxJs.

Esempio di applicazione con Ionic Native

Esempio di applicazione con Ionic Native

Conclusioni

Per quanto nutra dei dubbi su Angular2 e ne giustifico la complessità solo su applicazioni medio/grandi, Ionic 2 mi ha entusiasmato. Il fatto di appoggiarsi ad un framework basato su componenti e il nuovo sistema di navigazione lo rendono concettualmente simile ad altri framework in circolazione, uno su tutti React Native. Il consiglio che do è quindi di utilizzare Ionic 2 nei nuovi progetti appena sarà disponibile la final. Unico accorgimento che terrei è quello di affiancargli un framework per lo state management come Redux o MobX. In questo modo Ionic 2, come è giusto che sia, sarà solo uno strumento per gestire il layer di view della vostra architettura e in futuro potrà essere facilmente sostituito con qualcos’altro. Come di consueto i più curiosi possono trovare il codice completo degli esempi su GitHub. Alla prossima!

Francesco Strazzullo

Faccio il Front-end engineer per extrategy dove mi occupo di applicazioni Angular, React e applicazioni mobile. Da sempre sono appassionato di Architetture software e cerco di applicarle in maniera innovativa allo sviluppo frontend in generale.

  • Alberto

    Interessante articolo, grazie.
    Personalmente per lavoro ho creato un’app usando Xamarin e mi sono trovato abbastanza bene anche se ho riscontrato pro e contro (come molti linguaggi di programmazione ovviamente).
    Avevo avuto una breve esperienza con Ionic 1 e ho tentato la conversione dell’app in Ionic 2 ma ho riscontrato diverse problematiche, soprattutto con librerie npm e loro utilizzo e alcune cose non funzionano ancora (e sto usando la versione RC2); forse non è ancora pronto. Nelle ultime settimane mi sono cimentato anche con NativeScript, e cose nelle quali mi ero bloccato/rallentato qui sono andate via lisce come l’olio. I due framework si somigliano e dato che lato logica sono scritti in ts e usano angular2 ma è ancora troppo presto per giungere a conclusioni.

    Consigli su quale puntare o come muovermi dato che ho dedicato non moltissimo tempo ad entrambi?
    O rimanere con Xamarin?
    Grazie per un’eventuale risposta

    • Ciao Alberto,
      Ovviamente non è una domanda facile a cui rispondere. In realtà credo che la scelta dipenda sempre da due fattori. Il primo è il team con il quale lavori: se nel team hai persone che sono preparate su sviluppo Web allora Ionic1/2 può essere una buona scelta. Altro punto è l’importanza delle performance per il business del tuo cliente. Se lo so Xamarin vince a mani basse. Non ho ancora avuto modo di provare NativeScript quindi non ho un opinione forte in merito. Se sei interessato ho scritto un articolo su Medium contenenti dei consigli sulle scelte tecnologiche in ambito mobile. Lo puoi trovare qui https://medium.com/@TheStrazz86/choosing-the-right-technology-for-the-right-project-dda9fa27320f#.him5euv0f

      • Alberto

        Grazie, do un’occhiata all’articolo!