UNIVERSITÀ DEGLI STUDI DEL SANNIO FACOLTÀ DI INGEGNERIA CORSO DI LAUREA IN INGEGNERIA INFORMATICA TESI DI LAUREA IN TECNOLOGIE DI PRODUZIONE DEL SOFTWARE STUDIO DI UN FRAMEWORK APPLICATIVO MULTIPIATTAFORMA PER AMBIENTI MOBILE RELATORE: Prof. Luigi Troiano CANDIDATO: Umberto Russo Matr. 195/001063 CORRELATORE: Dott. Maria Carmela Vitelli ANNO ACCADEMICO 2012/2013 A i miei genitori... Sommario Indice delle Figure .................................................................... 6 Indice delle Tabelle .................................................................. 7 CAPITOLO 1 INTRODUZIONE ....................................................................... 8 1.1 Organizzazione del lavoro ................................................ 10 CAPITOLO 2 LE APPLICAZIONI IN AMBITO MOBILE ................................... 12 2.1 Panoramica sui sistemi operativi mobile........................... 12 2.2 Sviluppo di un'app in ambienti nativi ............................... 16 2.3 Ambienti: Android, iOS e Windows Phone ........................ 18 2.4 Realizzazione di un'app attraverso un framework multipiattaforma ................................................................. 27 CAPITOLO 3 PHONEGAP ............................................................................ 29 3.1 Scegliere un buon framework .......................................... 29 3.2 Caretteristiche di PhoneGap ............................................ 32 3.3 Architettura di PhoneGap e il suo modello di programmazione .................................................................. 37 3.4 Linguaggi di programmazione utilizzati e la loro relazione con PhoneGap ..................................................................... 42 3.5 jQuery Mobile: un framework nel framework .................... 50 4 CAPITOLO 4 PORTING DI UN'APPLICAZIONE ............................................. 57 4.1 Interfaccia grafica e navigazione tra le pagine ................... 58 4.2 Persistenza dei dati ......................................................... 67 4.3 Accesso alle API native con PhoneGap.............................. 70 4.4 Interazione con un web server ......................................... 85 CAPITOLO 5 CONCLUSIONI E SVILUPPI FUTURI ....................................... 93 Appendice ............................................................................... 97 BIBLIOGRAFIA ....................................................................... 108 5 Indice delle Figure Figura 1: Build Emulation Flow Android ............................. 20 Figura 2: Layers of iOS ....................................................... 22 Figura 3: Condivisione API Window 8 e Windows Phone 8 .. 24 Figura 4: Architettura Windows Phone 8 ............................ 26 Figura 5: Unificazione delle piattaforme Windows 8 ............ 26 Figura 6: PhoneGap Build Diagram .................................... 36 Figura 7: Architettura PhoneGap ........................................ 39 6 Indice delle Tabelle Tabella 1: Funzioni supportate da PhoneGap per i diversi OS Mobile parte 1 ..................................................................... 34 Tabella 2: Funzioni supportate da PhoneGap per i diversi OS Mobile parte 2 ..................................................................... 34 Tabella 3: Tabella delle affinità Sqlite3 ................................ 55 7 CAPITOLO 1 INTRODUZIONE Sono passati solo pochi anni dall'introduzione sul mercato di dispositivi mobili quali smartphone e tablet, ed è incredibile come questi hanno rivoluzionato il modo di vivere delle persone, oggi è quasi indispensabile potersi connettere ad internet tramite il proprio smartphone per poter usufruire della miriade di servizi atti a fornire un insieme sempre più organizzato di informazioni. Parallelamente allo sviluppo hardware, come sempre accade, il mondo del software ha dovuto reinventarsi per approcciare ad un mercato in crescita esponenziale, giganti dell' IT come Google e Apple hanno rivoluzionato il concetto di "cellulare" a tal punto da da domandarsi quale potrà mai essere lo step successivo. Attualmente esistono milioni di applicazioni mobile, la maggior parte per ambienti Android e iOS, ma si contano almeno una decina di sistemi operativi mobile con caratteristiche diverse. Questo si traduce, per lo sviluppo di applicazioni, nell'utilizzo di innumerevoli strumenti di sviluppo diversi fra loro e un dispendio notevole di risorse atti a garantire il funzionamento delle medesima applicazione sulla maggior parte di questi sistemi operativi. 8 Esistono però delle alternative: infatti, tramite l'utilizzo di opportuni framework applicativi si può risparmiare tempo, risorse e garantire la compatibilità dell'applicazione su diversi sistemi mobile. Lo scopo della seguente tesi è quello di valutare le attuali tecniche di sviluppo di applicativi mobile e confrontarle con l'uso alternativo di framework cross-platform, per comprendere se allo stato attuale è possibile realizzare applicazioni di qualità con un approccio multipiattaforma in grado di competere con lo sviluppo in ambienti nativi. Il vantaggio principale che spinge alla realizzazione di framework per ambienti mobile è certamente l'approccio cross-platform, il quale garantisce un notevole risparmio di risorse sia nella fase di progettazione che di sviluppo. Questo tipo di approccio è stato già brillantemente adoperato in passato, per esempio dalla Sun Microsystem, la quale ha prodotto il linguaggio di programmazione orientato agli oggetti Java, attualmente uno dei più utilizzati al mondo . 9 1.1 Organizzazione del lavoro Il presente lavoro propone lo studio e lo sviluppo di un applicativo multipiattaforma mobile, mediante il porting di un' applicazione già esistente in ambiente Android. Utilizzando il framework PhoneGap sarà possibile evidenziare le tecniche necessarie per il conseguimento dello scopo e valutare le eventuali alternative. Nel Capitolo 2 viene proposta una panoramica sull'ambiente mobile, vengono presi in considerazione gli attuali sistemi operativi più importanti e ne vengono delineate le differenze in termini di progettazione e sviluppo di software. Vengono presentati, inoltre, gli aspetti peculiari dello sviluppo in ambienti nativi e attraverso i diversi framework multipiattaforma oggi disponibili. Nel Capitolo 3 verrà presentato PhoneGap un framework cross-platform mobile realizzato dalla software house statunitense Adobe System, che consente di sviluppare delle applicazioni native attraverso l'utilizzo di tecnologie web quali HTML5 , CSS3 e JavaScript. 10 Nel Capitolo 4 viene concretizzata l'attività di analisi con la descrizione del lavoro svolto per realizzare il porting di un applicativo già esistente, progettato per l'ambiente Android, attraverso l'uso di PhoneGap. Infine nel Capitolo 5 confrontando l'applicazione nativa con quella ottenuta attraverso il porting, sarà possibile comprendere i diversi comportamenti dovuti a modelli di programmazione differenti. Evidenziando, per concludere, vantaggi e svantaggi offerti dall'utilizzo di un framework multipiattaforma rispetto alle tradizionali tecniche si sviluppo in ambienti mobile. 11 CAPITOLO 2 LE APPLICAZIONI IN AMBITO MOBILE Un'applicazione per dispositivi mobili si differenzia da quelle tradizionali sia per il supporto con cui viene usata sia per la concezione che racchiude in sé. Generalmente questo tipo di applicazioni vengono definite anche "App", poiché rispetto ad un'applicazione classica risultano più semplici e leggere ed hanno il compito di ampliare le capacità native del dispositivo su cui vengono installate. Negli ultimi anni però il mondo delle app è diventato sempre più complesso e la semplicità che caratterizzava le applicazioni mobile sta lasciando il posto a software più articolati, complice anche la repentina evoluzione hardware dei dispositivi quali smartphone e tablet. 2.1 Panoramica sui sistemi operativi mobile Un sistema operativo mobile, detto anche "mobile OS", controlla un dispositivo mobile con lo stesso principio con cui i sistemi operativi desktop controllano un PC o un Laptop. 12 La maggior parte delle problematiche affrontate da un sistema operativo mobile sono le stesse della controparte desktop: ossia la gestione della memoria RAM, l'utilizzo della CPU da parte dei processi attivi, la gestione di un file system ecc. In più, hanno il difficile compito di gestire fattori non presenti in ambienti desktop, come ad esempio: la gestione limitata delle risorse, l'assenza di alimentazione esterna, differenti tecnologie per l'accesso ad internet (WiFi, GPRS, HSDPA), nuovi metodi di immissione testuale ecc. Inoltre non bisogna dimenticare che uno smartphone è principalmente un telefono, un mezzo di comunicazione e quindi un OS mobile deve poter gestire anche questa fondamentale funzionalità. Una delle prime aziende informatiche a lavorare su sistemi operativi mobile più evoluti è stata la Microsoft Corporation, la quale nel 2005 lancia Windows Mobile 5. Successivamente nel 2007 Apple rivoluziona il mondo degli smartphone proponendo il suo sistema operativo mobile iOS (anche se inizialmente era chiamato iPhone OS), mentre l'anno successivo nel 2008 Google lancia la prima versione di Android. Di seguito una lista dei principali sistemi operativi mobile, che attualmente sono presenti sul mercato ed equipaggiano smartphone ed alcuni tablet. 13 iOS: sviluppato da Apple a partire dal 2007, caratterizzato da un kernel1 ibrido XNU basato su kernel Mach e FreeBSD, il modello del sorgente è proprietario anche se il nucleo Darwin è open source, è disponibile un SDK per lo sviluppo di app attraverso Xcode, attualmente è uno dei principali OS mobile. Android: sviluppato da Google a partire dal 2008 caratterizzato da un kernel linux monolitico, il modello del sorgente è completamente open source infatti è possibile trovare diverse varianti del sistema operativo sviluppate da appassionati, è disponibile un SDK per lo sviluppo di app attraverso Eclipse che comunque non rappresenta l'unico metodo per sviluppare in ambiente Android. Insieme ad iOS attualmente è uno dei principali OS mobile. Windows Phone: sviluppato da Microsoft Corporation a partire dal 2010 caratterizzato da un kernel Windows NT / Windows CE, il modello del sorgente è completamente proprietario, è disponibile un SDK per lo sviluppo di app attraverso Microsoft Visual Studio 2010 Express, anche se non è diffuso come Android e iOS rappresenta comunque un sistema operativo mobile presente in un ampia fetta di mercato. 1 Il kernel costituisce il nucleo di un sistema operativo, fornisce ai processi in esecuzione un accesso sicuro e controllato all'hardware. 14 BlackBerry: sviluppato da Research In Motion a partire dal 2002 caratterizzato da un kernel sviluppato in C++ con la presenza di un livello di astrazione che permette l'utilizzo di librerie scritte in java, il modello del sorgente è completamente proprietario ed è disponibile un SDK nativo per lo sviluppo di app in C/C++, anche se è possibile utilizzare altre tipi di linguaggi di programmazione. Open WebOS: sviluppato da Palm dal 2009 e successivamente acquistato da Hewlett-Packard, è caratterizzato da un kernel Linux monolitico, il modello del sorgente è proprietario con alcune parti open source, è disponibile un SDK per lo sviluppo di app attraverso vari linguaggi di programmazione tra cui C/C++. Symbian OS: sviluppato da Symbian Foundation a partire dal 2001, caratterizzato da un kernel del tipo Microkernel , ha un modello di sorgente libero, fino ad oggi ha equipaggiato quasi esclusivamente dispositivi nokia ed ormai il suo stato di sviluppo è concluso, è disponibile un SDK per lo sviluppo di app in un dialetto del C++ chiamato Symbian C++. Bada: sviluppato da Samsung dal 2010, caratterizzato da un kernel ibrido RTOS / Free BSD Kernel / Linux kernel, ha un modello di sorgente misto alcune parti sono open source, altre proprietarie o libere, è disponibile un 15 SDK per lo sviluppo di app in C++ mediante l'ambiente di sviluppo Eclipse. Nei prossimi paragrafi e capitoli per lo scopo che si prefigge il presente lavoro di tesi, verranno presi in considerazione i sistemi operativi più diffusi nell'attuale mercato mobile ossia Android [1], iOS [2] e Windows Phone [3]. 2.2 Sviluppo di un'app in ambienti nativi Sviluppare un applicativo mobile in ambienti nativi vuol dire utilizzare una serie di strumenti messi a disposizione dell'azienda produttrice del sistema operativo, tra cui l'importantissimo SDK 2 e la documentazione ad esso associata. Non tutti gli SDK sono uguali in termini di componenti, i quali formano l'ambiente di sviluppo. Infatti gli strumenti solitamente messi a disposizione per gli sviluppatori sono: un compilatore, che dà la possibilità di tradurre il codice sorgente in un eseguibile, una serie di librerie standard dotate di interfacce pubbliche, tecnicamente definite API 3 e la 2 Software Development Kit, insieme di tools messi a disposizione dal produttore di un sistema operativo per realizzare un software in un determinato ambiente. 3 Acronimo di Application Programming Interface, insieme di procedure disponibili al programmatore raggruppate a formare un insieme di strumenti specifici per eseguire un determinato compito. 16 documentazione sulle licenze da utilizzare per distribuire programmi creati con l'SDK. Questi componenti di base possono essere estesi con strumenti di vario tipo come: compilatori per diversi linguaggi di programmazione, IDE 4 molto avanzati e simulatori che permettono di simulare i dispositivi mobili. Molti SDK sono disponibili gratuitamente mentre altri vengono distribuiti attraverso l'uso di licenze commerciali, questo panorama così ampio permette di comprendere come la giusta scelta di sviluppo in ambienti specifici sia di peculiare importanza, poiché l'utilizzo di più kit di sviluppo richiede un cospicuo utilizzo di risorse. A complicare maggiormente lo sviluppo in ambienti nativi è l'utilizzo dei più disparati linguaggi di programmazione; si passa dai più diffusi C/C++ a dialetti degli stessi, da linguaggi orientati al web come JavaScript a tecnologie più datate come J2ME. Nel caso di studio riguardante questo lavoro gli ambienti di sviluppo analizzati riguardano i sistemi operativi Android, iOS e Windows Phone, di cui segue una trattazione. 4 Integrated Development Environment, ambiente di sviluppo integrato che aiuta i programmatori nello sviluppo del codice sorgente di un programma. 17 2.3 Ambienti: Android, iOS e Windows Phone Android Le applicazioni in ambiente Android sono sviluppate all'interno di un framework5, ossia una struttura dati specifica. Solitamente viene utilizzato come ambiente di sviluppo integrato Eclipse, il quale attraverso l'uso di plug-in può estendere le sue funzionalità e integrare completamente tutte le caratteristiche del SDK Android. Le applicazioni Android sono caratterizzate da una certa dualità: da un lato, si trovano le parti dinamiche (sviluppate in un dialetto del linguaggio Java) che costituiscono l'applicazione mobile, come la gestione degli eventi. Dall'altro si trovano le parti statiche, ad esempio alcuni elementi delle interfacce, queste vengono scritte in XML6. Questa suddivisione tra parti dinamiche e statiche rappresenta in realtà un'astrazione, utile comunque per comprendere il modello di programmazione generale su cui si basa lo sviluppo per il sistema operativo Android. In effetti le applicazioni realizzate per questo SO vengono interpretate dalla Dalvik Virtual Machine in modo molto simile a ciò che avviene in ambienti Java con la Java Virtual Machine. 5 Un framework è una struttura logica di supporto su cui un software può essere progettato è realizzato. eXtensible Markup Language, linguaggio di markup basato su un meccanismo sintattico che consente di definire e controllare il significato degli elementi contenuti in un documento o in un testo. 6 18 Quando si compila un sorgente scritto in dialetto Java per Android il compilatore produce un codice che potremmo definire "intermedio" chiamato Bytecode; quest'ultimo viene interpretato dalla Dalvik Virtual Machine e solo a questo punto si ha la reale esecuzione dell'applicazione. Questo approccio, ovviamente ripreso da ciò che avviene già in ambienti Java, è molto interessante poiché permette di eseguire un'applicazione su ogni dispositivo Android anche con architetture hardware diverse. Per ogni dispositivo esiste una versione specifica della Dalvik Virtual Machine in grado di interpretare nel medesimo modo la stessa applicazione, che ovviamente viene scritta e compilata in bytecode solo una volta. In questo modo la filosofia "write once run everywhere" coniata dalla Sun Microsystem viene, in modo più limitato, adottata anche dall'ambiente Android estendendo la portabilità del codice su architetture hardware diverse fra loro. Come risultato di questa idea, molti costruttori hanno deciso di adottare come sistema operativo mobile Android, potendo cosi fornire ai propri utenti un ambiente condiviso da moltissimi altri utenti. Un altro elemento che compone un'applicazione Android è il file "Manifest.xml", un documento scritto in XML che descrive l'applicazione al dispositivo prescelto definendo i contenuti e il comportamento dell'applicazione stessa. All'interno di questo file sono elencate le Activity e i Service con i permessi che l'applicazione necessita per funzionare correttamente. Infine uno strumento di fondamentale importanza completa 19 il kit di sviluppo Android: l'emulatore. Esso permette di emulare diversi dispositivi e versioni di Android dando così la possibilità allo sviluppatore di eseguire accurate sessioni di debug. Figura 1: Build Emulation Flow Android iOS Il sistema operativo iOS di Apple usa una variante del kernel "XNU Kernel" utilizzato nell' OS per ambienti desktop "Mac OS X", ed è per questo motivo che il pacchetto SDK messo a disposizione dalla Apple per lo sviluppo di applicazioni mobile è molto simile, in termini di risorse disponibili, alla controparte desktop. L'IDE utilizzato in questo tipo di ambiente è Xcode, va però specificato che il pacchetto SDK Apple per lo 20 sviluppo di software è compatibile solo ed esclusivamente con ambienti desktop Apple. Questo di per sè rappresenta già una limitazione in quanto si rende necessario l'acquisto di una macchina desktop Apple, inoltre la licenza di iOS non ne permette l'installazione su hardware di terze parti. Tornando alla descrizione del pacchetto SDK esso comprende: Cocoa Touch: un framework per la creazione di interfacce grafiche utilizzabile per i dispositivi iPhone, iPad e iPod. Media: un set di strumenti dedicati alla creazione di contenuti multimediali come audio e grafica, in particolare sono presenti librerie come OpenAL e OpenGL ES. Core Services: per la gestione di funzionalità più specifiche come la geolocalizzazione (Core Location), i servizi di rete, la gestione dei Threads, ecc. Core OS: per la gestione di funzionalità caratteristiche del Sistema Operativo come TCP/IP, Sockets, Power Management, File System, ecc. Queste componenti vengono viste come un insieme di livelli attraverso i quali iOS implementa le proprie funzionalità, il livello più basso è rappresentato dal Core OS mentre il livello più alto è il Cocoa Touch. 21 Figura 2: Layers of iOS Oltre alla Xcode toolchain appena presentata, il pacchetto SDK contiene un efficiente simulatore di iPhone utilizzato per testare le app prima dell'effettivo deploy su un reale dispositivo. Il linguaggio di programmazione necessario per realizzare applicazioni in ambiente iOS è l'Objective-C , che è un linguaggio orientato agli oggetti e di fatto rappresenta un'estensione del linguaggio C. Essendo un'estensione, l'Objective-C, mantiene una compatibilità totale con i costrutti utilizzati nel linguaggio C. Anche le applicazioni iOS, come quelle Android, vengono sviluppate mediante l'utilizzo di un framework tramite il quale è possibile accedere alle interfacce di sistema. In questo caso il framework è visto come una 22 directory che contiene una serie di librerie dinamiche condivise e risorse a supporto di tali librerie. Il compilatore utilizzato per lo sviluppo di app in ambiente iOS si chiama Apple LLVM Compiler. Quest'ultimo a differenza di Android, dove il codice prodotto dal compilatore viene successivamente interpretato dalla DVM, compila il codice Objective-C producendo direttamente un programma eseguibile. Bisogna precisare infine che il pacchetto SDK di iOS contiene un simulatore di iPhone, che nonostante sia molto performante in termini di velocità, non simula tutte le caratteristiche di un dispositivo reale: per esempio la memoria disponibile sull'emulatore non è limitata come quella presente su di un dispositivo reale. Windows Phone Windows Phone 8 è l'ultima versione del sistema operativo Microsoft destinato agli smartphone. Questo, rilasciato alla fine del 2012, rappresenta un ulteriore passo avanti nei progetti di Microsoft stessa. Bisogna infatti pensare che Microsoft produce anche il famoso sistema operativo desktop Windows 8 e commercialmente sta tentando di unificare (dal punto di vista utente) le diverse versioni dei suoi sistemi operativi. Il pacchetto SDK per lo sviluppo di applicazioni mobile contiene: 23 Microsoft Visual Studio Express 2012 for Windows Phone: un IDE molto avanzato per le fasi di progettazione e sviluppo. Windows Phone Emulator: un emulatore di dispositivi Windows Phone versione 8 e 7. Microsoft Expression Blend for Windows Phone: un tool di design per la realizzazione di interfacce grafiche . XNA Game Studio: uno strumento basato sul framework gratuito XNA per lo sviluppo di videogiochi su più piattaforme come: PC, Xbox 360 e ovviamente Windows Phone. Windows Phone 8 è basato sul kernel Windows NT lo stesso utilizzato appunto in Windows 8, questa sorta di unificazione permette lo sviluppo di applicazioni sia mobile che desktop attraverso l'uso dei linguaggi C++ e C#. Figura 3: Condivisione API Windows 8 e Windows Phone 8 24 Le applicazioni Windows Phone 8 condividono alcuni aspetti con il sistema operativo versione desktop, alcune API e driver models sono condivisi semplificando la fase di sviluppo se si intende operare negli ambienti desktop e mobile contemporaneamente. L'utilizzo del nuovo Kernel NT ridefinisce i diversi livelli dell'architettura che rispetto alla versione precedente, Windows Phone 7, puntano sempre di più a costruire una sorta di unificazione nello sviluppo di applicativi desktop e mobile. 25 Figura 4: Architettura Windows Phone 8 Figura 5: Unificazione delle piattaforme Windows 8 26 2.4 Realizzazione di un'app attraverso un framework multipiattaforma Sviluppare un'applicazione mediante un framework cross-platform implica un approccio differente rispetto alle tecniche tradizionali. La progettazione dell'applicazione deve tener conto delle diverse caratteristiche dei sistemi operativi e dell'hardware dei dispositivi. Infatti nel caso di sviluppo in ambienti nativi, si tende a progettare il software considerando le funzionalità messe a disposizione da un singola piattaforma. Con l'approccio cross-platform è necessario valutare insieme le caratteristiche delle diverse piattaforme su cui verrà rilasciato il software. Se vengono sfruttate le funzionalità comuni tra più sistemi operativi sarà possibile mantenere un unica linea di sviluppo. Ad esempio se consideriamo i dispositivi Android e iOS si può facilmente notare che sulla prima piattaforma citata i dispositivi dispongono di diversi pulsanti soft touch (menu, back button, search, ecc. ) mentre nella seconda piattaforma questi pulsanti sono assenti. Pertanto con un approccio cross-platform, il cui obiettivo è il deployment 7 sui sistemi sopra citati, non è consigliabile utilizzare nell'applicazione il pulsante soft touch menu (relativo alla piattaforma Android), poiché non esiste una funzione equivalente in iOS. 7 Il deployment è una fase del ciclo di vita del software che conclude lo sviluppo e da inizio alla manutenzione. 27 Questo comporterebbe la nascita di due linee di sviluppo parallele, andando contro l'idea che sta alla base dell'approccio multipiattaforma. Un altro aspetto da affrontare riguarda la scelta del framework crossplatform, di cui oggi ne esistono almeno una ventina che si differenziano per svariati aspetti. Un'attenta trattazione delle caratteristiche necessarie per un buon framework verrà affrontata nel prossimo capitolo. Di seguito un elenco dei framework più conosciuti: PhoneGap Appspresso AppFurnace Application Craft NS Basic/App Studio WorkLight QuickConnectFamily Rhodes 28 CAPITOLO 3 PHONEGAP PhoneGap è un Framework cross-platform mobile prodotto inizialmente da Nitobi e successivamente acquistato da Adobe System. Esso consente di sviluppare delle applicazioni per dispositivi mobili attraverso l'uso delle tecnologie orientate al web come: HTML5, CSS3 e JavaScript; al posto di linguaggi specifici per ogni device come l'Objective-C. Il risultato che si ottiene è un'applicazione ibrida, poiché il rendering del layout avviene attraverso l'utilizzo delle WebView presenti in modo nativo all'interno delle User Interface dei diversi Sistemi Operativi Mobile. Le caratteristiche ibride riguardano anche il lato back-end 8 dell'applicazione; poiché quest'ultima non è soltanto una web app, essa ha accesso alle API native del dispositivo. Questa caratteristica non è presente nelle applicazioni esclusivamente web based. 3.1 Scegliere un buon framework La scelta di un buon framework multipiattaforma per lo sviluppo di applicazioni mobile è di fondamentale importanza. Nelle fasi che 8 Il back-end rappresenta la parte software che elabora i dati generati dal front-end, che a sua volta è la parte software che gestisce l'interazione con l'utente. 29 caratterizzano la realizzazione di un software, in generale analisi, progettazione, implementazione e collaudo, risulta conveniente utilizzare strumenti che agevolano le varie fasi. Tutto questo si traduce in un notevole risparmio di risorse e tempo, inoltre un framework di qualità si riconosce anche dalla notorietà della software house che lo produce. Nel caso di PhoneGap parliamo di Adobe System, un'azienda presente sul mercato da diversi anni è che ha sempre realizzato prodotti di successo. Bisogna poi ricordare che un framework multipiattaforma permette l'accesso alle API native dell'ambiente mobile specifico, e non tutti i framework esistenti supportano tutte le funzionalità messe a disposizione delle diverse API. Un'altra caratteristica da notare riguarda le tempistiche di rilascio delle nuove versioni di un determinato framework. Rilasci relativamente frequenti danno l'opportunità di comprendere che il framework in questione è seguito ed utilizzato da molti e per tanto raggiunge fasi di sviluppo avanzate che permettono l'implementazione di funzionalità sempre più complete. La possibilità di espandere le caratteristiche di un framework è un altro punto a favore, poiché i progetti software più importanti sono sempre accompagnati da folte community di appassionati. Queste ultime 30 sviluppano plug-in di terze parti e creano un'ampia documentazione a corredo di tali estensioni. Infine bisogna sempre pensare quale sarà l'obiettivo da raggiungere con lo sviluppo di un'applicazione mobile. Esistono progetti open source e commerciali che richiedono attenzioni differenti per la successiva fase di distribuzione. Per quanto riguarda i progetti commerciali, il cui obiettivo è la monetizzazione, l'uso di licenze adatte allo scopo è fondamentale. Se non si desidera investire in strumenti per lo sviluppo che adottano a loro volta licenze commerciali, è necessario far riferimento a strumenti comunque professionali che si basano su licenze di tipo: MIT, open source, ecc. La scelta dell'utilizzo di PhoneGap, per il porting di un'applicazione già esistente in ambiente Android , è stata dettata da tutte le caratteristiche sopra elencate, il confronto del framework PhoneGap con altri concorrenti ha portato alla scelta di quest'ultimo in quanto ben rispondeva alle necessità relative al lavoro di porting9. 9 processo di trasposizione di un componente software, volto a consentirne l'uso in un ambiente di esecuzione diverso da quello originale. 31 3.2 Caratteristiche di PhoneGap Il core delle applicazioni PhoneGap utilizza HTML5 e CSS3 per il rendering dell'interfaccia grafica, mentre JavaScript viene utilizzato per implementare la logica dell'applicazione e contemporaneamente per accedere alle funzionalità native messe a disposizione dalle API. HTML5 ha la possibilità, grazie alle sue nuove caratteristiche, di accedere alle funzionalità native del dispositivo, anche se questo approccio non è raccomandabile poiché esso non è ancora uno standard perfettamente definito. Molti dispositivi mobile più datati supportano solo poche caratteristiche del linguaggio di markup HTML5, il World Wide Web Consortium [4] ha annunciato che la prima versione dello standard è prevista per la fine del 2014. Per incorporare l'applicazione realizzata mediante tecnologie web all'interno di una WebView e accedere alle API native, PhoneGap fa ampiamente uso di Foreign Function Iterface. Ossia un meccanismo attraverso il quale un programma scritto in un determinato linguaggio, può chiamare routines o far uso di servizi scritti in un altro linguaggio di programmazione. PhoneGap utilizza una libreria JavaScript comune a tutti Figura 5: Flow Diagram dell’architettura 32 gli ambienti mobile, la quale è collegata attraverso le FFI, ai servizi messi a disposizione delle librerie scritte in linguaggio nativo per ogni piattaforma mobile. In questo modo il codice scritto mediante PhoneGap rimane lo stesso per ogni sistema operativo mobile. Infine per ottenere il codice eseguibile è necessario nei diversi ambienti di sviluppo collegare esclusivamente le librerie native ed eseguire il build 10 dell'applicazione. Questo approccio però, rende le prestazioni dell'applicazione meno performanti rispetto ad un'applicazione sviluppata in ambiente nativo. In realtà quest'ultimo punto è una caratteristica di tutti i framework mobile multipiattaforma, un comportamento tra l'altro prevedibile se si pensa che l'applicazione per poter essere eseguita, deve necessariamente passare per una serie di wrapper. I sistemi operativi supportati da PhoneGap sono: Android, Windows Phone, iOS, Bada, Blackberry, webOS e Symbian. Di seguito alcune tabelle comparative che specificano le funzionalità native supportate da PhoneGap per i diversi sistemi operativi Mobile. 10 Il termine software build sta ad indicare il processo di conversione del codice sorgente in un programma eseguibile. 33 Tabella 1: Funzioni supportate da Phonegap per i diversi OS Mobile parte 1 Tabella 2: Funzioni supportate da Phonegap per i diversi OS Mobile parte 2 34 PhoneGap dispone di una community molto attiva, infatti è possibile trovare una serie di plug-in di terze parti sviluppati per migliorare o estendere le funzionalità originali previste dal framework. Ciò che realmente manca in PhoneGap è un tool che permette di gestire la dinamicità dell'interfaccia grafica e gli effetti di transizione caratteristici delle applicazioni native per ambienti mobile. Questa lacuna viene brillantemente riempita grazie all'utilizzo di JavaScript con il quale è possibile realizzare qualunque effetto grafico, anche se ciò aumenta i tempi di sviluppo e rende il codice molto più complesso. D'altronde la natura stessa di JavaScript permette l'utilizzo di innumerevoli framework e librerie che semplificano lo sviluppo delle interfacce grafiche. Non a caso uno dei framework JavaScript più utilizzati per lo sviluppo di applicazioni PhoneGap è jQuery Mobile [5], il quale implementa una serie di funzionalità che migliorano l'user experience come: componenti di interfaccia grafica, dialog box, messaggi di servizio, elementi dei form, ecc. Di seguito un diagramma molto esplicativo che mostra in che modo vengono estese le funzionalità di PhoneGap con l'uso di plug-in e librerie JavaScript. 35 Figura 6: Phonegap buil diagram Nel dettaglio: viene utilizzato un IDE, ad esempio NetBeans o Eclipse, per la scrittura del codice HTML5, CSS3 e JavaScript. Mediante quest'ultimo è possibile utilizzare librerie esterne o framework JavaScript come jQuery Mobile migliorando cosi l'user experience. Successivamente nella fase di Building si possono aggiungere Plug-in sviluppati per PhoneGap in modo da estendere le funzionalità previste originariamente, ottenendo infine in base all'ambiente in cui viene fatto il deploy un'applicazione pronta per essere eseguita. 36 3.3 Architettura di PhoneGap e il suo modello di programmazione L'architettura di PhoneGap è divisa in quattro livelli software differenti denominati: livello del sistema operativo, livello nativo di PhoneGap, livello JavaScript di PhoneGap e livello applicativo. Il livello del sistema operativo rappresenta quello più basso del framework PhoneGap, cioè la parte che più si avvicina alla struttura del sistema operativo su cui viene eseguita l'applicazione. Quando si sviluppa un'applicazione nativa, attraverso gli strumenti messi a disposizione del produttore del sistema operativo (SDK), si accede direttamente a questo livello, sfruttando cosi le API native previste dall'ambiente. Il livello nativo di Phonegap, chiamato anche "PhoneGap bridge layer", permette al browser, in particolare alle WebView, di accedere alle funzionalità native del dispositivo. Gli sviluppatori di PhoneGap con questo livello hanno creato una prima parte del "ponte" che lega il codice JavaScript con il codice nativo di ogni differente ambiente. Inoltre il "PhoneGap bridge layer" contiene un'altra componente software chiamata "webkit view" che permette di eseguire le applicazioni create dagli sviluppatori. Il livello JavaScript di PhoneGap rappresenta la seconda parte del "ponte" creato nel "PhoneGap bridge layer", esso contiene infatti la seconda parte del codice che permette di legare gli script JavaScript con l'ambiente nativo 37 del dispositivo. Questo livello contiene anche le API definite dal framework PhoneGap, che fungono da wrapper per accedere attraverso i livelli più bassi alle reali API di ogni piattaforma mobile. Questa parte dell'architettura può essere considerata il "cuore" di PhoneGap poiché contiene le interfacce di accesso alle funzionalità native del sistema operativo, permettendo così di accedere attraverso opportuni script a funzionalità come: geolocalizzazione , storage, filesystem, accelerometro, ecc. Per evitare frequenti casi di overhead, la chiamata alle API di PhoneGap a funzioni implementate nativamente nelle WebView viene reindirizzata attraverso questo livello alle API native, a cui è possibile accedere mediante i livelli sottostanti. Infine il livello applicativo rappresenta lo strato più elevato e astratto di PhoneGap, esso contiene l'applicazione realizzata dallo sviluppatore in HTML, CSS e JavaScript. Gli unici strati dell'architettura di PhoneGap accessibili allo sviluppatore sono il livello applicativo e l'interfaccia del livello JavaScript. Tutti gli altri livelli non sono visibili ad un programmatore PhoneGap e questo rappresenta una conseguenza dell'applicazione del principio di incapsulamento. Pertanto una parte di un'applicazione può nascondere informazioni incapsulandole in un costrutto dotato di interfaccia, permettendo l'information hiding. L'incapsulamento riduce il costo da pagare per correggere gli errori in fase di sviluppo di un'app. Questo 38 risultato viene ottenuto strutturando l'intero progetto, ed i moduli che lo compongono, in modo che un'errata decisione presa nell'implementazione di un singolo modulo non si ripercuota sull'intero progetto, e possa essere corretta modificando soltanto quel modulo. Figura 7: Architettura PhoneGap 39 Nell'architettura iniziale di PhoneGap i livelli Javascript e nativo erano uniti in un unico strato e successivamente con l'introduzione dei plug-in è stato necessario separare tali livelli. Essi sono stati riprogettati e resi componenti separati anche nella funzionalità di accesso alle API native. La possibilità di includere plug-in di terze parti espande le potenzialità di PhoneGap e l'uso di tali plug-in è reso flessibile grazie alla possibilità di poterli collegare sia al livello nativo che JavaScript. Ciò è necessario in quanto i plug-in consistono sempre di una parte nativa che esegue il codice e di una parte JavaScript che fornisce le interfacce (tra l'applicazione e il codice nativo che viene eseguito). I plug-in, quindi, non sono cross-platform e le due parti di cui sono composti devono essere sviluppate per ogni piattaforma mobile. Il modello di programmazione su cui si basa PhoneGap prevede l'utilizzo delle tecniche adoperate nelle web application e in particolare si divide nella progettazione di due componenti principali: l'interfaccia grafica e la logica dell'applicazione. L'interfaccia grafica viene implementata mediante i linguaggi HTML e CSS, nello stesso modo con cui viene realizzata una web application. Ci sono però alcuni accorgimenti che devono essere adottati per non incorrere in problemi legati al rendering dell'interfaccia. I dispositivi mobili oltre ad essere caratterizzati da un'ampia gamma di risoluzioni video, possono essere utilizzati anche in modalità landscape e portrait, questo implica 40 l'utilizzo di tecniche specifiche per la realizzazione di mobile web app come le media queries. La logica dell'applicazione viene implementata mediante JavaScript con il quale si ha pieno accesso alla capacità computazionale del dispositivo. Inoltre grazie all'architettura di PhoneGap è possibile accedere agli oggetti messi a disposizione dalle API, con i quali si possono manipolare alcune funzionalità hardware del sistema su cui viene eseguita l'applicazione. La logica JavaScript, come accade per le web application, segue il meccanismo della cattura degli eventi. Il modello di programmazione prevede la gestione degli eventi mediante i tradizionali event handler JavaScript e attraverso gli eventi PhoneGap. Con gli event handler messi a disposizione da JavaScript si possono catturare tutti gli eventi che accadono nel Document Object Model. Gli eventi PhoneGap, invece, permettono di differenziare un'applicazione web da un'applicazione mobile multipiattaforma, poiché in questo caso sarà possibile catturare eventi strettamente legati al dispositivo come: la variazione della posizione geografica (geolocalizzazione), il movimento spaziale (accelerometro),ecc. La fase successiva alla cattura di un evento prevede l'esecuzione di una determinata porzione di codice (funzione, procedura,ecc.) che gestisce la risposta a tale evento. 41 3.4 Linguaggi di programmazione utilizzati e la loro relazione con PhoneGap Come previsto da PhoneGap, i linguaggi utilizzati per creare applicazioni mobile sono presi in "prestito" dall'ambiente web e sostanzialmente vengono utilizzati HTML5, CSS3 e JavaScript. HTML5 Il linguaggio HTML (Hyper Text Markup Language) è un linguaggio di markup ossia un'insieme di regole che descrivono i meccanismi di rappresentazione di un ipertesto nel World Wide Web, utilizzando convenzioni standardizzate. Benché HTML5 [6] sia ancora un linguaggio di markup, in realtà nella sua ultima versione si è evoluto a tal punto da integrare funzionalità molto avanzate come ad esempio: la geolocalizzazione, la persistenza dei dati nel browser attraverso le Web Storage, il controllo dei contenuti multimediali, ecc. Questa sua evoluzione lo ha reso uno strumento molto potente, infatti viene utilizzato anche in altri ambiti che non riguardano strettamente le applicazioni web. Il ruolo di HTML5 nella realizzazione di un'applicazione PhoneGap è di definire sia la struttura dell'interfaccia grafica che le varie viste di cui è composta l'applicazione stessa. 42 E' possibile utilizzare diversi approcci per strutturare un'applicazione mediante HTML5, se non si desidera utilizzare framework JavaScript è possibile strutturarla in più file HTML e richiamarli in seguito ad un'azione specifica. Nel caso in cui si sceglie di utilizzare un framework JavaScript o comunque una libreria esterna per migliorare l'user experience, è necessario attenersi al modello di programmazione previsto. Nel caso di jQuery Mobile si utilizza un solo file HTML diviso in una struttura particolare che prevede l'uso di specifici attributi all'interno dei tag, con cui delineare gli elementi di una particolare vista. Di seguito un esempio di struttura a pagine in un singolo file HTML5, da notare l'uso di attributi come data-role="page" che definiscono la singola vista e i restanti attributi header, content e footer che a loro volta definiscono le tre componenti che costituiscono una vista. <!DOCTYPE html> <html> <head> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" /> <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile1.3.1.min.js"></script> </head> <body> <div data-role="page" id="pagina_1"> <div data-role="header"> <h1>Page Title</h1> </div><!-- /header --> 43 <div data-role="content"> <p>Page content.</p> </div><!-- /content --> <div data-role="footer"> <h4>Page Footer</h4> </div><!-- /footer --> </div><!-- /fine pagina 1 --> <div data-role="page" id="pagina_2"> <div data-role="header"> <h1>Page Title</h1> </div><!-- /header --> <div data-role="content"> <p>Page content.</p> </div><!-- /content --> <div data-role="footer"> <h4>Page Footer</h4> </div><!-- /footer --> </div><!-- /fine pagina 2 --> </body> </html> Mediante questo approccio è possibile gestire in modo chiaro le diverse viste che compongono l'applicazione e si possono facilmente aggiungere, qualora ve ne fosse la necessità , ulteriori viste. CSS3 Il CSS (Cascading Style Sheets) è un linguaggio usato per definire la formattazione di documenti HTML, XHTML o XML. Le regole per comporre il CSS sono contenute in un insieme di direttive emanate a partire dal 1996 dal World Wide Web Consortium. Questo linguaggio è stato ultimamente aggiornato alla terza versione e come nel caso di HTML5, 44 sono state introdotte molte novità. Le specifiche CSS3 [7] non sono state ancora pubblicate, questo significa che nella fase di sviluppo di un'applicazione, che prevede l'uso dei fogli di stile, bisogna fare attenzione al tipo di browser engine che verrà utilizzato. Infatti, in base a quest'ultimo si rende necessario adottare un insieme di determinate direttive che risultano compatibili. Per lo sviluppo di un'app PhoneGap i CSS vengono utilizzati insieme all' HTML5, grazie ad essi è possibile definire l'intero stile dell'interfaccia grafica in modo molto simile a quanto avviene per le web application. L'inserimento di codice CSS, può essere fatto in tre modi differenti ma nella maggior parte dei casi avviene includendo, tra i tag <head> del codice HTML, un collegamento ad un foglio di stile esterno. Utilizzare questo approccio è molto interessante, poiché è possibile con la sola sostituzione del foglio di stile cambiare totalmente l'intera interfaccia. Un vantaggio non da poco che può garantire un risparmio di risorse nel caso di restyling dell'applicazione. Di seguito un esempio di inclusione di un file CSS all'interno di una pagina HTML: 45 <html> <head> <title>Esempio</title> <link rel="stylesheet" type="text/css" href="foglio_di_stile.css"/> </head> <body> </body></html> Un esempio generico della struttura di un CSS: selettore1 { proprietà1 : valore1; proprietà2 : valore2, valore3; } selettore2 { proprietà1 : valore1; proprietà2 : valore2, valore3; proprietà3 : valore3, valore4; } selettore3 { proprietà1 : valore1; proprietà2 : valore2, valore3; } Come si può notare le proprietà CSS vengono applicate alla struttura HTML mediante l'uso di opportuni selettori, i quali si dividono fondamentalmente in tre tipi: le classi, gli identificatori e i tag. 46 Un esempio specifico potrebbe essere quello di assegnare un colore di sfondo all'intera interfaccia, una font valida per tutte le viste e definire una larghezza ed altezza specifici per una classe di liste. //in questo caso il selettore è un tag body { background-color : #ffffff; font-family : tahoma; } //qui invece il selettore è una classe .liste_tipo_1{ height: 200px; width: 300px; } JavaScript JavaScript [8] è un linguaggio di scripting orientato agli oggetti comunemente utilizzato nella creazione di siti web, è stato standardizzato a partire dal 1997 e l'ultima versione risale al 2011. Va precisato che tra Java e JavaScript non intercorre nessuna relazione benché i nomi dei due linguaggi siano simili. JavaScript è un linguaggio interpretato dal browser engine, la sua sintassi è relativamente simile a quella del Java ed è debolmente tipizzato. 47 Le interfacce che consentono a JavaScript di rapportarsi con un browser sono chiamate DOM11. Molti siti web utilizzano la tecnologia JavaScript lato client per creare potenti applicazioni web dinamiche. Un uso principale del JavaScript in ambito web è la scrittura di funzioni integrate nelle pagine HTML che interagiscono con il DOM del browser, per compiere determinate azioni non possibili con il solo HTML. Questo tipo di linguaggio risulta molto diffuso poiché non viene utilizzato solo ed esclusivamente in ambito web. Nel caso del suo utilizzo con PhoneGap, JavaScript ha il compito di gestire la logica dell'applicazione e allo stesso tempo di interagire con le API native dell'ambiente attraverso PhoneGap. Questo importante compito può essere affrontato utilizzando librerie di supporto esterne o addirittura interi framework JavaScript, in modo da migliorare l'user experience del programma senza necessariamente aumentarne la complessità. Per integrare uno script JavaScript all'interno del codice HTML si utilizza uno speciale tag <script>, all'interno del quale è possibile collegare uno script esterno oppure scrivere direttamente al suo interno il codice JavaScript. Nella maggior parte dei casi per mantenere separati i componenti di un'applicazione PhoneGap si sceglie di collegare script esterni, di seguito un esempio di un collegamento : 11 Document Object Model, è una forma di rappresentazione dei documenti strutturati come modello orientato agli oggetti. Il DOM è uno standard ufficiale del W3C. 48 <html> <head> <script type="text/javascript" src="codice_javascript_esterno.js"></script> </head> <body> </body> </html> Infine un esempio di codice JavaScript: una funzione che recupera una stringa inserita dall'utente all'interno di un form, la quale viene successivamente stampata in una dialog box. <script type="text/javascript"> function getText(){ var text = document.getElementById('textbox_id').value; return text; } alert(getText()); </script> Questa operazione non poteva essere eseguita mediante l'uso del solo HTML. Nel caso dell'applicazione realizzata per il presente lavoro di tesi, è stato scelto jQuery mobile come framework JavaScript. 49 3.5 jQuery Mobile: un framework nel framework jQuery Mobile è un web framework ottimizzato per i dispositivi touch, è sviluppato dalla jQuery foundation e viene distribuito con licenza MIT. Questo framework JavaScript è molto diffuso grazie alla sua compatibilità con la maggior parte degli smartphone e tablet esistenti sul mercato, inoltre si integra perfettamente con diversi mobile app framework come PhoneGap. Ci sono diversi motivi per cui si sceglie di utilizzare una libreria JavaScript o un framework per lo sviluppo di un'applicazione mobile multipiattaforma, sicuramente le motivazioni più rilevanti riguardano il risparmio di tempo e risorse per migliorare l'user experience. La possibilità di disporre, in un'unica risorsa software, di strumenti testati su varie piattaforme e con un buon indice di degrado aumenta la produttività e non espone a problemi (brillantemente risolti dal framework). Il connubio di PhoneGap con jQuery Mobile è perfetto: da un lato abbiamo un mobile app framework che ci permette di accedere alle API native del dispositivo, dall'altro un mobile web framework che ci permette di strutturare la UI e di catturare gli eventi legati al touchscreen (es. Custom Gesture). Nel paragrafo 3.4 è stata presentata la struttura di una pagina HTML che sfrutta jQuery Mobile. Da come si può notare l'intero file HTML viene utilizzato per creare delle pagine che rappresentano le viste dell'applicazione mobile. 50 Ogni vista è ulteriormente suddivisa in tre sezioni: header, content e footer; queste sezioni rappresentano rispettivamente: la parte alta della pagina, il contenuto centrale e il piè pagina. Per indicare al framework jQuery Mobile i ruoli delle varie sezioni, la loro posizione, gli effetti di transizione e il tema grafico ad essi associato vengono utilizzati degli speciali attributi: data-role: specifica il ruolo di un elemento (header, content, footer, ecc). data-position: specifica se l'elemento deve essere fixed, in tal caso l'header o il footer saranno fissi durante lo scorrimento della pagina. data-transition: specifica l'effetto di transizione quando si passa in una nuova pagina. data-theme: specifica il tema css associato ad un determinato elemento. Un'altra caratteristica, che rende questo framework molto flessibile, riguarda lo sviluppo di temi css personalizzati. Attraverso il jQuery Mobile Theme Roller, un'applicazione che permette di sviluppare diversi temi, è possibile modificare gli stili css associati all'interfaccia grafica e poter visualizzare dal vivo le modifiche apportate. jQuery Mobile utilizza un sistema di supporto di degrado a 3 livelli, permettendo così di rendere accessibile il contenuto di una pagina anche 51 con browser engine ormai datati. I tre livelli si dividono in: A-grade, Bgrade e C-grade; nel livello A viene garantita la miglior user experience con effetti di transizione Ajax-based, nel livello B non è prevista l' Ajax navigation e nel livello C sono disabilitate la maggior parte delle features mantenendo un'interfaccia funzionale alla navigazione di base. La sintassi utilizzata da questo framework è molto semplice per chi ha esperienza con il web framework jQuery, la versione web desktop di jQuery Mobile. Essa si basa sulla selezione di elementi del DOM e sulla loro manipolazione attraverso la chiamata di uno o più metodi. La logica che permette di eseguire determinate azioni nel contesto dell'applicazione si basa sulla cattura di determinati eventi, i quali avvengono durante l'utilizzo dell'applicazione; esistono diversi event handler che permettono di catturare un determinato comportamento dell'utente. In particolare per la versione mobile di jQuery vi sono degli eventi associati al touchscreen del dispositivo, di seguito un esempio degli eventi più utilizzati per realizzare un'applicazione mobile. //viene lanciato la prima volta che viene caricata una vista $('#page_1').live('pageinit',function(e){ }); //viene lanciato ogni volta che viene caricata una vista $('#page_1').live('pageshow',function(e){ }); 52 //viene lanciato ogni volta che viene eseguito uno swipe verso sinistra $('#div_1').on('swipeleft',function(e){ }); //viene lanciato ogni volta che viene premuto a lungo un elemento $('#div_2').on('taphold',function(e){ }); //viene lanciato ogni volta che incomincia lo scrolling di una vista $('#div_3').on('taphold',function(e){ }); //viene lanciato ogni volta che viene premuto il pulsante con id "btn_1" $('#btn_1').on('tap',function(e){ }); Quando un evento viene intercettato solitamente viene eseguita un'operazione di risposta all'evento stesso. Ad esempio: la pressione prolungata di un elemento del DOM può corrispondere alla comparsa di un menu, che permette all'utente di accedere ad una serie di opzioni. Per inserire o manipolare elementi del DOM si usa una particolare sintassi di jQuery che permette di selezionare le diverse componenti di una pagina HTML. La selezione di un determinato elemento del DOM può essere un'operazione anche molto complessa e per questo motivo jQuery mette a disposizione un set di strumenti per il matching degli elementi che compongono il DOM. 53 Di seguito un esempio di alcuni selettori usati in jQuery: //Non fa riferimento a classi o id, seleziona direttamente i tag HTML, in questo //caso tutti i div della pagina. $('div') //Seleziona un elemento il cui id è "container" $('#container') //Seleziona una classe di elementi il cui attributo class è "lista" $('.lista') //Seleziona tutti i paragrafi che nel DOM sono figli di elementi con classe //"testo" $('.testo p') //Seleziona il campo input del form con id "form_1", che ha come attributo name //"provincia" $('#form_1 input[name=provincia]') //Seleziona l'ultima riga di ogni tabella presente nel DOM $('tr:last') //Seleziona le righe pari di ogni tabella presente nel DOM $('tr:odd') Esistono moltissime combinazioni di selezione grazie alle quali è possibile accedere a tutti gli oggetti del DOM, questo meccanismo permette di gestire l'interfaccia di un'applicazione mobile manipolando correttamente gli elementi. Dopo la selezione di un elemento della pagina HTML si procede alla sua manipolazione e, anche questa operazione è affidata a jQuery o eventualmente a JavaScript puro. La libreria jQuery mette a disposizione, attraverso le sue API, una serie di metodi che permettono di operare su tutti 54 gli elementi selezionati attraverso un selettore. E' possibile cambiare le proprietà css, creare un'animazione complessa, nascondere o visualizzare elementi, ecc. Di seguito un esempio di manipolazione degli stessi elementi selezionati nella pagina precedente: //Fa scomparire tutti i div del DOM con un effetto di dissolvenza $('div').fadeOut(); // Colora di bianco lo sfondo dell'elemento con id "container" e //aggiunge un bordo sinistro di 5px in stile solid di colore nero. $('#container').css({backgroundColor: '#fff', borderLeft: '5px solid #000'}); //Nasconde tutti gli elementi con classe "lista". $('.lista').hide(); //Sostituisce il testo di tutti i paragrafi, che nel DOM sono figli di elementi //con classe "testo", con la frase "Testo di prova". $('.testo p').text('Testo di prova'); //Recupera il valore del campo input del form con id "form_1", che ha come attributo name "provincia" $('#form_1 input[name=provincia]').val(); //Aggiunge un bordo inferiore di 1px nero con stile solido, all'ultima riga di //ogni tabella presente nella pagina. $('tr:last').css({border-bottom: '1px solid black'}); //Aggiunge uno sfondo grigio alle righe pari di ogni tabella presente nella //pagina. $('tr:odd').css({backgroundColor: '#ccc'}); Si può quindi affermare, in sintesi, che il modello di programmazione adottato, per creare un'applicazione attraverso il framework jQuery Mobile, segue le operazioni di: cattura di eventi legati all'interfaccia, selezione degli 55 elementi del DOM, manipolazione degli stessi in risposta all'evento catturato. Infine viene presentata una porzione di codice in cui viene applicato il modello di programmazione appena descritto, unendo gli esempi sopra citati: //evento che intercetta il caricamento della pagina con id "page_1" $('#page_1').live('pageshow',function(e){ //Aggiunge uno sfondo grigio alle righe pari di ogni tabella presente //nella pagina. $('tr:odd').css({backgroundColor: '#ccc'}); //viene lanciato ogni volta che viene premuto il pulsante con id "btn_1" $('#btn_1').on('tap',function(e){ //Nasconde tutti gli elementi con classe "lista". $('.lista').hide(); }); }); In pratica, al caricamento della pagina con id="page_1" lo sfondo delle righe pari di tutte le tabelle presenti nella pagina diventa grigio e premendo il tasto con id="btn_1" si nascondono tutti gli elementi con la classe "lista_1". 56 CAPITOLO 4 PORTING DI UN'APPLICAZIONE In questo capitolo viene analizzato nel dettaglio il lavoro svolto per rendere un'applicazione Android multipiattaforma attraverso il framework PhoneGap [9]. L'applicazione prevede l'utilizzo delle funzionalità native del dispositivo mobile come: la connessione ad internet, l'accesso alla memoria di massa, la consultazione della rubrica contatti, la gestione delle telefonate, invio SMS, ecc. L'applicazione, inoltre, è di tipo gestionale e fornisce una serie di informazioni organizzate prevalentemente in liste e tabelle. In più è presente un'agenda collegata ad un calendario per la gestione degli eventi, una lista contatti derivante dalla rubrica del dispositivo e una serie di form per l'immissione di dati. Le fasi che hanno caratterizzato il porting sono: Studio preliminare delle funzionalità dell'applicazione per ambiente Android. Scelta degli strumenti per replicare l'interfaccia grafica e gli effetti ad essa legati. Scelta delle tecniche per replicare le funzionalità dell'app originale in un ambiente multipiattaforma. 57 4.1 Interfaccia grafica e navigazione tra le pagine La prima parte del porting è stata focalizzata sulla progettazione dell'interfaccia grafica e sul meccanismo di navigazione tra le pagine che compongono l'applicazione. Le scelte grafiche e tecniche effettuate hanno seguito in primis la necessità di replicare il più fedelmente possibile l'interfaccia dell'applicazione originale. Successivamente sono state valutate le modifiche necessarie per rendere utilizzabile l'applicazione su più sistemi operativi. Quest'ultimo punto è fondamentale, poiché bisogna tenere conto della diversa user experience legata alle varie piattaforme e riprogettare l'applicazione in modo da adattarsi senza stravolgere, allo stesso tempo, l'interfaccia originale. Il componente d'interfaccia più complesso da realizzare è stato il menu globale dell'applicazione, un menu di servizio che permette la navigazione tra le diverse viste che compongono l'app. Nella versione originale per Android tale menu veniva richiamato con la pressione del pulsante soft touch "menu", questo comportamento non è replicabile in altri ambienti come ad esempio iOS. E' stato, dunque, necessario implementare secondo una diversa modalità la presenza di questo menu, in particolare utilizzando jQuery Mobile e l'evento "live click". L'intera interfaccia grafica è stata realizzata secondo il modello di programmazione del framework jQuery Mobile: la pagina HTML utilizzata per definire l'interfaccia è stata suddivisa in più viste, ognuna contiene i 58 diversi componenti che si differenziano in base alla funzione della vista stessa. Il meccanismo di navigazione prevede una pagina principale, la vista indice, che contiene i collegamenti alle pagine secondarie ognuna relativa ad una funzionalità o servizio specifico dell'applicazione. In ogni pagina l'utente può accedere al menu globale per cambiare contesto e passare ad una vista qualsiasi, oltre che poter accedere alla vista settings (dedicata alle impostazioni generali dell'app). Un'altro aspetto che ha caratterizzato la fase di porting dell'interfaccia riguarda gli effetti di transizione legati alla navigazione tra le viste. PhoneGap non supporta effetti di transizione nativamente, mentre l'applicazione Android originale prevedeva alcuni effetti di sliding e fading12, i quali sono stati implementati nella versione multipiattaforma con jQuery Mobile. Per la realizzazione dell'interfaccia relativa alla vista "calendario" è stato utilizzato un plug-in jQuery il cui nome è "fullcalendar", che permette di ottenere un calendario dinamico con cui è stata realizzata anche la funzione di agenda eventi. 12 Letteralmente scorrimento e dissolvenza, indicano gli effetti di transizione che è possibile notare su molte applicazioni mobile con un'interfaccia utente più accattivante. 59 Di seguito una parte della struttura HTML utilizzata per definire la vista indice e agenda: <!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="css/jquery.mobile-1.3.0.min.css"/> <link rel="stylesheet" href="css/index.css"/> <script src="js/jquery-1.8.2.min.js"></script> <script src="js/jquery.mobile-1.3.0.min.js"></script> <script type="text/javascript" src="cordova-2.5.0.js"></script> <script src="js/index.js" type="text/javascript"></script> <script type='text/javascript' src='js/fullcalendar.js'></script> <link rel='stylesheet' type='text/css' href='js/fullcalendar.css' /> <link rel="stylesheet" type="text/css" href="js/jqm-datebox.css" /> <script type="text/javascript" src="js/jqm-datebox.core.js"></script> <script type="text/javascript" src="js/jqm-datebox.mode.flipbox.js"></script> <!-- PLUGIN PHONEGAP--> <script type='text/javascript' src='js/SmsComposer.js'></script> <script type='text/javascript' src='js/EmailComposer.js'></script> </head> <body> <!-- inizio index --> <div data-role="page" id="index_page" > <div id="flag_orange"><img src="img/tag_orange.png"/></div> <div id="wrapper"> <div id="logo"><img src="img/logo.png"/></div> <table id="icon_index"> <tr> <td><a href="#profilo_page" data-transition="slide"><img src="img/profilo_n.png"/><br/> Profilo</a></td> <td><a href="#agenda_page" data-transition="slide" ><img src="img/agenda_n.png"/><br/> Agenda</a></td> <td><a href="#contatti_page_tutti" datatransition="slide"><img src="img/contatti_n.png"/><br/> Contatti</a></td> </tr> 60 <tr> <td><a href="#regali_page" data-transition="slide"><img src="img/regali_n.png"/><br/> Regali</a></td> <td><a href="#invitati_page" data-transition="slide"><img src="img/invitati_n.png"/><br/> Invitati</a></td> <td><a href="#budget_page" data-transition="slide"><img src="img/budget_n.png"/><br/> Budget</a></td> </tr> </table> <!-- messaggio di errore o successo sincronizzazione client/server--> <div id="sync_msg"> <p></p> </div> </div> </div> <!-- fine index --> <!-- inizio agenda --> <div id="agenda_page" data-role="page"> <div data-role="panel" class="mypanel" data-display="overlay" dataposition="left"> <img src="img/logo.png" class="global_menu_logo"/> <ul data-role="listview" data-inset="true"> <li><a href="#index_page" data-transition="flip"><img src="img/home_n.png" class="ui-li-icon ui-corner-none">Home</a></li> <li><a href="#profilo_page" data-transition="flip"><img src="img/profilo_n.png" class="ui-li-icon">Profilo</a></li> <li><a href="#agenda_page" data-transition="flip"><img src="img/agenda_n.png" class="ui-li-icon">Agenda</a></li> <li><a href="#contatti_page_tutti" datatransition="flip"><img src="img/contatti_n.png" class="ui-liicon">Contatti</a></li> <li><a href="#settings_page" data-transition="flip"><img src="img/settings_n.png" class="ui-li-icon">Settings</a></li> <li><a href="#regali_page" data-transition="flip"><img src="img/regali_n.png" class="ui-li-icon">Regali</a></li> <li><a href="#invitati_page" data-transition="flip"><img src="img/invitati_n.png" class="ui-li-icon">Invitati</a></li> <li><a href="#budget_page" data-transition="flip"><img src="img/budget_n.png" class="ui-li-icon ui-corner-none">Budget</a></li> </ul> </div> <div class="section_title"> <div class="yellow_cube"></div> <div class="orange_cube"></div> <div class="green_cube"></div> <a>Agenda</a> 61 </div> <div class="content_1"> <a class="agenda_title2">Agenda</a> <br/> <a class="agenda_subtitle">Tutte le date</a> <div class="lateral_button" id="agenda_calendario_button"><a style="color: #ffffff; text-decoration: none;" href="#calendario_page" datatransition="slide" class="button_link">Calendario</a></div> <br/><br/> <div class="lateral_button" id="agenda_diario_button"><a style="color: #ffffff; text-decoration: none;" href="#diario_page" datatransition="slide" class="button_link">Diario</a></div> </div> <div id="agenda_list"> </div> <div class="content_3"> <p style="clear: both;" class="paragraph plus_sign"><img src="img/agenda_tag_n.png" width="15"> <a style="color: #000000; text-decoration: none;" href="#aggiungi_in_calendario_page"> Aggiungi</a></p> </div> </div> <!-- fine agenda --> </body> </html> Nel codice si possono notare le due viste index e agenda realizzate mediante il modello di programmazione di jQuery Mobile. Le viste sono racchiuse tra div con attributo data-role="page". Inoltre nella pagina agenda, evidenziato in verde, si può notare la struttura del menu globale caratterizzato dall'attributo data-role="panel". 62 Segue il codice jQuery per le viste index e agenda, strutturato secondo il meccanismo di cattura degli eventi: $('#index_page').live('pageinit',function(e){ $('#index_page').live('click',function(e){ $('#sync_msg p').html(''); }); //script per cambiare il colore dell'icona nella pagina principale all'evento touch $('#icon_index a[href="#profilo_page"]').hover( function () { $(this).children("img").attr("src", "img/profilo_p.png"); }, function () { $(this).children("img").attr("src", "img/profilo_n.png"); } ); $('#icon_index a[href="#agenda_page"]').hover( function () { $(this).children("img").attr("src", "img/agenda_p.png"); }, function () { $(this).children("img").attr("src", "img/agenda_n.png"); } ); $('#icon_index a[href="#contatti_page_tutti"]').hover( function () { $(this).children("img").attr("src", "img/contatti_p.png"); }, function () { $(this).children("img").attr("src", "img/contatti_n.png"); } ); $('#icon_index a[href="#regali_page"]').hover( function () { $(this).children("img").attr("src", "img/regali_p.png"); }, function () { $(this).children("img").attr("src", "img/regali_n.png"); } ); }); 63 $('#agenda_page').live('pageshow',function(e){ $("#menu_label").live('click',function() { $( "#agenda_page .mypanel" ).panel( "open" ); }); //apro la connessione con il db var db = window.openDatabase("Database", "1.0", "db", 200000); //query che recupera gli eventi in agenda db.transaction(function(tx){ tx.executeSql("SELECT * FROM AgendaItemJDO GROUP BY dataInizio ORDER BY dataInizio ASC", [], initAgendaList); }); //aggiorna l'agenda function initAgendaList(tx, results) { $('#agenda_list').html(''); var len = results.rows.length; if(len == 0){ $('#agenda_list').append('<div class="paragraph agenda_row">Non ci sono appuntamenti o scadenze in agenda.</div>'); } var anno = ""; var anno_precedente = ""; var mesi = new Array("Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dic"); for (var i=0; i<len; i++){ //appendo tutti gli elementi della lista in sequenza nel div contatti_tutti_list var date = new Date(results.rows.item(i).dataInizio); anno = date.getFullYear(); if(anno != anno_precedente){ $('#agenda_list').append('<div class="agenda_year">'+ anno +'</div>'); } anno_precedente = anno; $('#agenda_list').append('<div data_ev="'+ results.rows.item(i).dataInizio +'" class="paragraph agenda_row">'+ '<div class="flag_agenda">'+ date.getDate() +' '+ mesi[date.getMonth()] + '</div>'+ '<div id="'+ results.rows.item(i).dataInizio +'" class="eventi_giorno">'+ '</div>'+ '</div>'); } $('.agenda_row:last').css('border-bottom', 'solid 1px #999'); 64 } //query che recupera gli eventi in agenda db.transaction(function(tx){ tx.executeSql("SELECT * FROM AgendaItemJDO ORDER BY dataInizio ASC", [], initAgendaRowList); }); //aggiorna l'agenda function initAgendaRowList(tx, results) { var len = results.rows.length; for (var i=0; i<len; i++){ $('#'+results.rows.item(i).dataInizio).append('<div>'+ results.rows.item(i).note +'</div>'); } } }); A pagina 64 si può notare l'evento "pageshow" che cattura il caricamento della vista agenda. Inoltre è presente anche l'event handler "live click" che intercetta l'evento touch relativo alla comparsa del menu globale. 65 La struttura HTML è collegata con delle regole CSS per definire lo stile di ogni singola vista, in particolare sono stati definiti alcuni parametri CSS globali per un uso tipicamente mobile, di seguito una porzione di codice CSS3: body { -webkit-touch-callout: none; -webkit-text-size-adjust: none; -webkit-user-select: none; height:100%; margin:0px; padding:0px; width:100%; background: -moz-linear-gradient(100% 100% 180deg, #f8f8f8, #cccccc); background: -webkit-gradient(linear, right top, right bottom, from(#f8f8f8), to(#cccccc)); background-repeat: no-repeat; background-attachment: fixed; } input, textarea { -webkit-user-select: text; } I primi parametri relativi al tag body vengono utilizzati per prevenire la copia di eventuali immagini in seguito ad un evento touch prolungato e il resizing text to fit, funzione che adatta il testo alle dimensioni della schermata. Bisogna infatti sottolineare che il rendering del layout avviene in un'istanza del browser ma bisogna dare l'illusione all'utente di utilizzare un'app nativa disabilitando parte delle feature che caratterizzano i browser mobile. 66 4.2 Persistenza dei dati Per garantire che i dati immessi attraverso l'uso dell'applicazione PhoneGap siano disponibili anche quando l'applicazione viene terminata è stato necessario utilizzare un meccanismo di persistenza dei dati. La scelta è ricaduta su Sqlite3 [10], un database management system SQL, utilizzato ampiamente in dispositivi come: telefoni cellulari, PDA, set-top boxes, ecc. Sqlite è una libreria scritta in linguaggio C che implementa un DBMS SQL di tipo ACID, il suo utilizzo è regolato da una licenza libera e permette di creare una base di dati incorporata in un unico file. Sqlite3 è compatibile con la maggior parte dei sistemi operativi mobile e risulta uno strumento perfettamente adatto per fornire la persistenza dei dati in un'applicazione mobile, inoltre essendo un DBMS SQL permette appunto l'utilizzo delle Structured Query Language (un linguaggio standard per manipolare i database). A differenza di altri database, Sqlite3 non è un processo standalone utilizzabile di per sè (come ad esempio MySql), ma può essere incorporato all'interno di un altro programma. Le caratteristiche più importanti di Sqlite3, per cui è stato scelto come strumento per garantire la persistenza dei dati, sono: la compattezza della libreria (solo 500KB per l'intera libreria) la velocità di esecuzione delle query 67 supporta buona parte dello standard SQL92 ha transizioni atomiche, consistenti, isolate e durabili (ACID), anche in caso di crash di sistema un database consiste di un unico file, il cui formato interno è indipendente dalla piattaforma La struttura del database, a supporto dell'applicazione, è organizzata in più tabelle le quali vengono referenziate tra di loro mediante il meccanismo delle chiavi primarie e delle chiavi esterne. In totale sono state utilizzate 10 tabelle per la gestione dei dati, la struttura del database viene creata nell'istante in cui l'applicazione viene avviata per la prima volta, di seguito un esempio di query utilizzata per la creazione del database: //Query in SQL per la creazione di una tabella nell'istante del primo avvio //dell'applicazione CREATE TABLE IF NOT EXISTS UserJDO (id INTEGER PRIMARY KEY, name VARCHAR(255), email VARCHAR(255), emailLowerCase VARCHAR(255), password VARCHAR(255), age VARCHAR(255), birthDate DATE, phone VARCHAR(255), city VARCHAR(255), sex VARCHAR(255), activated BOOLEAN, disabled BOOLEAN, promoter VARCHAR(255)) Come si può notare viene utilizzato lo statement sql "CREATE TABLE IF NOT EXIST" il quale garantisce la creazione della tabella solo se essa non è stata già creata precedentemente. In questa fase vengono definiti anche i datatype associati alle colonne della tabella. In Sqlite3 i datatype non sono definiti in modo statico e fortemente tipizzato come avviene in altri 68 database, ma viene utilizzato un approccio dinamico in modo che il datatype di un valore, sia associato con il valore stesso e non con il suo container. I datatype definiti in Sqlite3 sono quindi in numero minore rispetto ad altri database. Per garantire la completa compatibilità con il linguaggio SQL è possibile utilizzare i più comuni datatype presenti nelle implementazioni SQL tradizionali. Sqlite provvederà attraverso una tabella di affinità ad eseguire l'operazione di casting per rendere i dati coerenti con l'implementazione di Sqlite3. Di seguito la tabella di affinità usata da Sqlite3: Tabella 3: Tabella delle affinità Sqlite3 69 Nella query precedente è possibile notare come la colonna "id" sia stata definita "INTEGER PRIMARY KEY" ossia una colonna con datatype intero e caratteristica di chiave primaria auto incrementante. Le restanti query per la creazione del database hanno tutte la medesima struttura ovviamente con colonne differenti, scelte in base alla funzione a cui la tabella è destinata. Per poter accedere al database ed eseguire una query è necessario utilizzare PhoneGap e la sua capacità di sfruttare le API native del dispositivo. Un'accurata trattazione di questa metodologia è illustrata nel paragrafo seguente. 4.3 Accesso alle API native con PhoneGap PhoneGap permette l'accesso alle API native del dispositivo mobile, il modo in cui è possibile eseguire questa operazione è stato trattato nel paragrafo 3.2 (Caratteristiche di PhoneGap). Si ricorda che per alcuni sistemi operativi mobile non è possibile utilizzare tutte le funzionalità del dispositivo ma per gli OS Mobile per cui è previsto il porting (iOS, Windows Phone 8 e Android) non ci sono particolari limitazioni. 70 Di seguito vengono illustrate alcune funzionalità supportate da PhoneGap e quindi prese in considerazione le parti relative alle API utilizzate per il porting dell'applicazione. Storage Per poter accedere alla memoria di massa del dispositivo bisogna richiamare delle particolari funzioni che fanno riferimento alla libreria JavaScript di PhoneGap. Questa parte delle API è stata utilizzata per eseguire le query necessarie al corretto funzionamento dell'applicazione e per poter accedere in scrittura alla memoria. Di seguito un esempio del codice JavaScript necessario per la creazione della struttura del database, ed un esempio di codice HTML che richiama la libreria PhoneGap per l'accesso alle API native. <!-- Codice HTML --> <!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <!-- Foglio di stile di jQuery Mobile --> <link rel="stylesheet" href="css/jquery.mobile-1.3.0.min.css"/> <!-- Foglio di stile dell' interfaccia grafica --> <link rel="stylesheet" href="css/index.css"/> <!-- inclusione del framework jQuery Mobile --> <script src="js/jquery-1.8.2.min.js"></script> <script src="js/jquery.mobile-1.3.0.min.js"></script> 71 <!-- libreria Phonegap per l'accesso alle API native --> <script type="text/javascript" src="cordova-2.5.0.js"></script> <!-- codice javascript contenente la logica dell'applicazione --> <script src="js/index.js" type="text/javascript"></script> </head> <body> <!-- struttura della pagina html --> </body> </html> //codice Javascript //Event listner associato all'evento "deviceready" di Phonegap document.addEventListener("deviceready", onDeviceReady, false); //funzione che viene richiamata al presentarsi dell'evento "deviceready" function onDeviceReady() { var db = window.openDatabase("Database", "1.0", "db", 200000); db.transaction(function(tx){ tx.executeSql('CREATE TABLE IF NOT EXISTS UserJDO (id INTEGER, name VARCHAR(255), email VARCHAR(255), emailLowerCase VARCHAR(255), password VARCHAR(255), age VARCHAR(255), birthDate DATE, phone VARCHAR(255), city VARCHAR(255), sex VARCHAR(255), activated BOOLEAN, disabled BOOLEAN, promoter VARCHAR(255))'); }); } Il codice HTML nell'esempio mostra come vengono integrate nell'applicazione le diverse librerie JavaScript (jQuery Mobile e PhoneGap), i fogli di stile e la logica dell'applicazione. Il secondo esempio 72 mostra una parte della logica dell'applicazione ed in particolare la creazione del database. Si può notare come viene aggiunto un evento PhoneGap, detto anche "PhoneGap lifecycle events", ossia "deviceready" e come questo venga catturato quando il dispositivo avvia l'applicazione in quanto la libreria PhoneGap viene caricata completamente. Al verificarsi di queste condizioni viene richiamata la funzione "onDeviceReady" nella quale viene stabilita la connessione al database e successivamente, mediante le funzioni "db.transaction" e "tx.executeSql", viene eseguita la query. In questo caso la query crea una tabella e non ritorna nessun risultato da gestire come nel caso di una select. Le funzione "tx.executeSql" può essere utilizzata per eseguire tutte le query, essa prevede (quando necessario) l'utilizzo di due funzioni di callback. La prima viene lanciata dopo l'esecuzione della query, quando quest'ultima ha successo e contiene nel caso di una select il result set. Mentre la seconda funzione viene lanciata nel caso di errore nell'esecuzione della query e viene usata per gestire l'eventuale eccezione. Di seguito un esempio di codice con lo statement SQL Select: var db = window.openDatabase("Database", "1.0", "db", 200000); db.transaction(init_page); function init_page(tx) { tx.executeSql('SELECT * FROM Lista', [], initList, errorCB); } function initList(tx, results) { var len = results.rows.length; for (var i=0; i<len; i++){ 73 $('#list_1').append('<div db_id="'+ results.rows.item(i).id +'" class="box_list">'+ '<div class="box_list_top">'+ results.rows.item(i).name +'</div></div>'); } } function errorCB(err){ alert("Error processing SQL " + err.code); } Come si può notare dopo la connessione con il database viene eseguita una query di selezione, se non si presentano errori viene eseguita la funzione "initList" che ha il compito di popolare una lista scorrendo le righe attraverso il result set corrispondente al risultato della query. Nel caso venga sollevata un'eccezione questa viene gestita mediante la funzione "errorCB". Anche le query che prevedono l'uso degli statement "insert", "update" o "delete" vengono eseguite mediante la chiamata a funzione "tx.executeSql". Le API che garantiscono l'accesso alla memoria del dispositivo sono basate sulle specifiche del W3C Web SQL Database e W3C Web Storage. Connection L'oggetto "connection" previsto dalle API di PhoneGap, viene utilizzato per reperire informazioni riguardo le connessioni del dispositivo a reti WiFi o cellulari. La possibilità di conoscere lo stato di connessione alla rete 74 internet di un dispositivo è di fondamentale importanza nel caso ci sia la necessità di utilizzare servizi web associati ad un'applicazione. Nel caso dell'applicazione sviluppata, essa integra un servizio di sincronizzazione con un web server e l'utilizzo di una serie di servizi web come la verifica delle credenziali utente, per cui si rende necessaria la manipolazione dell'oggetto "connection". In particolare tale oggetto viene utilizzato per conoscere se il dispositivo è connesso ad una rete e di che rete si tratti. In base alla verifica di tale informazione si può procedere alla sincronizzazione o all'utilizzo di altri servizi web. Di seguito una porzione di codice che utilizza l'oggetto "connection": function checkConnection() { var networkState = navigator.connection.type; //impostare lo states a 0 per le connessioni non ammesse //esempio: se voglio aggiornare il dispositivo solo con connessione wifi e 3g impostare ad 1 WIFI e CELL_3G var states = {}; states[Connection.UNKNOWN] = 1; states[Connection.ETHERNET] = 1; states[Connection.WIFI] = 1; states[Connection.CELL_2G] = 1; states[Connection.CELL_3G] = 1; states[Connection.CELL_4G] = 1; states[Connection.CELL] = 1; states[Connection.NONE] = 0; return states[networkState]; } if(checkConnection() == 1){ alert('Connessione valida'); }else{ alert('Connessione non valida'); } 75 La funzione "checkConnection" viene utilizzata per verificare il tipo di connessione usata dal dispositivo e in particolare è stata progettata per ritornare il valore "0" oppure "1". In pratica è necessario associare all'array "states", che riporta i diversi tipi di connessioni possibili, i valori "0" per le connessioni che non si desidera utilizzare e "1" per le connessioni valide. Successivamente quando viene richiamata la funzione essa ritornerà due valori possibili. Mediante tali valori sarà possibile decidere se eseguire una determinata operazione che coinvolge la connessione del dispositivo o meno. Nell'esempio si può notare un costrutto "if-else" che esegue un check sulla connessione e stampa a video il suo stato. Il codice completo per la gestione della sincronizzazione e del controllo credenziali utente verrà mostrato nei paragrafi successivi. Contacts L'oggetto "contacts" permette di accedere alle informazioni presenti nella rubrica del dispositivo. Questa funzionalità è stata implementata nell'applicazione per poter recuperare alcune informazioni dei contatti presenti in rubrica. Tali informazioni vengono successivamente manipolate e salvate nel database in modo da creare delle liste contatti alternative con la possibilità di dividere i contatti in gruppi o selezionare dei preferiti. Inoltre l'applicazione permette l'inserimento, mediante una vista con un 76 form specifico, di ulteriori contatti non presenti nella rubrica del dispositivo. Questa parte dell'applicazione prevede l'utilizzo di 5 viste separate con i seguenti compiti: Mostrare tutti i contatti presenti nel database (importati dalla rubrica o inseriti manualmente). Mostrare i contatti divisi in gruppi con la possibilità di selezionare solo uno specifico gruppo (Amici, Parenti,Colleghi, ecc.). Mostrare solo i contatti classificati come "Preferiti". Fornire un Form per l'inserimento manuale dei contatti o in alternativa importarli mediante l'oggetto "contacts". Per importare i contatti è stata creata un'ulteriore vista che permette di visualizzarli in modo ordinato ed eventualmente filtrarli mediante un campo di ricerca dinamico. Di seguito il codice utilizzato per creare la lista dei contatti presenti nel dispositivo e per realizzare la vista che permette di selezionare il contatto da importare: //carico l'elenco dei contatti presenti nella rubrica var options = new ContactFindOptions(); options.filter=""; options.multiple=true; 77 //seleziono i campi che desidero recuperare dalla rubrica filter = ["displayName","phoneNumbers","emails","urls","addresses"]; navigator.contacts.find(filter, onSuccess, onError, options); function onSuccess(contacts) { for (var i=0; i<contacts.length; i++) { var phone = ''; var name = ''; var alt_phone = ''; var email = ''; var web = ''; var address = ''; if (contacts[i].phoneNumbers != null && contacts[i].phoneNumbers != 'undefined' && contacts[i].displayName != null && contacts[i].displayName != 'undefined') { phone = contacts[i].phoneNumbers[0].value; if(contacts[i].phoneNumbers[1] != null && contacts[i].phoneNumbers[1] != 'undefined'){ alt_phone = contacts[i].phoneNumbers[1].value; } if(contacts[i].emails){ email = contacts[i].emails[0].value; } if(contacts[i].urls){ web = contacts[i].urls[0].value; } if(contacts[i].addresses){ address = contacts[i].addresses[0].formatted; } name = contacts[i].displayName; $('#import_contact_list').append('<li><a name="'+ name +'" phone="'+ phone +'" alt_phone="'+ alt_phone +'" email="'+ email +'" web="'+ web +'" address="'+ address +'">'+ '<h2>'+ name +'</h2>'+ '<p>'+ phone +'</p>'+ '<p>'+ alt_phone +'</p>'+ '<p>'+ email +'</p></a>'+ '</li>'); } } $("#import_contact_list").listview("refresh"); } 78 //funzione chimata nel caso di errori function onError(contactError) { alert('onError!'); } Come si può notare l'oggetto "contacts" prevede una funzione filtro che viene utilizzata per selezionare solo gli attributi dei contatti che si desidera recuperare. Nel caso specifico: il nome e cognome del contatto, i numeri di telefono, le email, i siti web e gli indirizzi stradali. Viene così prodotta una lista di contatti la cui lunghezza coincide con il numero di quelli presenti in rubrica e a questo punto è possibile, mediante un ciclo "for", scorrere tale lista e recuperare le informazioni di ogni contatto. Queste informazioni vengo infine utilizzate per creare una lista completa di tutti i contatti i quali risultano singolarmente selezionabili per essere importati nell'applicazione. Device Attraverso questo oggetto è possibile accedere alle informazioni software e hardware riguardanti il dispositivo su cui è in esecuzione l'applicazione. Queste informazioni vengono utilizzate per filtrare particolari porzioni di codice, come ad esempio funzioni che fanno riferimento a plug-in di terze parti, che potrebbero funzionare solo su alcune piattaforme mobile. In effetti benché l'applicazione realizzata tramite PhoneGap sia multipiattaforma, per implementare particolari funzionalità a volte è 79 necessario sfruttare plug-in di terze parti che spesso non vengono sviluppati per tutte le piattaforme mobile. Nel caso dell'applicazione di cui è stato effettuato il porting, è necessario accedere alla funzioni di chiamata, invio SMS ed E-mail. Queste funzioni non sono previste nativamente da PhoneGap per cui sono state aggiunte mediante plug-in; il problema sollevato da questa soluzione però riguarda alcune linee di codice che non risultano identiche nella piattaforma Android e iOS. Per garantire quindi un'unica linea di sviluppo del codice sorgente è stata adottata una tecnica che prevede il riconoscimento della piattaforma su cui viene eseguita l'applicazione e la selezione del codice corretto per l'esecuzione di determinate funzionalità. Di seguito un esempio di utilizzo dell'oggetto "device": document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { var element = document.getElementById('deviceProperties'); element.innerHTML = 'Device Name: ' + device.model + '<br />' + 'Device Cordova: ' + device.cordova + '<br />' + 'Device Platform: ' + device.platform + '<br />' + 'Device UUID: ' + device.uuid + '<br />' + 'Device Version: ' + device.version + '<br />'; } 80 Le proprietà dell'oggetto "device" sono le seguenti: model: ritorna il nome del dispositivo cordova: ritorna la versione di cordova utilizzata (l'engine di PhoneGap) platform: ritorna il nome del sistema operativo in uso. uuid: ritorna un identificativo del dispositivo. version: ritorna la versione del sistema operativo. Utilizzando la proprietà "platform" insieme a "version" è possibile individuare con precisione il sistema operativo su cui è in esecuzione l'applicazione e quindi scegliere il codice opportuno da eseguire per accedere ad una determinata funzionalità. Events Gli eventi gestiti da PhoneGap sono una parte molto importante delle API. Grazie ai "cordova lifecycle events" è possibile individuare e catturare alcuni eventi che si possono presentare durante l'utilizzo dell'applicazione, eventi che il framework jQuery Mobile non può gestire. Nella prima parte di questo paragrafo è stato descritto l'evento "deviceready" per mostrare un esempio di codice che utilizzava tale evento. In realtà "deviceready" è essenziale per ogni applicazione PhoneGap poiché segnala quando le API di PhoneGap sono correttamente caricate. Questo significa che tutte le 81 chiamate alle API PhoneGap possono avvenire solo dopo che l'evento "deviceready" sia stato catturato. Di seguito una lista con una breve descrizione degli eventi gestiti da PhoneGap: deviceready: l'evento che segnala il caricamento completo delle API PhoneGap. pause: evento che segnala quando l'applicazione viene messa in background dal sistema operativo. resume: segnala quando l'applicazione ritorna alla sua normale esecuzione uscendo dallo stato di background. online: segnala la connessione del dispositivo alla rete internet. offline: segnala la disconnessione del dispositivo dalla rete internet. backbutton: segnala la pressione del pulsante back (Disponibile solo su hardware che prevede la presenza di tale componente). batterycritical: segnala che la batteria del dispositivo è quasi scarica. batterylow: segnala che la carica della batteria e minima. batterystatus: segnala quando cambia lo stato della batteria di un'unita (1%), oppure quando viene collegata o scollegata dal caricabatterie. menubutton: segnala la pressione del pulsante menu (Disponibile solo su hardware che prevede la presenza di tale componente). 82 searchbutton: segnala la pressione del pulsante menu (Disponibile solo su Android). startcallbutton: segnala la pressione del pulsante avvio chiamata (disponibile solo su blackberry). endcallbutton: segnala la pressione del pulsante fine chiamata (disponibile solo su blackberry). volumedownbutton: segnala la pressione del pulsante per ridurre il volume. volumeupbutton: segnala la pressione del pulsante per aumentare il volume. Segue un esempio di codice utilizzato per lo sviluppo dell'applicazione multipiattaforma: //event listner per intercettare il corretto caricamento delle API document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { //event listner per intercettare l'evento //background document.addEventListener("pause", onPause, false); che pone l'app in //event listner per intercettare l'evento di connessione ad internet document.addEventListener("online", onOnline, false); } function onPause(){ syncData(); } 83 function onOnline(){ syncData(); } Dal codice di esempio si nota che solo l'evento "ondeviceready" viene aggiunto all'inizio del codice, mentre gli altri eventi vengono aggiunti nella funzione "onDeviceReady" che viene lanciata dopo il completo caricamento delle API PhoneGap. Questo approccio viene utilizzato con tutti gli altri eventi per evitare che le chiamate alla API non vengano eseguite. Nell'applicazione, in particolare, i due eventi "pause" e "online" vengono utilizzati per chiamare la funzione di sincronizzazione con il web server, che verrà mostrata nel paragrafo successivo. 84 4.4 Interazione con un web server L'applicazione originale Android prevede la funzionalità di sincronizzazione con un web server basato sulla piattaforma Google App Engine. Per questo motivo anche l'applicazione realizzata per il porting multipiattaforma integra la stessa funzionalità; le tecnologie che permettono lo scambio di dati nell'architettura server/client implementata sono AJAX [11] e JSON [12]. AJAX AJAX è una tecnica di sviluppo software per la realizzazione di applicazioni web interattive (Rich Internet Application). Lo sviluppo di applicazioni con AJAX si basa su uno scambio di dati in background fra web browser e server, che consente l'aggiornamento dinamico di una pagina web senza esplicito ricaricamento da parte dell'utente. AJAX è asincrono nel senso che i dati extra sono richiesti al server e caricati in background senza interferire con il comportamento della pagina esistente. Normalmente le funzioni richiamate sono scritte con linguaggio JavaScript e nel caso dell'applicazione in esame è stato utilizzato jQuery. AJAX è una tecnica multipiattaforma utilizzabile cioè su molti sistemi operativi, architetture informatiche e browser web. In realtà AJAX non è una tecnologia individuale, piuttosto è un gruppo di tecnologie usate insieme. 85 Questa tecnica utilizza una combinazione di: HTML e CSS per il markup e lo stile, JavaScript per la manipolazione del DOM, l'oggetto XMLHttpRequest per l'interscambio asincrono dei dati. Inoltre utilizza un protocollo di scambio dati come JSON. Di seguito un esempio di chiamata AJAX tramite jQuery: $.ajax({ type: "GET", url: "http://www.sito.com/servlet.jsf", dataType: "html", data: "username=" + username + "&password=" + password, success: function(response) { alert(response); }, error: function(jqXHR, textStatus, errorThrown) { alert("error: "+jqXHR.responseText); alert("error: "+textStatus); alert("error: "+errorThrown); } }); } La chiamata AJAX effettuata tramite jQuery prevede l'utilizzo di una serie di parametri, i più importanti sono type: definisce il metodo di invio dei parametri al server (POST e GET). url: definisce l'URL del server a cui inviare i dati, solitamente una pagina di servizio che manipola i dati inviati dal client. dataType: il formato dei dati inviati al server. data: un array di dati che vengono inviati al server nella forma chiave/valore. 86 Le funzioni "success" e "error" gestiscono rispettivamente l'esito dell'invio dei dati al server e gli eventuali errori ed eccezioni sollevate. La funzione "success" prevede l'utilizzo di un parametro che contiene la risposta del server alla chiamata, mentre la funzione "error" implementa tre parametri per la gestione degli errori. JSON JSON è l'acronimo di JavaScript Object Notation, un formato adatto per lo scambio dei dati in applicazioni client/server. Viene usato in AJAX come alternativa a XML/XSLT. La semplicità di JSON ne ha decretato una rapida diffusione specialmente nella programmazione AJAX, il suo uso è particolarmente semplice infatti in JavaScript l'interprete è in grado di eseguirne il parsing tramite una semplice chiamata a funzione. I tipi di dato supportati da JSON sono: booleani interi, reali e virgola mobile. stringhe array e array associativi null 87 Di seguito un esempio di dati organizzati in una struttura JSON: var dati = { "type": "menu", "value": "File", "items": [ {"value": "New", "action": "CreateNewDoc"}, {"value": "Open", "action": "OpenDoc"}, {"value": "Close", "action": "CloseDoc"} ] } Infine alcune porzioni di codice utilizzate nell'applicazione multipiattaforma. Verifica delle credenziali: function checkCredentialSettings(){ //checkConnection verifica la presenza di connessione ad internet if(checkConnection() == 1){ //messaggio di avviso per l'utente $('#info_message').html('Verifica delle credenziali...'); //recupero delle credenziali di accesso dal form var username = $('#settings_form input[name=nome_utente]').val(); var password = $('#settings_form input[name=password_utente]').val(); //verifica l'esistenza dell'account sul server $.ajax({ type: "GET", url: urlServerCheckCredential, dataType: "html", data: "username=" + username + "&password=" + password, success: function(response) { var ser_resp = response.split('<body>'); var check = ser_resp[1].replace('</body>','').replace(/^\s\s*/, '').replace(/\s\s*$/, ''); if(check == 'OK'){ $( "#info_message" ).html('Credenziali corrette !'); }else{ 88 $( "#info_message" ).html('Credenziali errate'); } }, error: function(jqXHR, textStatus, errorThrown) { $( "#info_message" ).html('Errore di connessione con il server.'); } }); }else{ $( "#info_message" ).html('Connessione assente.'); } } Sincronizzazione del dispositivo con il web server: var html = ''; $.ajax({ type: "GET", url: urlServerSync, dataType: "html", data: "username=" + username + "&password=" + password + "&change=" + lastChange, success: function(response) { //recupero il messaggio html come oggetto jquery html = jQuery(response); //eseguo il parsing html per recuperare ack e data, nel caso di data eseguo un replace del carattere '+' con uno spazio var ack = $.trim($(html).filter('ack').text()); var data = $.trim($(html).filter('data').text().replace(/\+/g, '%20')); //decodifico i dati nel formato utf-8 data = decodeURIComponent(data); //se ack è server devo aggiornare lo smartphone (client) if(ack == 'server'){ //eseguo il parsing dei dati JSON var parse_json = $.parseJSON(data); //apro la connessione con il db var db = window.openDatabase("Database","1.0","123nozze", 200000); 89 db.transaction(function(tx){ tx.executeSql('DELETE FROM UserJDO'); tx.executeSql('INSERT INTO UserJDO (name, birthDate, email, city, sex) VALUES ("'+parse_json.wedding.bride.name+'","'+parse_json.wedding.bride.birthda te+'","' + parse_json.wedding.bride.email + '", "'+ parse_json.wedding.bride.city +'", "female")'); } //se il server mi invia il json dell'agenda procedo all'aggiornamento if(parse_json.hasOwnProperty('agenda')){ tx.executeSql('DELETE FROM AgendaItemJDO'); $.each(parse_json.agenda, function(i,item){ //aggiorno l'agenda var data_agenda = parse_json.agenda[i].dataInizio; //prendo solo la data eliminando l'ora data_agenda = data_agenda.substr(0,10); tx.executeSql('INSERT INTO AgendaItemJDO (dataInizio,note) VALUES ("'+ data_agenda +'","'+ parse_json.agenda[i].notes +'")'); }); } }); } //se ack è client devo aggiornare il web server (server) if(ack == 'client'){ var data_json = ''; //creo il json dal db var db = window.openDatabase("Database", "1.0", "123nozze", 200000); db.transaction(function(tx){ tx.executeSql('SELECT * FROM DbModifyJDO', [], jsonDati); tx.executeSql('SELECT * FROM UserJDO WHERE sex="male"', [], jsonUser); }); function jsonDati(tx, results) { var len = results.rows.length; for (var i=0; i<len; i++){ data_json=data_json+'{"date":"'+results.rows.item(i).date +'",'; } } function jsonUser(tx, results) { var len = results.rows.length; for (var i=0; i<len; i++){ 90 data_json = data_json + '"user":{'+ '"id":1,'+ '"name":"'+results.rows.item(i).name+'",'+ '"email":"'+results.rows.item(i).email+'",'+ '"age":0,'+ '"sex":"MALE",'+ '"birthdate":"'+results.rows.item(i).birthDate+'",'+ '"activated":true,'+ '"disabled":"false",'+ '"city":"'+results.rows.item(i).city+'"'+ '},'; } } //chiudo l'array JSON data_json = data_json + '}'; $.ajax({ type: "POST", url: urlUpdateServerSync, headers: {"Accept":"*/*","username": username, "data": data_json}, dataType: "html", data: "username=" + username + "&data=" + data_json, success: function(response) { response = $.trim(response); if(response == 'update_ok'){ $.mobile.changePage("#index_page"); $( "#sync_msg p" ).html('Sincronizzazione completata !'); }else{ $.mobile.changePage("#index_page"); $( "#sync_msg p" ).html('Errore di sincronizzazione.'); } }, error: function(jqXHR, textStatus, errorThrown) { $.mobile.changePage("#index_page"); $( "#sync_msg p" ).html('Errore: impossibile aggiornare il server.'); } }); } }); Per la sincronizzazione con il web server sono state utilizzate più chiamate AJAX per via del protocollo di comunicazione già presente nel lato server. La prima parte dello script prevede una chiamata AJAX iniziale inviando al server le credenziali di accesso e la data di ultima modifica dei dati sul 91 dispositivo mobile. Il server risponde con due informazioni racchiuse nei tag "ack" e "data". Valutando il primo tag è possibile capire in che direzione deve avvenire l'aggiornamento, mentre il secondo tag contiene i dati nel caso di aggiornamento del dispositivo mobile. Nel caso di aggiornamento del dispositivo vengono recuperati i dati in formato JSON inviati dal server e aggiornato il database, mentre nel caso opposto viene creato un pacchetto dati JSON e inviato tramite AJAX al server per la sincronizzazione. 92 CAPITOLO 5 CONCLUSIONI E SVILUPPI FUTURI Per verificare gli obiettivi raggiunti da questa tesi sono stati confrontati i due metodi attualmente disponibili per lo sviluppo di applicazioni mobile. Ed è stata così valutata la qualità delle applicazioni multipiattaforma realizzate mediante un framework, rispetto alle applicazioni sviluppate in ambienti nativi. La valutazione di queste tecniche è stata dettata da diversi fattori chiave: in particolare disponendo dell'applicazione originale scritta per il sistema operativo Android è stato possibile confrontare l'applicazione multipiattaforma nel medesimo ambiente. Ovviamente le stesse valutazioni sono state effettuate per altri ambienti come iOS e Windows Phone 8, però in questi casi, non disponendo dell'applicazione scritta in questi ambienti è stata analizzata la versione multipiattaforma secondo alcuni criteri come: le prestazioni generali, il corretto rendering del layout, l'interazione con le API native, ecc. Queste valutazioni hanno dato la possibilità di comprendere i principali vantaggi e i conseguenti svantaggi dell'utilizzo di framework multipiattaforma come alternativa allo sviluppo di applicazioni in ambienti nativi. Tra i vantaggi che caratterizzano un framework multipiattaforma sicuramente bisogna considerare la grande possibilità di adottare la 93 filosofia "write once run everywhere", ossia scrivere una sola volta il codice per poterlo eseguire su più architetture differenti. Questa caratteristica sicuramente è il motivo principale per cui nasce la necessità di adottare un framework multipiattaforma. Oggi esistono molti ambienti diversi tra loro e poter sviluppare (anche solo per i dispositivi più diffusi) un applicativo richiede risorse non indifferenti, le quali vengono risparmiate con l'utilizzo di un buon framework. Grazie a questo approccio si ha la possibilità di seguire una sola linea di sviluppo, facilitando il processo di versioning e manutenzione del codice, che in alternativa dovrebbe essere differente per ogni sistema operativo mobile. Inoltre viene utilizzato un set limitato di linguaggi e tecnologie, nel caso di PhoneGap HTML5, CSS3 e JavaScript, per realizzare l'applicazione. Si può quindi affermare che mediante l'utilizzo di un framework multipiattaforma per ambienti mobile si riducono notevolmente i tempi di sviluppo e le risorse impiegate nel progetto. Ovviamente a queste favorevoli considerazioni seguono anche alcuni svantaggi che devono essere necessariamente considerati prima dell'adozione di un framework multipiattaforma. In primis, i framework ora disponibili potrebbero non supportare lo sviluppo per alcuni sistemi operativi. Questo rappresenta un problema relativo, poiché data la presenza di svariati OS Mobile si tende a realizzare applicazioni per i dispositivi più diffusi evitando sistemi poco conosciuti. Nel caso di PhoneGap, comunque, il problema non sussiste del tutto, 94 poiché i sistemi operativi supportati sono i più diffusi, comprendendo anche Symbian OS il cui sviluppo è ormai concluso. Un problema più rilevante riguarda le prestazioni dell'applicazione in termini di velocità di esecuzione. In effetti le prestazioni di un'applicazione multipiattaforma rispetto ad una scritta in ambiente nativo sono inferiori. Il motivo di tale decadimento prestazionale è comunque da ricercare nel modo in cui operano i diversi framework e in particolare PhoneGap. Ricorrere a FFI, wrapper pattern e ovviamente alle WebView non aumenta le prestazioni ma al contrario introduce un discreto overhead. Ciò non significa che l'applicazione sia estremamente lenta e inutilizzabile, anzi confrontando l'app nativa Android con la versione multipiattaforma si nota leggermente la perdita di reattività e tutto ciò rimane comunque accettabile. Bisogna ricordare che un'applicazione multipiattaforma per sua stessa natura non può essere completamente paragonata ad una nativa, però con l'utilizzo di alcuni accorgimenti si può realizzare un'app di ottima qualità garantendo una user experience comparabile alle applicazioni native. Inoltre in un ambiente multipiattaforma in cui l'applicazione viene eseguita grazie alle WebView, le prestazioni della stessa app potrebbero essere differenti sui diversi sistemi operativi mobile. Questo dipende dalle prestazioni dei browser engine (es. Webkit, Trident, ecc.) utilizzati nei browser dei diversi OS Mobile. Infine utilizzare un approccio multipiattaforma vuol dire rendere il software totalmente dipendente dal framework, che potrebbe non 95 implementare alcune funzionalità previste invece dall'ambiente nativo. Valutando tutti gli aspetti sopra elencati si può giungere ad una conclusione oggettiva: l'utilizzo di un framework multipiattaforma non rappresenta un'alternativa allo sviluppo in ambienti nativi, ma un metodo differente che può affiancare le tradizionali tecniche di sviluppo. E' necessario valutare in fase di progettazione gli obiettivi di un'applicazione e vedere se si presta ad essere realizzata mediante un framework multipiattaforma o in ambienti nativi. Un'applicazione che ha necessità di sfruttare la maggior parte delle API native, che non richiede il rilascio su più OS Mobile e che necessità di elevate prestazioni computazionali è sicuramente candidata ad essere sviluppata in ambiente nativo. Al contrario, un'applicazione che richiede un breve periodo di sviluppo, che deve essere rilasciata per più sistemi operativi e non necessità di elevate prestazioni computazionali, è perfetta per essere realizzata mediante un framework multipiattaforma. In ogni modo PhoneGap, come altri framework, è una risorsa recente nell'ambito delle applicazioni mobile. Ed avendo riscosso molto successo negli ultimi anni, c'è motivo di credere che con le future release gli svantaggi che ora limitano l'utilizzo completo delle risorse del dispositivo saranno via via sempre minori. Come spesso accade nel mondo dell'IT nulla è facilmente prevedibile e un domani sviluppare applicazioni mobile multipiattaforma potrebbe divenire un nuovo standard ! 96 Appendice Viene riportato parte del codice sviluppato per la realizzazione del porting: 1) Funzioni di servizio utilizzate più volte nella logica dell'applicazione: //gestione primo avvio dell'applicazione function firstStart(){ $.mobile.changePage( "#first_log", { role: "dialog" } ); $( "#first_log" ).dialog({ closeBtn: "none" }); $('#new_user').live('click',function(e){ $.mobile.changePage("#registrazione_page"); }); $('#login_user').live('click',function(e){ $.mobile.changePage("#settings_page"); }); } //aggiornamento data di ultima modifica del database function lastChangeUpdate(){ //formatto la data corrente nel formato YYYY-MM-DD HH:MM:SS var lastChange = new Date(); 97 lastChange=lastChange.getUTCFullYear()+"+AddZero(lastChange.getUTCMonth()+1)+"-"+AddZero(lastChange.getUTCDate())+" "+AddZero(lastChange.getUTCHours())+":"+AddZero(lastChange.getUTCMinutes())+":" +AddZero(lastChange.getUTCSeconds()); var db = window.openDatabase("Database", "1.0", "db", 200000); db.transaction(function(tx) { tx.executeSql('UPDATE DbModifyJDO SET date="'+ lastChange +'"'); }); } //Gestione delle connessioni del dispositivo function checkConnection() { var networkState = navigator.connection.type; //impostare lo states a 0 per le connessioni non ammesse //esempio: se voglio aggiornare il dispositivo solo con connessione wifi e 3g impostare ad 1 WIFI e CELL_3G var states = {}; states[Connection.UNKNOWN] = 1; states[Connection.ETHERNET] = 1; states[Connection.WIFI] = 1; 98 states[Connection.CELL_2G] = 1; states[Connection.CELL_3G] = 1; states[Connection.CELL_4G] = 1; states[Connection.CELL] states[Connection.NONE] = 1; = 0; return states[networkState]; } //Verifica delle credenziali utente function checkCredentialSettings(){ if(checkConnection() == 1){ $('#info_message').html('Verifica delle credenziali...'); var username = $('#settings_form input[name=nome_utente]').val(); var password = $('#settings_form input[name=password_utente]').val(); //verifica l'esistenza dell'account sul server $.ajax({ type: "GET", url: urlServerCheckCredential, dataType: "html", data: "username=" + username + "&password=" + password, success: function(response) { 99 var ser_resp = response.split('<body>'); var check = ser_resp[1].replace('</body>','').replace(/^\s\s*/, '').replace(/\s\s*$/, ''); if(check == 'OK'){ $( "#info_message" ).html('Credenziali corrette !'); }else{ $( "#info_message" ).html('Credenziali errate'); } }, error: function(jqXHR, textStatus, errorThrown) { $( "#info_message" ).html('Errore di connessione con il server.'); } }); }else{ $( "#info_message" ).html('Connessione assente.'); } } //La seguente funzione viene eseguita quando l'app viene messa in background function onPause() { var db = window.openDatabase("Database", "1.0", "db", 200000); db.transaction(function(tx){ 100 tx.executeSql('SELECT * FROM DbModifyJDO', [], selectSync); }); function selectSync(tx, results) { var len = results.rows.length; var sync = 0; for (var i=0; i<len; i++){ sync = results.rows.item(i).sync; } if(sync == 1){ syncData(); } } } 101 2) Script per la gestione del calendario dinamico: //Calendario dinamico con funzione di agenda $('#calendario_page').live('pageshow',function(e){ $("#calendario_page").swiperight(function() { $( "#calendario_page .mypanel" ).panel( "open" ); }); $('#calendar').fullCalendar('destroy'); $('#calendar').fullCalendar({ editable: true, viewDisplay: function(view) { var date = $("#calendar").fullCalendar('getDate'); var month_int = $.fullCalendar.formatDate(date, "MMMM"); $('#agenda_month').html(month_int); var year_int = date.getFullYear(); $('#agenda_year').html(year_int); //apro la connessione con il db var db = window.openDatabase("Database", "1.0", "db", 200000); //query che recupera tutti gli eventi in agenda db.transaction(function(tx){ 102 tx.executeSql("SELECT * FROM AgendaItemJDO GROUP BY dataInizio", [], initCalendary); }); function initCalendary(tx, results) { var len = results.rows.length; for (var i=0; i<len; i++){ var data_evento = results.rows.item(i).dataInizio; var myEvent = { title:"", allDay: true, start: data_evento, end: data_evento, color: "#f05923", backgroundColor: "#f05923" }; $('#calendar').fullCalendar( 'renderEvent', myEvent ); } $('.diario_row:last').css('border-bottom', 'solid 1px #999'); 103 } }, buttonText: { today: 'Oggi', day: 'Giorno', week:'Settimana', month:'Mese' }, dayClick: function(date, allDay, jsEvent, view) { var selectedDate = $.fullCalendar.formatDate( date, "yyyy-MM-dd"); $('#current_date').val(selectedDate); $.mobile.changePage("#diario_page"); } }); }); 104 3) Codice per la gestione di un singolo contatto della rubrica con possibilità di telefonata, invio SMS ed e-mail: $('#contatti_scheda_page').live('pageshow',function(e){ $("#contatti_scheda_page").swiperight(function() { $( "#contatti_scheda_page .mypanel" ).panel( "open" ); }); var iddb_mod = $('#scheda_contatto_form input[name=id_contatto]').val(); //apro la connessione con il db var db = window.openDatabase("Database", "1.0", "db", 200000); db.transaction(function(tx){ tx.executeSql('SELECT * FROM ContattoRubricaJDO WHERE id='+ iddb_mod +'', [], function(tx, results){ //setto i campi della pagina scheda contatto con le informazioni recuperate dal db if(results.rows.item(0).preferiti == 1){ $('#preferito_scheda').attr('src','img/star_on.png'); }else{ $('#preferito_scheda').attr('src','img/star_off.png'); } $('#preferito_scheda').attr('alt',iddb_mod); 105 $('#scheda_contatto_form input[name=nome_scheda]').val(results.rows.item(0).nome); var el = $('#scheda_contatto_form select[name=categoria_cont_scheda]'); el.val(results.rows.item(0).categoria).attr('selected', true).siblings('option').removeAttr('selected'); el.selectmenu("refresh", true); $('#scheda_contatto_form input[name=tel1_scheda]').val(results.rows.item(0).telefono1); $('#scheda_contatto_form input[name=tel2_scheda]').val(results.rows.item(0).telefono2); $('#scheda_contatto_form input[name=email_cont_scheda]').val(results.rows.item(0).email); $('#scheda_contatto_form input[name=sito_web_scheda]').val(results.rows.item(0).sitoWeb); $('#scheda_contatto_form textarea[name=indirizzo_cont_scheda]').val(results.rows.item(0).indirizzo); $('#scheda_contatto_form textarea[name=note_cont_scheda]').val(results.rows.item(0).note); $('#tel_contact a').attr('href','tel:' + results.rows.item(0).telefono1); $('#sms_contact').live('click',function(e){ 106 window.plugins.smsComposer.showSmsComposer("",[results.rows.item(0).telefono1]) ; }); $('#email_contact').live('click',function(e){ window.plugins.emailComposer.showEmailComposer("","",[results.rows.item(0).email ], [], [], true); //, [] }); }); }); }); 107 BIBLIOGRAFIA 108 109 Ringraziamenti: Come ogni tesi che si rispetti dedico quest'ultima parte al ringraziamento delle persone che mi hanno sostenuto e accompagnato in questo percorso fatto di gioia, sudore e passione. Ringrazio quindi: Il Relatore di questa tesi: Prof. Luigi Troiano, oltre ad essere un ottimo professore, negli ultimi mesi mi ha dimostrato di essere anche una persona molto umana e disponibile. Il Correlatore di questa tesi: Dott. Maria Carmela Vitelli, che mi ha (in)seguito durante il tirocinio con tanta pazienza e comprensione, grazie Maria Carmela ! I ragazzi di Intelligentia srl, in particolare Davide De Pasquale per il supporto tecnico nei momenti di difficoltà. I miei genitori, che mi hanno sempre sostenuto durante il mio lungo percorso e che hanno sempre avuto fiducia in me. I miei compagni di studio, Claudio Fioretti, Antonio Ascione, Fabio Fusco, Antonio Di Meola, Francesco Alfieri e in particolare Silvio Napoletano con cui ho condiviso gli ultimi momenti prima del traguardo. 110 Gli amici di sempre, Vincenzo Russo e Marco Frangiosa che mi hanno accompagnato in tutto il mio percorso sapendomi distrarre quando la pressione era diventata troppo alta. Stefano Mastrocinque con cui ho condiviso momenti di studio e amicizia, in quel di Lentace, indimenticabile ! Valeria De Rosa, Per la sua costante e fondamentale presenza nel mio percorso di laurea, nella stesura di questa tesi e ovviamente nella vita... Grazie per avermi supportato e, soprattutto, sopportato ! 111
© Copyright 2024 Paperzz