Nella lezione precedente abbiamo visto come creare un nuovo progetto scegliendo come soluzione una Blank App (Xamarin.Froms Portable). A questo punto è utile soffermarci sul fatto che Xamarin offre due diversi approcci per la creazione di soluzioni cross-platform. Vedremo dunque quali sono e focalizzeremo l'attenzione sullo Shared Assets Project.
App cross-platform: gli approcci di Xamarin
Nel creare una nuova soluzione cross-platform, possiamo determinare fin dall'inizio la
modalità di condivisione di codice tra i progetti delle piattaforme che comporranno la nostra soluzione. La scelta, come abbiamo visto la scorsa lezione, è ricondotta a due possibili modalità di condivisione:
Modalità di condivisione | Descrizione |
---|---|
Shared Assets Project (SAP) | Offre la possibilità di condividere il codice attraverso l'intera soluzione, sfruttando le direttive del compilatore per includere differenti porzioni di codice, specifiche per ogni piattaforma. |
Portable Class Libraries (PCLs) | A differenza degli Shared Project, l'approccio PCL permette di usare un sottoinsieme di librerie offerte dal .NET framework per sfruttare lo stesso codice nei progetti che compongono l'intera soluzione. L'insieme di librerie da utilizzare è limitato dalle piattaforme che si desidera supportare per la propria applicazione. |
Nella precedente lezione abbiamo creato una nuova soluzione sfruttando le PCL, ma questa non è sempre la scelta migliore per la creazione delle nostre app. Infatti, per app sufficientemente semplici potrebbe essere più conveniente usare una soluzione Shared Project invece che PCL. Cerchiamo, quindi, di comprendere come deve essere effettivamente strutturata l'architettura della nostra applicazione e come prendere questa decisione in modo che si adatti al meglio alle nostre esigenze di sviluppo.
Architettura di una soluzione cross-platforms
Nella figura seguente è riportato il classico esempio di un'architettura cross-platforms che offre il riutilizzo del codice attraverso le varie piattaforme.
In accordo con le linee guida di Xamarin, e più in generale dal ben noto pattern architetturale Layers, è possibile suddividere la nostra soluzione essenzialmente in due macro progetti:
Core Project | È il cuore della nostra applicazione e si compone degli elementi essenziali, come l'accesso a dati e servizi remoti e alla logica di business della nostra applicazione |
---|---|
Platform-Specific Application Projects | È l'insieme dei progetti delle piattaforme che si desidera supportare per la propria app. In particolare, ogni progetto dovrebbe essere costituito dalla gestione dell'interfaccia utente (UI) e dalla gestione di specifiche funzionalità delle piattaforme tra il layer relativo alla logica di business della nostra applicazione e l'UI |
Con riferimento alla figura precedente, possiamo identificare il Core Project con il contenitore Share Code, che permette una condivisione del codice attraverso PCL o SAP e le piattaforme che si desidera supportare che rientrano nelle Platform-Specific Application Projects.
L'organizzazione del Core Projects è basata sull'utilizzo del ben noto pattern Layers, un approccio per suddividere il codice in un insieme di strati, ciascuno responsabile di uno specifico comportamento dell'app:
- il Business Layer conterrà tutta la logica e le operazioni principali che offriranno l'interazione con l'utente;
- il Data Access Layer esporrà un set di API per l'accesso ai dati del database, API che saranno richiamate dal Business Layer tramite l'uso di opportune interfacce.
Oltre all'impiego dei layer, è consigliato avere dimestichezza e impiegare altri importanti software design pattern tra cui Model-View-Controller (MVC), Singleton e Façade.
Applicare questi pattern software renderà più semplice creare un'app ben strutturata e facile da gestire nel tempo. Compresa l'architettura generale di una soluzione Cross-Platform, è necessario analizzare cosa comporta la creazione di una soluzione Xamarin.Forms basata su PCL o SAP per valutare quale sia l'approccio migliore per la nostra app. In questa lezione esamineremo SAP.
Shared Asset Project
L'approccio basato su Shared Project fa sì che il codice sia condiviso tra i progetti di interesse durante la compilazione della soluzione. Vediamo nella prossima figura come cambia l'architettura, che abbiamo visto in precedenza.
Concettualmente, lo Shared Project (e i suoi layer) vengono copiati in ogni progetto della soluzione che lo referenzia, e viene compilato come parte del progetto.
I progetti basati su questo approccio hanno un limite: i progetti Android e iOS accedono ad una versione del .NET framework che differisce da quella usata per i progetti Windows. È necessario differenziare il codice per ogni piattaforma supportata per effettuare l'operazione di interesse, come ad esempio l'accesso al database.
La soluzione a questo problema è offerta dal supporto alle direttive C# al compilatore:
#if
#elif
#endif
L'utilizzo di queste direttive è combinato con dei simboli che permettono di identificare le piattaforme. Quelli di principale interesse sono:
Simbolo | Descrizione |
---|---|
__MOBILE__ |
Impiegato nei progetti iOS e Droid |
__IOS__ |
Definito nel progetto iOS |
__ANDROID__ |
Definito nel progetto Droid |
__ANDROID_nn__ |
Definito per Android, dove nn rappresenta il livello delle API per cui eseguire una particolare azione |
WINDOWS_PHONE_APP |
Definito nel progetto per Windows Phone |
WINDOWS_UWP |
Utilizzato nel progetto delle UWP |
Questi simboli sono specifici per ogni progetto e sono definiti all'interno delle Proprietà del progetto. Verifichiamolo per il progetto iOS:
- clicchiamo con il tasto destro sul progetto, e selezioniamo Proprietà;
- dal menu laterale, selezioniamo Compila;
- alla voce Simboli di compilazione condizionale vedremo i due simboli
__MOBILE__
e__IOS__
.
Nel progetto Android non troveremo però il simbolo __ANDROID__
. Ciononostante, esso è comunque definito e riconosciuto da Xamarin.
Tramite la combinazione dei simboli e delle condizioni #if-#elif
, possiamo integrare funzionalità specifiche delle piattaforme di interesse aggiungendo, nei metodi che lo richiedono, un blocco di istruzioni condizionali del tipo seguente:
#if __IOS__
// codice specifico per iOS
#elif __ANDROID__
// codice specifico per Android
#elif WINDOWS_PHONE_APP
// codice specifico per Windows Phone
… //supporto agli altri progetti
#endif
Così facendo, durante la compilazione, lo Shared Project sarà compilato come parte di ogni progetto, e attraverso le direttive del compilatore verrà utilizzato solo il codice specifico per quella piattaforma. Se un progetto non referenzia lo Shared Project, non potrà disporre delle funzionalità che offre.