Registrare un'applicazione per rispondere ad Intent Impliciti
In questo tutorial vedremo di capire come avviene il processo di selezione dell'Activity da richiamare, affinché un'applicazione possa rispondere all'invio di Intent Impliciti da parte di altre app.
Abbiamo visto che gli Intent sono un collaudato meccanismo per trasmettere messaggi all’interno del sistema, affinché altre Activity, componenti, applicazioni, servizi, rispondano e prendano in gestione l’azione.
Ebbene, abbiamo visto in un precedente tutorial sugli Intent Impliciti, come spesso noi conosciamo l'azione e i dati che vogliamo trasmettere, ma NON sappiamo a priori quale sarà l'applicazione o Activity che dovrà rispondere a tale azione.
Potrebbe essere il tuo client di posta, potrebbe essere l'applicazione che gestisce i messaggi, potrebbe essere una tua applicazione Social e così via. Tutto dipende da come i progettisti di queste applicazioni, hanno deciso di rendere sensibili parti di queste.
Il sistema operativo Android, pertanto, in tutte le situazioni in cui si propaga un messaggio gestibile da più applicazioni o Activity, dovrà dare la possibilità all’utente di scegliere quale di queste app dovrà gestire il dato, tipicamente tramite una finestra simile a quella di figura a lato. A partire dalla versione M di Android, spesso questa scelta è fatta in automatico, ma in alcuni casi di ambiguità, Android ci riproporrà questa finestra.
Cosa imparerai
- Imparerai a registrare un’ Activity in modo che possa essere attivata dalla chiamata di un’altra Activity tramite un Intent Implicito
- Conoscerai le più usate azioni che è possibile monitorare durante queste chiamate
- Imparerai a registrare un’Activity che faccia le veci di un browser
- Imparerai a registrare un’Activity che si attivi se l’utente vuole inviare un messaggio email, un sms, o in generale dei dati.
Il pianto del bambino e Intent-Filter
Qual è il meccanismo, alla base di Android, che permette a quest’ultimo di scegliere quali applicazioni mostrare all’utente nel caso di esecuzione di un Intent Implicito da parte di qualche APP interna al dispositivo?
E’ necessario riprendere in mano un file, visto in uno dei primo tutorial e poi un po’ abbandonato: il file androidmanifest.xml
Come puoi osservare dal codice qui sotto, ogni nostra applicazione, presenta all’interno di questo file, il tag <intent-filter> come figlio del nodo <activity>.
<activity name=".MainActivity" android:label="@string/app_name"> <intent-filter> ... </intent-filter> </activity>
Grazie al software Android Studio, questo tag viene SEMPRE creato in automatico all’atto della creazione di un nuovo progetto che abbia almeno un’Activity.Questo quindi ci aiuta a ricordare a cosa serve e com’è strutturato a livello d’informazioni da inserire. In assenza di tale riga, il componente o l'applicazione potrà essere richiamata solo in modo Esplicito, in quanto è come se fosse SORDA a questo continuo invio di messaggi generato dagli Intent.
Questo nodo ha il preciso compito d’informare Android, che la nostra Activity è in grado di "svegliarsi" in seguito al verificarsi di particolari messaggi/azioni trasmessi dall'interno del dispositivo o da altre applicazioni.
NB: Il messaggio/azione a cui deve rispondere OBBLIGATORIAMENTE ogni nostra applicazione, è proprio il lancio e l’avvio di questa. Se tu sbirciassi adesso nel file androidmanifest.xml della tua applicazione, troverai sicuramente una voce che permette di ottenere questo comportamento.
ll meccanismo, se vogliamo, è molto simile a quello che avviene in natura tra madre e figlio appena nato: quando la mamma sente il pianto del bambino, in automatico si sveglierà e si alzerà per controllare cosa sia successo (coliche, bisogno di affetto, voglia di giocare, etc).
In generale il papà non è "programmato" per sentirlo (se hai figli, forse ne sai qualcosa), quindi, nella sua Activity, non sarà fortunatamente presente alcun nodo <intent-filter>.
Applicare le "orecchie" ad un'applicazione e Activity
Affinché una certa applicazione sia in grado di attivarsi in seguito al verificarsi dell'invio di un messaggio di azione specifico da parte di qualche componente di Android o da parte di altre applicazioni, è necessario modificare il file androidmanifest.xml e aggiungere un nodo, il tag <intent-filter> all'interno dell'Activity che vogliamo si attiviti.
Grazie a questa modifica è come se la nostra app, venisse, come detto, dotata di "orecchie" per sentire.
Il tag è caratterizzato da una serie d’informazioni, le quali cercano di fornire ad Android, tutto il necessario per fare la scelta corretta, non appena si verifichi il lancio di un Intent Implicito.
E’ proprio sulla base dei valori che andrò a inserire in questo nodo, che Android deciderà quali applicazioni o activity lanciare.
In generale, per ogni nodo <intent-filter> che deciderò di inserire all’interno del tag <activity>, è possibile specificare 3 tipologie di attributi: ACTION,CATEGORY,DATA.
Più attributi inseriremo, più selettiva sarà la scelta che Android dovrà fare per attivare l’activity.
E’ chiaro che ci deve essere corrispondenza tra questi attributi e quelli che l’intent invierà, al fine di poter attivare l’activity correttamente.
I nodi che è possibile specificare all’interno di <intent-filter> sono:
- <action>: qui inserirai il nome dell'azione (già codificata per noi, dagli sviluppatori di Android) che verrà "ascoltata" dalla nostra Activity e che la nostra Activity sarà in grado di gestire (es. MAIN, EDIT, VIEW etc)
- <category> (* opzionale): è un’ulteriore informazione che identifica il tipo di azione. Nel caso il nostro Intent non specifichi questo dato, allora spesso si inserisce il valore DEFAULT
- <data> (* opzionale): fornisce informazioni sulla tipologia di dati eventuali che l'Activity è in grado di gestire (testo, immagine etc) nel formato mime (es. text/plain), specificando una serie di attributi tra cui android:host, android:mimetype,android:path, android:port, android:scheme. Anche in questo caso è opzionale.
Come puoi notare, l’unico tag obbligatorio è <action>, che è intimamente collegato al parametro AZIONE specificato all’interno di un Intent Implicito.
Ad esempio, riprendendo il codice visto in precedenza, ogni applicazione, affinché possa essere lanciata, deve diventare sensibile all’azione MAIN e deve appartenere alla categoria LAUNCHER, due informazioni che vengono registrate nel relativo nodo del file manifest, corrispondente all’Activity Principale.
Qui sotto trovi le righe in questione:
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
Non è necessario imparare a memoria tutte le diverse tipologie di AZIONI native codificate all'interno di Android, perché, in genere, è sufficiente farsi aiutare dal nostro IDE, ricordandosi che il tutto si trova dentro ad android.intent.a…
La lista, come vedi, è molto lunga e potrebbe spaventare, ma in realtà, sono meno di 10 le azioni che generalmente vengono usate nella maggior parte delle applicazioni.
Ecco allora le azioni più comuni, che è possibile monitorare:
- android.intent.action.MAIN: per rispondere a richieste di lancio applicazione
- android.intent.action.EDIT: per rispondere a richieste di modifica dati
- android.intent.action.SEND: per rispondere a richieste di invio dati
- android.intent.action.VIEW: per rispondere a richieste di visualizzazione di dati
- android.intent.action.CALL: per rispondere a richieste di chiamata numero telefonico
- android.intent.action.DIAL: per rispondere a richieste di inserimento numero telefonico
NB: All’interno della stessa Activity, io posso definire più azioni contemporaneamente.
Per quanto riguarda le categorie, le più usate sono:
- android.intent.category.LAUNCHER: per definire l’Activity da usare per il lancio dell’app.
- android.intent.category.DEFAULT: per definire l’Activity predefinita da usare
Come si usa l'Intent Filter nella pratica?
Torniamo allora all’esempio precedente, e ipotizziamo che nel dispositivo dell’ utente siano installate due applicazioni:
- la prima, tramite un bottone, è in grado di inviare un Intent implicito per la visualizzazione di una pagina web (ACTION_VIEW), passando anche dei dati, come per esempio un url, in questo modo:
Intent intenzione = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.video-corsi.com"));
- la seconda applicazione, spesso chiamata Sub-Activity, è in grado di rispondere a tutte le azioni di richiesta per l’apertura di una pagina web, fatte da una qualsiasi app.
Come devo modificare il file manifest della seconda applicazione affinché si "risvegli" in seguito all’invio dell’Intent Implicito?
Dovrò chiaramente aggiungere un nodo <intent-filter> all’interno dell’Activity che vogliamo possa gestire l’eventuale dato inviato.
Se modificassi il file manifest della seconda app, come nell’esempio qui sotto:
<activity android:name=".Pagina1" android:label="@string/pagina1_name" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" android:host="*" /> </intent-filter> </activity>
mi aspetto che l’Activity di nome Pagina1 sia aperta, ogniqualvolta ci sia un Intent Implicito che invia un’azione di tipo VIEW.
Nota la presenza, sia del nodo opzionale <category> impostato al valore costante android.intent.category.DEFAULT e del nodo <data> in cui ho specificato come proprietà schema "http", ad indicare che i dati in grado di essere gestiti sono dei link, compresa un’indicazione sull’host, in modo da filtrare eventuali url.
NB: il simbolo dell’asterisco, nella sintassi delle espressioni regolari, è equivalente ad un qualsiasi carattere. Quindi una stringa del tipo: http://*corso* comprende molte stringhe del tipo http://www.corso.com, http://www.corsoandroid.it, http://corso.com etc
Inserendo poi questo codice all’interno della Sub-Activity, sarò in grado di recuperare il link passato dall’app chiamante, nell’ipotesi ovviamente che l’utente scelga di aprirlo con la mia app.
Intent intent = getIntent(); String url = intent.getDataString();
E’ chiaro che se io non aggiungessi alcun nodo <intent-filter>, la mia activity non sarebbe MAI richiamabile da alcuna applicazione o altra Activity in modo Implicito. L’unica possibilità sarebbe la chiamata Esplicita.
Qui sotto alcuni esempi di come si possa impostare il nodo <intent-filter> per rispondere ad azioni comuni.
Esempio: Registro un’Activity da lanciare come browser
<activity android:name=".MiaActivitiy" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http"/> </intent-filter> </activity>
Esempio: Registro un’Activity da usare per l’invio di dati
<activity android:name=".MiaActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity>
In tutti gli esempi visti, non abbiamo mai fatto alcun cenno a cosa succeda quando la Sub-Activity chiamata dall’Activity, si attiva e conclude l’azione per cui era stata progettata, oppure cosa succede in seguito alla chiusura. Come avrai intuito, non c’è alcun legame tra l’Activity chiamante e la Sub-Activity.
In certe situazioni mi potrebbe far comodo, conoscere che la Sub-Activity ha concluso il tutto, in modo positivo e avere così indietro un messaggio o un parametro che possa essermi di aiuto per informare l’ l’Activity chiamante ad eseguire certe ulteriori azioni. Tipico esempio è quando inseriamo nella nostra app un bottone per accedere alla fotocamera e scattare una foto. Al termine, l'immagine potrebbe essere recuperata dall'app e visualizzata nell'Activity chiamante, quindi devo avere un meccanismo in grado di passare questa immagine.
Per fare questo è necessario introdurre un nuovo concetto, quello di startActivityForResult(); che vedremo in uno dei prossimi tutorial.
2024-10-14 Tipo/Autore: Davide Copelli {ing} Pubblicato da: CorsoAndroid.it