Un Intent
è un oggetto di messaggistica che puoi utilizzare per richiedere un'azione da un altro componente dell'app.
Anche se gli intent facilitano la comunicazione tra i componenti in diversi modi, ci sono tre
casi d'uso fondamentali:
- Avvio di un'attività
Un
Activity
rappresenta una singola schermata in un'app. Puoi avviare una nuova istanza di unActivity
passando unIntent
astartActivity()
.Intent
descrive l'attività da avviare e riporta tutti i dati necessari.Se vuoi ricevere un risultato dall'attività al termine, chiama
startActivityForResult()
. La tua attività riceve il risultato come oggettoIntent
separato nel callbackonActivityResult()
dell'attività. Per ulteriori informazioni, consulta la guida Attività. - Avviare un servizio
Un
Service
è un componente che esegue operazioni in background senza un'interfaccia utente. Con Android 5.0 (livello API 21) e versioni successive, puoi avviare un servizio conJobScheduler
. Per ulteriori informazioni suJobScheduler
, scopriAPI-reference documentation
.Per le versioni precedenti ad Android 5.0 (livello API 21), puoi avviare un servizio utilizzando della classe
Service
. Puoi avviare un servizio di eseguire un'operazione una tantum (come il download di un file) passando unIntent
astartService()
.Intent
descrive il servizio per avviare e trasporta tutti i dati necessari.Se il servizio è progettato con un'interfaccia client-server, puoi associarlo al servizio da un altro componente passando
Intent
abindService()
. Per ulteriori informazioni, consulta la guida sui servizi. - Pubblicare una trasmissione
Una trasmissione è un messaggio che qualsiasi app può ricevere. Il sistema fornisce vari annunci per eventi di sistema, ad esempio quando il sistema si avvia o il dispositivo inizia a ricaricarsi. Puoi trasmettere un annuncio ad altre app trasmettendo un
Intent
asendBroadcast()
osendOrderedBroadcast()
.
Il resto di questa pagina spiega come funzionano gli intent e come utilizzarli. Per informazioni correlate, consulta Interazione con altre app e Condivisione di contenuti.
Tipi di intent
Esistono due tipi di intent:
- Gli intent espliciti specificano il componente dell'applicazione che soddisferà l'intento, specificando un valore
ComponentName
completo. In genere, userai un'intent esplicita per avviare un componente nella tua app, perché conosci il nome della classe dell'attività o del servizio che vuoi avviare. Per Ad esempio, potresti avviare una nuova attività nella tua app in risposta a un'azione dell'utente oppure avviare un servizio per scaricare un file in background. - Gli intent impliciti non menzionano un componente specifico, ma dichiarano un'azione generale. che viene gestito da un componente di un'altra app. Ad esempio, se vuoi mostrare all'utente una posizione su una mappa, potete utilizzare un intento implicito per richiedere che un altro mostrare una posizione specificata su una mappa.
La Figura 1 mostra come viene utilizzato un intent quando viene avviata un'attività. Quando
L'oggetto Intent
nomina in modo esplicito un componente di attività specifico, ovvero il sistema
avvia immediatamente quel componente.
Quando utilizzi un intent implicito, il sistema Android trova il componente appropriato da avviare confrontando i contenuti dell'intent con i filtri per intent dichiarati nel file manifest di altre app sul dispositivo. Se l'intent corrisponde a un filtro per intent, il sistema avvia il componente e lo pubblica
l'oggetto Intent
. Se sono compatibili più filtri di intent, il sistema visualizza una finestra di dialogo in modo che l'utente possa scegliere l'app da utilizzare.
Un filtro intent è un'espressione nel file manifest di un'app che specifica il tipo di intent che il componente vorrebbe ricevere. Ad esempio, dichiarando un filtro intent per un'attività, consenti ad altre app di avviare direttamente la tua attività con un determinato tipo di intent. Allo stesso modo, se non dichiari alcun filtro per intent per un'attività, quest'ultima può essere avviata solo con un intento esplicito.
Attenzione:per assicurarti che la tua app sia sicura,
usa un modello esplicita
quando si avvia un Service
e non
dichiarare i filtri di intent per i tuoi servizi. L'utilizzo di un intent implicito per avviare un servizio è
un rischio per la sicurezza perché non puoi sapere con certezza quale servizio risponderà all'intento,
e l'utente non può vedere quale servizio viene avviato. A partire da Android 5.0 (livello API 21), il sistema
genera un'eccezione se chiami bindService()
con un intento implicito.
Sviluppo di un'intenzione
Un oggetto Intent
trasporta informazioni utilizzate dal sistema Android
per stabilire quale componente iniziare (ad esempio il nome esatto del componente o il componente
categoria che dovrebbe ricevere l'intent), oltre alle informazioni utilizzate dal componente destinatario nella
eseguire correttamente l'azione (ad esempio l'azione da intraprendere e i dati su cui agire).
Le informazioni principali contenute in un Intent
sono le seguenti:
- Nome componente
- Il nome del componente da iniziare.
Questa informazione è facoltativa, ma è l'informazione fondamentale che influenza l'intenzione explicit, ovvero l'intent che deve essere mostrato solo al componente dell'app definita dal nome del componente. Senza il nome di un componente, l'intent è implicito e la decide quale componente deve ricevere l'intent in base alle altre informazioni sull'intent (come l'azione, i dati e la categoria descritti di seguito). Se hai bisogno di avviare un processo nella tua app, devi specificarne il nome.
Nota: quando avvii
Service
, specifica sempre il nome del componente. In caso contrario, non puoi sapere con certezza quale servizio che risponderà all'intento e l'utente non potrà vedere quale servizio avvia.Questo campo dell'
Intent
è unComponentName
, che puoi specificare utilizzando un modello nome qualificato della classe del componente di destinazione, incluso il nome del pacchetto dell'app, ad esempio:com.example.ExampleActivity
. Puoi impostare il nome del componente consetComponent()
,setClass()
,setClassName()
, o conIntent
. - Azione
- Una stringa che specifica l'azione generica da eseguire (ad esempio visualizza o scegli).
Nel caso di un intent di trasmissione, questa è l'azione che si è verificata e viene segnalata. L'azione determina in gran parte il modo in cui è strutturato il resto dell'intento, in particolare le informazioni contenute nei dati e negli extra.
Puoi specificare le tue azioni affinché possano essere utilizzate dagli intent all'interno della tua app (o da altre app per richiamare i componenti dell'app), ma in genere specifichi le costanti di azione definita dalla classe
Intent
o da altre classi framework. Ecco alcune azioni comuni per avviare un'attività:ACTION_VIEW
- Utilizza questa azione in un intent con
startActivity()
quando hai a disposizione alcune informazioni che un'attività può essere mostrata all'utente, come una foto da visualizzare in un'app Galleria o un indirizzo a visualizzali in un'app di mappe. ACTION_SEND
- Noto anche come intent di condivisione, dovresti usarlo in un intent con
startActivity()
se hai a disposizione alcuni dati che l'utente può condividere tramite un'altra app, ad esempio un'app email o un'app di condivisione sui social.
Consulta il riferimento del corso
Intent
per saperne di più costanti che definiscono azioni generiche. Sono definite altre azioni altrove nel framework Android, ad esempio inSettings
per le azioni che aprono schermate specifiche nell'app Impostazioni del sistema.Puoi specificare l'azione per un intent con
setAction()
o con un costruttoreIntent
.Se definisci le tue azioni, assicurati di includere il nome del pacchetto dell'app come prefisso, come illustrato nell'esempio seguente:
Kotlin
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Java
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- Dati
- L'URI (un oggetto
Uri
) che fa riferimento ai dati a cui essere intervenuto su e/o il tipo MIME dei dati. Il tipo di dati forniti è generalmente dettato dall'azione dell'intent. Per Ad esempio, se l'azione èACTION_EDIT
, i dati devono contenere la macro URI del documento da modificare.Quando crei un intent, spesso è importante specificare il tipo di dati (il suo tipo MIME) oltre al relativo URI. Ad esempio, un'attività in grado di visualizzare immagini probabilmente non sarà per riprodurre un file audio, anche se i formati URI potrebbero essere simili. La specifica del tipo MIME dei dati consente al sistema Android di trovare il componente migliore per ricevere l'intent. Tuttavia, a volte il tipo MIME può essere dedotto dall'URI, in particolare quando i dati sono un URI
content:
. Un URIcontent:
indica che i dati si trovano sul dispositivo e controllato da unContentProvider
, che rende visibile al sistema il tipo MIME dei dati.Per impostare solo l'URI dei dati, chiama
setData()
. Per impostare solo il tipo MIME, chiamasetType()
. Se necessario, puoi impostare entrambi esplicitamente consetDataAndType()
.Attenzione: se vuoi impostare sia l'URI sia il tipo MIME, non chiama
setData()
esetType()
perché annullano ciascuno il valore dell'altro. Usa sempresetDataAndType()
per impostarli entrambi URI e tipo MIME. - Categoria
- Una stringa contenente informazioni aggiuntive sul tipo di componente
che dovrebbe gestire l'intento. È possibile specificare un numero qualsiasi di descrizioni
inseriti in un intent, ma la maggior parte degli intent non richiede una categoria.
Ecco alcune categorie comuni:
CATEGORY_BROWSABLE
- L'attività target consente di essere avviata da un browser web per visualizzare i dati a cui fa riferimento un link, ad esempio un'immagine o un messaggio email.
CATEGORY_LAUNCHER
- L'attività è l'attività iniziale di un'attività ed è elencata nel avviatore di applicazioni del sistema.
Consulta la descrizione della classe
Intent
per l'elenco completo delle categorie.Puoi specificare una categoria con
addCategory()
.
Queste proprietà elencate sopra (nome componente, azione, dati e categoria) rappresentano che definiscono le caratteristiche di un'intenzione. Leggendo queste proprietà, il sistema Android sia in grado di risolvere da quale componente dell'app deve essere avviato. Tuttavia, un'intent può contenere informazioni aggiuntive che non influiscono sul modo in cui viene risolta in un componente dell'app. Un intent può anche fornire le seguenti informazioni:
- Extra
- Coppie chiave-valore che trasportano le informazioni aggiuntive necessarie per ottenere
l'azione richiesta.
Così come alcune azioni utilizzano particolari tipi di URI di dati, anche altre utilizzano particolari extra.
Puoi aggiungere altri dati con vari metodi di
putExtra()
, accettano due parametri: il nome della chiave e il valore. Puoi anche creare un oggettoBundle
con tutti i dati aggiuntivi, quindi inserire ilBundle
nelIntent
conputExtras()
.Ad esempio, durante la creazione dell'intenzione di inviare un'email con
ACTION_SEND
, puoi specificare il destinatario to con ilEXTRA_EMAIL
e specifica l'oggetto con ChiaveEXTRA_SUBJECT
.La classe
Intent
specifica molte costantiEXTRA_*
per tipi di dati standardizzati. Se devi dichiarare le tue chiavi aggiuntive (per intent che riceve l'app), assicurati di includere il nome del pacchetto dell'app come prefisso, come illustrato nell'esempio seguente:Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Attenzione: non usare
Parcelable
o Dati diSerializable
quando invii un intent previsto un'altra app da ricevere. Se un'app tenta di accedere ai dati in un oggettoBundle
ma non alla classe parceled o serializzata, il sistema generaRuntimeException
. - Flag
- I flag sono definiti nella classe
Intent
e fungono da metadati per l'intento. I flag possono indicare al sistema Android come avviare un'attività (ad esempio, attività l'attività deve appartenere e come trattarla dopo il suo lancio (ad esempio se appartiene all'elenco dei attività).Per ulteriori informazioni, consulta il metodo
setFlags()
.
Esempio di intent esplicito
Un intent esplicito è quello che utilizzi per avviare uno specifico componente dell'app, ad esempio
per un'attività o un servizio specifico nella tua app. Per creare un intento esplicito, definisci
il nome del componente per l'oggetto Intent
,
le altre proprietà di intent sono facoltative.
Ad esempio, se hai creato un servizio nella tua app denominato DownloadService
, pensato per scaricare un file dal web, puoi avviarlo con il seguente codice:
Kotlin
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse
(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse
(fileUrl)); startService(downloadIntent);
Intent(Context, Class)
fornisce l'app Context
e
componente di un oggetto Class
. Di conseguenza,
questo intent avvia esplicitamente la classe DownloadService
nell'app.
Per ulteriori informazioni su come creare e avviare un servizio, consulta Servizi.
Esempio di intent implicito
Un intent implicito specifica un'azione che può richiamare qualsiasi app sul dispositivo in grado di eseguire l'azione. L'utilizzo di un intent implicito è utile quando la tua app non può eseguire ma probabilmente altre app potrebbero farlo e vorresti che fosse l'utente a scegliere quale app utilizzare.
Ad esempio, se vuoi che l'utente condivida contenuti con altre persone,
crea un intent
con l'azione ACTION_SEND
e aggiungere extra che specificano i contenuti da condividere. Quando chiami
startActivity()
con questo intento, l'utente può
scegli un'app con cui condividere i contenuti.
Kotlin
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
Quando viene chiamato startActivity()
, il sistema
esamina tutte le app installate per determinare quali sono in grado di gestire questo tipo di intent (una
l'intent con l'azione ACTION_SEND
e che contenga "testo/normale"
dati). Se c'è una sola app in grado di gestire questa situazione, questa si apre immediatamente e riceve il
l'intento. Se nessuna altra app è in grado di gestirlo, la tua app può rilevare il
ActivityNotFoundException
che si verifica. Se più attività accettano l'intent, il sistema
mostra una finestra di dialogo come quella della Figura 2, in modo che l'utente possa scegliere l'app da utilizzare.
Nella guida sono disponibili anche ulteriori informazioni sull'avvio di altre app sull'invio all'utente di un'altra app.
Forzare un selettore di app
Se più app rispondono al tuo intento implicito, l'utente può selezionare l'app da utilizzare e renderla la scelta predefinita per un'azione. La possibilità di selezionare un valore predefinito è utile quando si esegue un'azione per la quale l'utente probabilmente desidera utilizzare la stessa app ogni volta, ad esempio quando si apre una pagina web (gli utenti spesso preferiscono un solo browser web).
Tuttavia, se più app possono rispondere all'intento e l'utente potrebbe voler usare un altro
ogni volta, dovresti mostrare esplicitamente una finestra di dialogo. La finestra di dialogo del selettore chiede
l'utente può selezionare l'app da utilizzare per l'azione (l'utente non può selezionare un'app predefinita
l'azione). Ad esempio, quando la tua app esegue "Condividi" con l'azione ACTION_SEND
, gli utenti potrebbero voler condividere contenuti utilizzando un'app diversa a seconda
della sua situazione attuale, quindi dovresti sempre usare la finestra di dialogo del selettore, come mostrato nella Figura 2.
Per mostrare il selettore, crea un Intent
utilizzando createChooser()
e passalo a startActivity()
, come mostrato nell'esempio seguente.
Questo esempio mostra una finestra di dialogo con un elenco di app che rispondono all'intent passato al metodo createChooser()
e utilizza il testo fornito come
titolo della finestra di dialogo.
Kotlin
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Java
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
Rileva i lanci di intent non sicuri
La tua app potrebbe avviare intent per spostarsi tra i componenti al suo interno o per eseguire un'azione per conto di un'altra app. Per migliorare la sicurezza della piattaforma, Android 12 (livello API 31) e versioni successive forniscono una funzionalità di debug che ti avvisa se la tua app esegue un avvio non sicuro di un intent. Ad esempio, la tua app potrebbe eseguire un avvio non sicuro di un intent nidificato, che viene passato come extra in un altro intento.
Se la tua app esegue entrambe le seguenti azioni, il sistema rileva un lancio di intent e una violazione di StrictMode si verifica:
- La tua app separa un intent nidificato dagli extra di un intent caricato.
- La tua app avvia immediatamente un'app
utilizzando gli intent nidificati,
come trasferire l'intento
startActivity()
,startService()
, obindService()
Per ulteriori dettagli su come identificare questa situazione e apportare modifiche alla tua app, leggi il post del blog sulla Nesting di Android Intenzioni su Medium.
Verificare la presenza di lanci di intent non sicuri
Per verificare la presenza di lanci per intent non sicuri nella tua app, chiama
detectUnsafeIntentLaunch()
quando configuri VmPolicy
, come mostrato nello snippet di codice riportato di seguito. Se
rileva una violazione di StrictMode, potresti interrompere l'esecuzione dell'app
e proteggere le informazioni potenzialmente sensibili.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Java
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
Usare gli intent in modo più responsabile
Per ridurre al minimo la possibilità del lancio di un intent non sicuro e di una violazione di StrictMode, segui queste best practice.
Copia solo gli extra essenziali all'interno degli intent e esegui eventuali operazioni necessarie
igienizzazione e convalida. La tua app potrebbe copiare gli extra da un intent a
un altro intent usato per avviare un nuovo componente. Ciò si verifica quando
chiamate da app
putExtras(Intent)
o
putExtras(Bundle)
.
Se l'app esegue una di queste operazioni, copia solo le azioni aggiuntive che
che prevede un componente di ricezione. Se l'altro intent (che riceve la copia)
avvia un componente che non è
esportato, sanificare
convalidare gli extra prima di copiarli nell'intento che avvia
di strumento di authoring.
Non esportare i componenti dell'app inutilmente. Ad esempio, se
avviare un componente dell'app utilizzando un intent nidificato interno, impostare
l'attributo android:exported
del componente a false
.
Utilizza un PendingIntent
anziché un intento nidificato. In questo modo, quando un'altra app separa i PendingIntent
dei suoi
contenente Intent
, l'altra app può avviare PendingIntent
utilizzando
l'identità della tua app. Questa configurazione consente all'altra app di avviarsi in sicurezza
qualsiasi componente della tua app, inclusi quelli non esportati.
Il diagramma nella figura 2 mostra in che modo il sistema passa il controllo dal tuo (client) app a un'altra app (di servizio) e tornare all'app:
- La tua app crea un intent che richiama un'attività in un'altra app. Entro
questo intent, aggiungi un oggetto
PendingIntent
come extra. Questo intent in attesa richiama un componente nella tua app; questo componente non viene esportato. - Quando riceve l'intent dell'app, l'altra estrae i valori nidificati
PendingIntent
oggetto. - L'altra app richiama il metodo
send()
sull'oggettoPendingIntent
. - Dopo aver ritrasferito il controllo all'app, il sistema richiama lo stato usando il contesto della tua app.
Figura 2. Diagramma della comunicazione tra app quando si utilizza un oggetto Pending nidificato l'intento.
Ricezione di un intent implicito
Per pubblicizzare gli intent impliciti che la tua app può ricevere, dichiara uno o più filtri per intent per
per ciascuno dei componenti della tua app con un <intent-filter>
nel tuo file manifest.
Ogni filtro per intent specifica il tipo di intent che accetta in base all'azione dell'intent,
dati e categoria. Il sistema invia un intent implicito al componente dell'app solo se il parametro
per intent possono passare attraverso uno dei filtri di intent.
Nota: un'intenzione esplicita viene sempre pubblicata nel relativo target, indipendentemente dai filtri di intent dichiarati dal componente.
Un componente dell'app deve dichiarare filtri separati per ogni job univoco che può fare.
Ad esempio, un'attività in un'app Galleria immagini può avere due filtri: un filtro
per visualizzare un'immagine e un altro filtro per modificare un'immagine. Quando inizia l'attività,
controlla Intent
e decide come comportarsi in base alle informazioni
in Intent
(ad esempio per mostrare o meno i controlli dell'editor).
Ogni filtro per intent è definito da un elemento <intent-filter>
nel file manifest dell'app, nidificato nel componente dell'app corrispondente (ad esempio un elemento <activity>
).
In ogni componente dell'app che include un elemento <intent-filter>
,
imposta esplicitamente un valore
android:exported
Questo attributo indica se il componente dell'app è accessibile ad altre app. In alcuni
ad esempio le attività i cui filtri per intent includono
LAUNCHER
, è utile impostare questo attributo su true
. Altrimenti,
è più sicuro impostare questo attributo su false
.
Avviso: se un'attività, un servizio o un broadcast receiver nella tua app utilizza i filtri per intent e non imposta esplicitamente il valore per android:exported
, la tua app non può essere installata su un dispositivo che esegue Android 12 o versioni successive.
All'interno di <intent-filter>
,
puoi specificare il tipo di intent da accettare utilizzando uno o più
di questi tre elementi:
<action>
- Dichiara l'azione intent accettata nell'attributo
name
. Il valore deve essere il valore letterale della stringa di un'azione, non la costante di classe. <data>
- Dichiara il tipo di dati accettati, utilizzando uno o più attributi che specificano vari
dell'URI di dati (
scheme
,host
,port
,path
) e tipo MIME. <category>
- Dichiara che la categoria di intent è accettata nell'attributo
name
. Il valore deve essere il valore letterale della stringa di un'azione, non la costante di classe.Nota:per ricevere intent impliciti, devi deve includere
CATEGORY_DEFAULT
nel filtro per intent. I metodistartActivity()
estartActivityForResult()
tratta tutti gli intent come se avesse dichiarato la categoriaCATEGORY_DEFAULT
. Se non dichiari questa categoria nel filtro per intent, nessun intent implicito verrà risolto in la tua attività.
Ad esempio, di seguito è riportata una dichiarazione di attività con un filtro intent per ricevere un intento ACTION_SEND
quando il tipo di dati è di tipo di testo:
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
Puoi creare un filtro che includa più di un'istanza di
<action>
,
<data>
oppure
<category>
In questo caso occorre assicurarsi che il componente sia in grado di gestire
combinazioni di questi elementi di filtro.
Quando vuoi gestire più tipi di intent, ma solo in determinate combinazioni di l'azione, i dati e il tipo di categoria, devi creare più filtri per intent.
Un intent implicito viene testato rispetto a un filtro confrontando l'intent con ogni tre elementi. Per essere pubblicato nel componente, l'intent deve superare tutti e tre i test. Se non riesce a trovare una corrispondenza per neanche uno di questi, il sistema Android non invia l'intent al componente. Tuttavia, poiché un componente può avere più filtri per intent, un intent che non passare attraverso uno dei filtri di un componente potrebbe passare attraverso su un altro filtro. Nella sezione di seguito sono disponibili ulteriori informazioni su come il sistema risolve gli intent sulla risoluzione dell'intenzione.
Attenzione : l'utilizzo di un filtro per intent non è un modo sicuro per impedire l'avvio di altre app
dai componenti. Sebbene i filtri per intent limitino un componente in modo che risponda solo
determinati tipi di intent impliciti, un'altra app può potenzialmente avviare il componente dell'app
utilizzando un intent esplicito se lo sviluppatore determina i nomi dei componenti.
Se è importante che soltanto la tua app possa avviare uno dei tuoi componenti,
e non dichiarare i filtri di intent nel file manifest. Imposta invece
Attributo exported
a "false"
per quel componente.
Analogamente, per evitare di eseguire inavvertitamente
Service
, usa sempre un intento esplicito per avviare il tuo servizio.
Nota:
per tutte le attività, devi dichiarare i filtri di intent nel file manifest.
Tuttavia, i filtri per i broadcast receiver possono essere registrati in modo dinamico chiamando
registerReceiver()
. Potrai quindi annullare la registrazione del destinatario con unregisterReceiver()
. In questo modo consenti alla tua app
di ascoltare trasmissioni specifiche solo per un determinato periodo di tempo mentre utilizzi l'app
in esecuzione.
Filtri di esempio
Ecco un esempio per dimostrare alcuni dei comportamenti dei filtri per intent dal file manifest di un'app di condivisione sui social:
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
La prima attività, MainActivity
, è il punto di ingresso principale dell'app, l'attività che
si apre quando l'utente avvia inizialmente l'app con l'icona in Avvio applicazioni:
- L'azione
ACTION_MAIN
indica che questo è il punto di ingresso principale e non prevede dati sull'intent. - La categoria
CATEGORY_LAUNCHER
indica che questa attività dovrebbe essere posizionata in Avvio applicazioni del sistema. Se l'elemento<activity>
non specifica un'icona conicon
, il sistema utilizza l'icona da<application>
.
Per visualizzare l'attività in Avvio applicazioni, è necessario che questi due elementi siano accoppiati.
La seconda attività, ShareActivity
, ha lo scopo di facilitare la condivisione di testi e contenuti multimediali
contenuti. Sebbene gli utenti possano accedere a questa attività passando da MainActivity
,
possono anche accedere a ShareActivity
direttamente da un'altra app che emette un intento implicito corrispondente a uno dei due filtri per intent.
Nota: il tipo MIME,
application/vnd.google.panorama360+jpg
è un tipo di dati speciale che specifica
foto panoramiche, che puoi gestire con Google
le API panoramiche.
Abbina gli intent a quelli di altre app filtri per intent
Se un'altra app ha come target Android 13 (livello API 33) o versioni successive, può gestire le tue
solo se quest'ultimo corrisponde alle azioni e alle categorie di un
Elemento <intent-filter>
nell'altra app. Se il sistema non trova
una corrispondenza, genera un
ActivityNotFoundException
L'app di invio deve gestire
questa eccezione.
Analogamente, se aggiorni la tua app in modo che abbia come target Android 13
o superiore, tutti gli intent provenienti da app esterne vengono inviati a un
del componente esportato della tua app solo se quell'intent corrisponde alle azioni e
categorie di un elemento <intent-filter>
dichiarato dalla tua app. Questo comportamento
si verifica indipendentemente dalla versione dell'SDK target dell'app di invio.
La corrispondenza dell'intenzione non viene applicata nei seguenti casi:
- Intent pubblicati a componenti che non dichiarano filtri per intent.
- Intent provenienti dalla stessa app.
- gli intent provenienti dal sistema; ovvero gli intent inviati
"UID sistema" (uid=1000). Le app di sistema includono
system_server
e le app che hanno impostatoandroid:sharedUserId
aandroid.uid.system
. - Intent che hanno origine dalla directory principale.
Scopri di più sulla corrispondenza all'intenzione.
Utilizzare un intent in attesa
Un oggetto PendingIntent
è un wrapper attorno a un oggetto Intent
. Lo scopo principale di un PendingIntent
è concedere l'autorizzazione a una richiesta estera
di utilizzare i Intent
contenuti come se fossero stati eseguiti dai tuoi
il processo dell'app.
I principali casi d'uso relativi a un intento in sospeso includono quanto segue:
- Dichiarazione di un intent da eseguire quando l'utente esegue un'azione con la notifica
(lo
NotificationManager
del sistema Android esegueIntent
). - Dichiarare l'intenzione da eseguire quando l'utente compie un'azione con l'utente
Widget app
(l'app della schermata Home esegue
Intent
). - Dichiarazione di un'intenzione da eseguire in un momento futuro specifico (i
l'
AlarmManager
del sistema esegueIntent
).
Così come ogni oggetto Intent
è progettato per essere gestito da una
tipo di componente dell'app (Activity
, Service
o
BroadcastReceiver
), anche un PendingIntent
deve essere
creati con la stessa considerazione. Se usi un intent in attesa, l'app non
eseguire l'intent con una chiamata come startActivity()
. Devi invece dichiarare il tipo di componente previsto quando crei l'oggetto
PendingIntent
chiamando il rispettivo metodo del creator:
PendingIntent.getActivity()
per unIntent
che avvia unActivity
.PendingIntent.getService()
per unIntent
che avvia unService
.PendingIntent.getBroadcast()
per unIntent
che avvia unBroadcastReceiver
.
A meno che la tua app riceva intent in attesa da altre app,
i metodi precedenti per creare un PendingIntent
sono probabilmente gli unici
PendingIntent
metodi di cui avrai bisogno.
Ogni metodo utilizza l'app corrente Context
,
Intent
da aggregare e uno o più flag che specificano
come dovrebbe essere utilizzato l'intent (ad esempio se può essere utilizzato più di una volta).
Per saperne di più sull'utilizzo degli intent in attesa, consulta la documentazione di ogni dei rispettivi casi d'uso, ad esempio nella scheda Notifiche e le guide dell'API App Widgets.
Specifica la mutabilità
Se la tua app ha come target Android 12 o versioni successive, devi specificare:
mutabilità di ogni oggetto PendingIntent
creato dalla tua app. Per dichiarare che
un determinato oggetto PendingIntent
è mutabile o immutabile, usa
PendingIntent.FLAG_MUTABLE
o
PendingIntent.FLAG_IMMUTABLE
rispettivamente.
Se la tua app tenta di creare un oggetto PendingIntent
senza impostare nessuno dei flag di mutabilità, il sistema genera un
IllegalArgumentException
e
in Logcat viene visualizzato il seguente messaggio:
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
Crea intent in attesa immutabili, se possibile
Nella maggior parte dei casi, l'app dovrebbe creare oggetti PendingIntent
immutabili, come
mostrato nel seguente snippet di codice. Se un oggetto PendingIntent
è immutabile,
le altre app non possono modificare l'intent per regolare il risultato della chiamata al
l'intento.
Kotlin
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
Tuttavia, alcuni casi d'uso richiedono invece oggetti PendingIntent
modificabili:
- Supportare azioni di risposta diretta in
notifiche. La
La risposta diretta richiede una modifica ai dati del clip nell'oggetto PendingIntent
associato alla risposta. In genere, questa modifica viene richiesta passando
FILL_IN_CLIP_DATA
come flag al metodofillIn()
. - Associazione delle notifiche al framework Android Auto tramite istanze di
CarAppExtender
- Posizionamento delle conversazioni in bolle utilizzando istanze di
PendingIntent
. Un oggettoPendingIntent
mutabile consente al sistema di applicare i flag corretti, ad esempioFLAG_ACTIVITY_MULTIPLE_TASK
eFLAG_ACTIVITY_NEW_DOCUMENT
. - Richiesta di dati sulla posizione del dispositivo tramite chiamata
requestLocationUpdates()
o API simili. L'oggettoPendingIntent
modificabile consente al sistema di aggiungere per intent che rappresentano gli eventi del ciclo di vita delle località. Questi eventi includono un cambiamento nella località e la disponibilità di un fornitore. - Programmazione delle sveglie utilizzando
AlarmManager
. L'oggettoPendingIntent
modificabile consente al sistema di aggiungereEXTRA_ALARM_COUNT
intent extra. Questo extra rappresenta il numero di volte in cui una sveglia ricorrente è stata attivata. Se contiene questo extra, l'intent può comunicare con precisione un'app per sapere se una sveglia ricorrente è stata attivata più volte, ad esempio quando il dispositivo era in sospensione.
Ti consigliamo vivamente di creare un oggetto PendingIntent
modificabile nella tua app
di utilizzare un intent esplicito e di compilare
ComponentName
. In questo modo, ogni volta che un'altra app richiama PendingIntent
e restituisce il controllo alla tua app, viene sempre avviato lo stesso componente della tua app.
Utilizza intent espliciti all'interno di intent in attesa
Per definire meglio il modo in cui altre app possono usare gli intent in attesa della tua app, aggregare un intent in sospeso a un intent esplicito. Per seguire questa best practice, segui questi passaggi:
- Verifica che i campi relativi all'azione, al pacchetto e al componente dell'intent di base siano impostati.
-
Usa
FLAG_IMMUTABLE
, aggiunta in Android 6.0 (livello API 23) per creare intent in attesa. Questo flag impedisce alle app che ricevono unPendingIntent
di compilare proprietà non compilate. Se il valoreminSdkVersion
della tua app è22
o un livello inferiore, puoi garantire sicurezza e compatibilità insieme utilizzando il seguente codice:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
Risoluzione dell'intenzione
Quando il sistema riceve l'intenzione implicita di avviare un'attività, cerca il l'attività migliore per l'intenzione, confrontandola con i filtri per intent sulla base di tre aspetti:
- Azione.
- Dati (sia URI che tipo di dati).
- Categoria.
Le seguenti sezioni descrivono in che modo gli intent vengono associati ai componenti appropriati in base alla dichiarazione del filtro per intent nel file manifest di un'app.
Test azioni
Per specificare le azioni per intent accettate, un filtro per intent può dichiararne zero o più
<action>
, come mostrato nell'esempio seguente:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
Per superare questo filtro, l'azione specificata nel Intent
deve corrispondere a una delle azioni elencate nel filtro.
Se il filtro non elenca nessuna azione, non c'è niente per
intent a trovare una corrispondenza, in modo che tutti gli intent non superino il test. Tuttavia, se Intent
non specifica un'azione, passa il test a patto che il filtro
contiene almeno un'azione.
Test categoria
Per specificare le categorie di intent accettate, un filtro intent può dichiarare zero o più elementi <category>
, come mostrato nell'esempio seguente:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
Per avere l'intenzione di superare il test, ogni categoria in Intent
deve corrispondere a una categoria del filtro. Non è necessario l'inverso: il filtro per intent potrebbe
dichiarare più categorie di quelle specificate in Intent
e
Intent
risulta ancora valido. Di conseguenza, un intent senza categorie
supera sempre questo test, indipendentemente dalle categorie dichiarate nel filtro.
Nota:
Android applica automaticamente la categoria CATEGORY_DEFAULT
a tutti gli intent impliciti passati a startActivity()
e startActivityForResult()
.
Se vuoi che la tua attività riceva intent impliciti, deve includere una categoria per "android.intent.category.DEFAULT"
nei filtri intent, come mostrato nell'esempio <intent-filter>
precedente.
Test dei dati
Per specificare i dati sull'intent accettati, un filtro per intent può dichiararne zero o più
<data>
, come mostrato nell'esempio seguente:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
Ogni <data>
può specificare una struttura URI e un tipo di dati (tipo multimediale MIME).
Ogni parte dell'URI è un attributo distinto: scheme
, host
, port
e path
:
<scheme>://<host>:<port>/<path>
L'esempio seguente mostra i possibili valori per questi attributi:
content://com.example.project:200/folder/subfolder/etc
In questo URI, lo schema è content
, l'host è com.example.project
,
la porta è 200
e il percorso è folder/subfolder/etc
.
Ciascuno di questi attributi è facoltativo in un elemento <data>
,
ma ci sono dipendenze lineari:
- Se non viene specificato uno schema, l'host viene ignorato.
- Se non viene specificato un host, la porta viene ignorata.
- Se non sono specificati sia lo schema sia l'host, il percorso viene ignorato.
Quando l'URI in un'intenzione viene confrontato con una specifica URI in un filtro, viene confrontato solo con le parti dell'URI incluse nel filtro. Ad esempio:
- Se un filtro specifica solo uno schema, tutti gli URI con questo schema corrispondono al filtro.
- Se un filtro specifica uno schema e un'autorità ma non un percorso, tutti gli URI con lo stesso schema e la stessa autorità passano il filtro, indipendentemente dai relativi percorsi.
- Se un filtro specifica uno schema, un'autorità e un percorso, solo gli URI con lo stesso schema, l'autorità di controllo e il percorso superano il filtro.
Nota: una specifica del percorso può contenere un asterisco (*) per richiedere solo una corrispondenza parziale del nome del percorso.
Il test dei dati confronta sia l'URI sia il tipo MIME nell'intent con un URI e un tipo MIME specificati nel filtro. Le regole sono le seguenti:
- Un'intenzione che non contiene né un URI né un tipo MIME supera il test solo se il filtro non specifica URI o tipi MIME.
- Un intent che contiene un URI, ma nessun tipo MIME (né esplicito né dedotto dal l'URI) supera il test solo se il suo URI corrisponde al formato URI del filtro e il filtro non specifica un tipo MIME.
- Un intent che contiene un tipo MIME ma non un URI supera il test solo se il filtro elenca lo stesso tipo MIME e non specifica un formato URI.
- Un intent che contiene sia un URI sia un tipo MIME (esplicito o dedotto dal
URI) supera la parte del test di tipo MIME solo se
corrisponde a uno dei tipi elencati nel filtro. Passa la parte URI del test
se il suo URI corrisponde a un URI nel filtro o se ha un valore
content:
ofile:
e il filtro non specifica alcun URI. In altre parole, si presume che un componente supporti i daticontent:
efile:
se il filtro elenca solo un tipo MIME.
Nota: se un intent specifica un tipo URI o MIME, il test dei dati
non riuscirà se non sono presenti elementi <data>
in <intent-filter>
.
Quest'ultima regola, la regola (d), riflette l'aspettativa
che i componenti siano in grado di ottenere dati locali da un file o da un fornitore di contenuti.
Pertanto, i filtri possono indicare solo un tipo di dati e non è necessario
assegnare un nome agli schemi content:
e file:
.
L'esempio seguente mostra un caso tipico in cui un elemento <data>
indica ad Android che il componente può ricevere dati immagine da un contenuto
e lo visualizziamo:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
I filtri che specificano un tipo di dati, ma non un URI, sono forse i più comuni perché la maggior parte dei dati disponibili viene fornita dai fornitori di contenuti.
Un'altra configurazione comune è un filtro con uno schema e un tipo di dati. Per
Ad esempio, un elemento <data>
come il seguente indica ad Android che
il componente può recuperare i dati video dalla rete per eseguire l'azione:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
Corrispondenza di intent
Gli intent vengono abbinati ai filtri per intent non solo per scoprire un target
per attivare, ma anche per scoprire qualcosa sull'insieme
componenti sul dispositivo. Ad esempio, l'app Home compila il programma di avvio app
trovandovi tutte le attività con filtri di intent che specificano
l'azione ACTION_MAIN
e la categoria CATEGORY_LAUNCHER
.
Una corrispondenza è valida solo se le azioni e le categorie nell'intent corrispondono al filtro, come descritto nella documentazione della classe IntentFilter
.
La tua applicazione può utilizzare la corrispondenza degli intent in modo simile a quanto fa l'app Home.
PackageManager
ha un insieme di metodi query...()
che restituiscono tutti i componenti che possono accettare un determinato intento e
una serie simile di metodi resolve...()
che determinano il componente migliore per rispondere a un intento. Ad esempio:
queryIntentActivities()
restituisce un elenco di tutte le attività che possono essere eseguite
l'intent passato come argomento e queryIntentServices()
restituisce un elenco simile di servizi.
Nessuno dei due metodi attiva i componenti; elencano solo quelli che
può rispondere. Esiste un metodo simile,queryBroadcastReceivers()
, per i broadcast receiver.