AVD, SDK e firma app
AVD Manager
Android Virtual Device Manager gestisce tutti gli emulatori installati e ti permette di scegliere il tipo di emulatore da creare con il tipo di SDK.
SDK Manager
Software Development Kit manager ti permette di scaricare e gestire tutte le versioni di SDK disponibili, dalla 20 alla 31. Ad ogni SDK corrisponde una specifica versione di Android.
Creazione app e firma
Le app sono create con componenti multiple che collaborano, aperte e messe in funzione da Android quando è necessario e ciascun componente ha un ruolo diverso ed ha proprie API. A partire da un progetto Android, l'app viene compilata, viene creato l'APK contenente il .dex, le risorse .arsc e quelle non compilate e il manifest, successivamente viene firmata dallo sviluppatore e, tramite ADB, eseguita su un dispositivo o emulatore.
Firma di un file APK
Per i test è bene firmare l'app in modalità debug, in questo modo è utilizzata una chiave con password nota, per cui non è necessario inserirla per far partire l'app. In release mode invece è necessario firmare l'app esplicitamente, in particolare se sarà caricata nel Play Store.
Gli Android Development Tools firmano l'APK e si occupano di tutto purché lo sviluppatore fornisca un certificato valido. La prima volta che si esegue l'app o si lancia il debug del progetto in Android Studio, l'IDE crea automaticamente il keystore di debug e il certificato che ha una durata di 30 anni (in precedenza era solo di 1 anno) e alla scadenza si avrà un errore di build.
Procedura per ottenere un certificato
- Si crea un keystore, cioè un file binario che contiene le chiavi private, da conservare in un posto sicuro.
- Si crea una chiave privata, che rappresenta l'entità associata all'app (azienda/persona).
- Si aggiunge la configurazione per la firma al modulo corrente (il predefinito è app).
- Viene invocato il build task assembleRelease di Android Studio.
- Il package app/build/apk/app-release.apk è firmato.
Non è una buona idea inserire la password dello storechain e la password dell’app nel file di build, meglio fare in modo che siano prese da variabili d’ambiente o richiederle tramite console all’utente.
Firma V2 e V3
Da Nougat è stato introdotto un nuovo schema di firma che permette una installazione più veloce e maggiore protezione da alterazioni di APK. Per default la firma è applicata a entrambe le versioni (JAR e V2) e, firmando tramite V2 e apportando modifiche al progetto dopo la firma, essa viene invalidata.
Da Android 9 è stata introdotta la firma V3 che supporta la rotazione della chiave, ovvero la possibilità di rifirmare come parte di un aggiornamento APK. Perdere la password di una app pubblicata nello store comporta l’impossibilità di aggiornare l’app, in quanto ad ogni aggiornamento bisogna rifirmarla.
Metodo per firmare un'app
Il metodo più veloce per firmare un'app è: Build > Generate signed APK che crea un keystore e genera l'APK firmato. Da agosto 2021, per pubblicare una nuova app sul Google Play Store bisogna utilizzare il Play App Signing che utilizza due chiavi:
- Upload key: chiave usata per firmare la app prima del caricamento su Play Store, è privata ma di proprietà dell’autore, può essere la release key di Android Studio.
- App signing key: chiave di firma, è parte del ‘modello di aggiornamento sicuro’ di Android, non cambia durante la vita dell'app, può essere fornita dall’autore o generata da Google.
Google utilizza la upload key per verificare l’identità dell’autore e poi firma l'APK con la app signing key di distribuzione sul suo store. Utilizzando una chiave di caricamento separata è possibile richiedere un ripristino della upload key se viene smarrita o rubata.
OHA, Dalvik e ART
OHA
L’OHA o Open Handset Alliance è un consorzio di aziende per costruire un ecosistema di produzione e sviluppo (HW e SW) aperto e compatibile. È stato creato da Google per la realizzazione di applicazioni per dispositivi mobili da più di 84 aziende eterogenee e con diversi obiettivi, interessi e culture che si uniscono per accelerare l’innovazione e offrire ai clienti un prodotto economico ma tecnologicamente avanzato, fornendo una User Experience moderna e adatta alle varie tipologie di utenti, bisogni e culture.
Il risultato dell’OHA è la piattaforma Android che non è altro che una pila o stack software creata per lo sviluppo di dispositivi mobili la cui applicazione viene creata tramite l’Android SDK.
Architettura di Android
L’architettura Android è costituita da 5 livelli:
- Application
- Application Framework
- Android Runtime
- Libraries
- Kernel Linux
Kernel Linux
Il Kernel Linux costituisce il livello più basso dell’architettura Android. Esso mette a disposizione i servizi core e cioè contiene una serie di driver che interagiscono con l’hardware al fine di fornire i principali servizi di un sistema operativo: sicurezza (permessi), gestione e condivisione della memoria e dei processi, gestione file e I/O network, drivers e dispositivi (accesso ai sensori), componenti specifici di Android (gestione dei consumi e batteria).
Libraries
Le Libraries sono un insieme di strumenti e librerie scritte in C/C++ per motivi di performance e sicurezza, esposte tramite interfacce Java come per esempio SQLite, OpenGL webkit e altro. Se si vuole implementare parte delle app in linguaggio nativo quali C o C++ è possibile fare uso dell’NDK o Native Development Kit, in maniera da avere prestazioni più alte a discapito di più complessità. Un uso tipico è giochi, elaborazioni di segnali o simulazioni fisiche.
Android Runtime
Le componenti delle Libraries saranno utilizzate dalle Core Libraries presenti in Dalvik Virtual Machine o ART che verranno poi eseguite tramite una delle due in base alla versione di Android. Una macchina virtuale è un software che esegue app Android scritte in Java. Un’app scritta in Java viene compilata in Java bytecode, un tool converte il bytecode in un file .dex (Dalvik Executable) e tramite altre applicazioni l’app è installata sul dispositivo: quando l’utente avvia l’app, Dalvik/ART esegue il file dex (bytecode Android). Il corrispettivo del .jar su Android è il .apk.
Dalvik VM
È una macchina virtuale progettata per essere usata in ambienti con poche risorse e far girare bytecode Java su dispositivi mobile quindi con CPU lente, poca RAM, poca batteria e senza area di swap. Utilizzato sin da API 4.4, è basato su tecnologia JIT (just-in-time) in quanto l’app è compilata in parte dallo sviluppatore, successivamente Dalvik (interprete) analizza il codice dell’app compilandolo in tempo reale in linguaggio macchina durante l’esecuzione dell'app migliorandone le prestazioni (rispetto a Java nativo) – da 4x a 10x più veloce di un interprete tradizionale.
ART
Utilizzato dalla API 5.0+, nuovo ambiente di Runtime che ha migliorato vari aspetti critici (p.e. gestione della memoria). ART è basata su tecnologia AOT (ahead-of-time) che compila il codice solo durante l'installazione dell'app, aumentando però il tempo di installazione di un app.
Application framework
Si tratta di software riutilizzabile utile in molte applicazioni. L’Application Framework mette a disposizione una serie di componenti di alto livello per la realizzazione di applicazioni sfruttando i servizi forniti da Libraries e Android Runtime:
- Package manager: database che tiene traccia delle app installare nel dispositivo e consente ad un app di trovare, mettersi in comunicazione e richiedere servizi ad un'altra app. Si può utilizzare la classe PackageManager per il recupero di vari tipi di informazioni relative ai pacchetti dell'applicazione attualmente installati sul dispositivo. Puoi trovare questa classe attraverso il metodo getPackageManager().
- Window Manager: gestisce le finestre che compongono un’app, es. notification bar, main application, subwindow etc. Usa Context.getSystemService(Context.WINDOW_SERVICE) per ottenere l'interfaccia che le app usano per parlare con il Window Manager. Ogni istanza del gestore di finestre è associata a un particolare Display.
- View System: fanno parte tutti gli elementi della UI (Icone, testo, pulsanti etc). Questa classe rappresenta il blocco costitutivo di base per i componenti dell'interfaccia utente. Una View occupa un'area rettangolare sullo schermo ed è responsabile del disegno e della gestione degli eventi. View è la classe base per i widget, utilizzati per creare componenti interattivi dell'interfaccia utente (pulsanti, campi di testo, ecc.). La sottoclasse ViewGroup è la classe base per i layout, che sono contenitori invisibili che contengono altre viste (o altri ViewGroup) e definiscono le loro proprietà di layout.
- Resource Manager (Oggetto in Java): esso gestisce le risorse non compilate tra cui fanno parte le stringhe presenti nella cartella res/values/strings. Le risorse sono i file aggiuntivi e i contenuti statici utilizzati dal codice, ad esempio bitmap, definizioni di layout, stringhe dell'interfaccia utente, istruzioni di animazione e altro.
- Activity Manager: gestisce il ciclo di vita delle applicazioni e gestisce anche lo Stack per la navigazione.
- Content Provider: database che consente alle app di memorizzare e condividere le informazioni. (Per esempio è possibile accedere alla info dei contatti in maniera tale da effettuare le telefonate). Il Content Provider gestisce l'accesso a un insieme strutturato di dati. Li incapsula e fornisce meccanismi per definirne la sicurezza.
- Location Manager: permette alle app di ricevere informazioni sul movimento e relative alla posizione (GPS) del dispositivo. Consente inoltre di svolgere task specifici come trovare la posizione e la direzione. Questa classe fornisce l'accesso ai servizi di localizzazione del sistema. Questi servizi consentono alle applicazioni di ottenere aggiornamenti periodici della posizione geografica del dispositivo o di attivare un Intent specificato dall'applicazione quando il dispositivo entra in prossimità di una determinata posizione geografica. Classe non direttamente istanziata ma si recupera tramite Context.getSystemService(Context.LOCATION_SERVICE). Tutti i metodi dell'API di localizzazione richiedono le autorizzazioni ACCESS_COARSE_LOCATION o ACCESS_FINE_LOCATION.
- Notification Manager: consente alle app di inserire informazioni nella notification bar per esempio per avvisare l’utente che si è verificato uno specifico evento. È la maniera per dire all’utente che qualcosa è avvenuta in background.
Application
Sono tutte le applicazioni installate nel dispositivo e nessuna di queste app è parte del sistema, in quanto se si ha un’app preferita la si può installare al posto di qualsiasi app standard.
Activity
Di solito una sola activity rappresenta l’entry point dell’app, nel file ‘AndroidManifest’ è segnata come <action android:name="android.intent.action.MAIN" /> nell’intent filter. Ogni volta che un’activity apre un’altra activity, l’activity chiamante è inserita nel backstack di Android (pila: LIFO) ed è messa in stop. Ogni cambio di stato è notificato da un evento (callback), che può essere intercettato per eseguire azioni compensative.
Activity life cycle
- onCreate(): viene creata l'activity, impostato il layout, gestito il Bundle con eventuale stato precedente.
- onStart(): visualizzato il layout, impostati i listener [ma l'activity non è pronta per l'interazione].
- onResume(): activity attivata e pronta ad andare in run.
- onPause(): activity non più interattiva ma ancora visibile.
- onStop(): activity non più visibile.
- onRestart(): è alternativo al metodo onCreate() per ripristinare oggetti già creati ma poi disabilitati.
Un’applicazione Android non esiste da sola ma può collaborare con altre applicazioni. Quando l’activity sta per diventare visibile è invocato il metodo di callback onStart() mentre quando l’activity sta per diventare invisibile è invocato il metodo onStop() e questi due metodi determinano l’intervallo di visibilità dell’activity. Va inoltre ricordato che quando un’activity è pronta per l’interazione con l’utente è chiamato il metodo di callback onResume() [ad es. quando si riaccende il dispositivo dopo lo sleep] mentre quando un’activity sta per non essere più in grado di interagire con l’utente è chiamato il metodo onPause() (ma è visibile e in primo piano).
onCreate()
È un metodo critico e deve essere veloce infatti se entro 5 secondi l’app non risponde, il sistema operativo mostra una finestra di ANT (Application not responding). Questo metodo è invocato quando l’activity è creato, inizializza lo stato della classe, chiama il super.onCreate(), imposta l’activity content View per il layout (setContentView(R.layout.main)), mantiene i riferimenti alla UI e configura la View se necessario.
onStart()
Chiamato quando l’activity sta diventando visibile e tipicamente parte quando ci sono comportamenti solo visibili (richiesta di aggiornamenti di sensori geolocalizzati) oppure in fase di caricamento di applicazioni con stato persistente (email).
onRestart()
Chiamato quando l’activity è stata fermata ma sta per riprendere e viene utilizzato per tipiche azioni prima che l’activity sia ripristinata dallo stato di stop.
onPause()
Chiamato quando l’activity sta perdendo il focus, primo sintomo che l’utente sta lasciando l’activity oppure quando l’activity perde il primo piano. Viene usato per salvare uno stato persistente (qui si possono richiamare i metodi del salvataggio stato).
onResume()
Chiamato quanto l’activity è visibile e sta per interagire nuovamente con gli utenti es. inizio comportamenti del primo piano, es. far partire un’animazione o suonare un brano.
onStop()
Chiamato quando l’activity non è più visibile ma può essere mostrata dopo. Viene memorizzato lo stato nella cache. Questo metodo potrebbe non essere mai richiamato quando l’activity viene terminato da Android stesso quindi è bene non inserirevi dati persistenti.
onDestroy()
Chiamato quando l’activity sta per essere distrutta es. rilascio risorse dell’attività. Questo metodo potrebbe non essere chiamato quando ad Android serve memoria.
Salvataggio dello stato di un Activity
In Android una Activity è gestita come un processo del S.O. e quindi ha uno STATO. Alcuni cambiamenti di stato causano automaticamente il riavvio dell’activity in quanto il S.O. può anche distruggere una activity perché ha bisogno di memoria e risorse (o per priorità). In questa maniera anche il suo stato è distrutto, cosa trasparente all’utente, che si aspetta che lo stato sia sempre mantenuto durante l’interazione.
Per mettere al sicuro le informazioni importanti ci si serve del metodo onSaveInstanceState(Bundle outState) che viene chiamato automaticamente sempre prima della rimozione di una activity dalla pila dei task. Si fa quindi l'override del metodo, ed al suo interno si implementa il salvataggio delle variabili di stato. Le variabili di stato (esempio valori per 'calcolo mance') vengono salvate nel Bundle outState.
Lo stato di un activity invece può essere ripristinato in due maniere:
- Nell’onCreate(Bundle savedInstanceState)
- Nell’onRestoreInstanceState(Bundle savedInstanceState), che viene richiamato dopo onStart() quindi quando è già inizializzata con tutti i suoi elementi che possono essere modificati con lo stato precedente.
Per ripristinare i valori di uno stato, si deve capire se l’app si sta avviando per la prima volta oppure è ripristinata da uno stato precedente; questo viene fatto controllando se l’oggetto savedInstanceState != null.
onSaveInstanceState() è talvolta chiamato automaticamente per ogni View infatti quasi tutti i widget implementano questo metodo per default, a patto che si sia assegnato loro un ID (per poter poi recuperare il dato) es. le EditText salvano il testo immesso dall’utente, CheckBox salva lo stato selezionato. Quindi in onSaveInstanceState() potremmo salvare esplicitamente solo dati che non fanno specificatamente parte di qualche widget e per usarlo si fa override del metodo e all’interno si chiama il metodo della superclasse tuttavia la sua chiamata non è garantita, quindi non va usato per la persistenza.
Bundle
Il bundle serve per memorizzare tipi di dati primitivi come chiave-valore. Viene usato spesso per salvare lo stato di un activity o per passare i dati tra Activity. Per salvare dati si usa .putXX mentre per recuperare i dati si usa .getXX.
Classe R
Durante la creazione della GUI e l’aggiunta di risorse, gli strumenti di build generano la classe R, contenente classi static nidificate che rappresentano le risorse della cartella res del progetto. Essa può essere utilizzata per avere il riferimento ad un elemento della UI definito in un layout XML. final Button button = (Button) findViewById(R.id.bottone_prova);
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.