Indirizzare l'utente a un'altra app

Una delle funzionalità più importanti di Android è la capacità di un'app di indirizzare l'utente a un'altra app in base a un'"azione" che vorrebbe eseguire. Ad esempio, se la tua app ha l'indirizzo di un'attività che vuoi mostrare su una mappa, non è necessario creare un'attività nella tua app che mostri una mappa. Puoi invece creare una richiesta per visualizzare l'indirizzo utilizzando un Intent. Il sistema Android avvia quindi un'app in grado di mostrare l'indirizzo sulla mappa.

Come spiegato nella prima classe, Creazione della prima app, devi utilizzare gli intent per spostarti tra le attività nella tua app. In genere occorre un intent esplicito, che definisce il nome esatto della classe del componente che vuoi avviare. Tuttavia, se vuoi che un'app separata esegua un'azione, come "visualizzare una mappa", devi utilizzare un intent implicito.

Questa lezione spiega come creare un intent implicito per una determinata azione e come utilizzarlo per avviare un'attività che esegue l'azione in un'altra app. Guarda anche il video incorporato qui per capire perché è importante includere controlli di runtime per i tuoi intent impliciti.

Creazione di un intent implicito

Gli intent impliciti non dichiarano il nome della classe del componente da avviare, bensì un'azione da eseguire. L'azione specifica l'azione che vuoi fare, ad esempio view, edit, send o ricevi qualcosa.

Associare le azioni intent ai dati

Gli intent spesso includono anche i dati associati all'azione, ad esempio l'indirizzo che vuoi visualizzare o il messaggio email che vuoi inviare. A seconda dell'intent che vuoi creare, i dati potrebbero essere Uri, uno di vari altri tipi di dati oppure l'intent potrebbe non aver bisogno di dati.

Se i tuoi dati sono Uri, puoi utilizzare un semplice costruttore Intent() per definire l'azione e i dati.

Ad esempio, ecco come creare un intent per avviare una telefonata utilizzando i dati Uri per specificare il numero di telefono:

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

Quando l'app richiama questo intent chiamando il numero startActivity(), l'app Telefono avvia una chiamata al numero di telefono specificato.

Ecco un paio di altri intent con la relativa azione e Uri coppia di dati:

Visualizza una mappa

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

Visualizzare una pagina web

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

Aggiungere extra a un intent

Altri tipi di intent impliciti richiedono dati "aggiuntivi" che forniscono tipi di dati diversi, come una stringa. Puoi aggiungere uno o più dati extra utilizzando i vari metodi di putExtra().

Per impostazione predefinita, il sistema determina il tipo MIME appropriato richiesto da un intent in base ai dati Uri inclusi. Se non includi un Uri nell'intent, in genere è consigliabile utilizzare setType() per specificare il tipo di dati associati all'intent. L'impostazione del tipo MIME consente di specificare ulteriormente i tipi di attività che devono generare l'intent.

Di seguito sono riportati alcuni intent che aggiungono ulteriori dati per specificare l'azione desiderata:

Inviare un'email con un allegato

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

Creare un evento nel calendario

Nota: questo intent per un evento di calendario è supportato solo con il livello API 14 e successivi.

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

Nota: è importante definire Intent il più possibile specifico. Ad esempio, se vuoi visualizzare un'immagine utilizzando l'intent ACTION_VIEW, devi specificare un tipo MIME image/*. In questo modo, l'intent non attiva le app che possono "visualizzare" altri tipi di dati (come un'app di mappe).

Inizia un'attività con l'intent

Dopo aver creato il tuo Intent e impostato le informazioni aggiuntive, chiama startActivity() per inviarlo al sistema:

Kotlin

startActivity(intent)

Java

startActivity(intent);

Gestire la situazione in cui nessuna app può ricevere un intent

Sebbene molti intent vengano gestiti correttamente da un'altra app installata sul dispositivo, ad esempio un'app per telefono, email o calendario, l'app deve prepararsi a situazioni in cui nessuna attività è in grado di gestire l'intent dell'app. Ogni volta che richiami un intent, preparati a rilevare un'istanza ActivityNotFoundException, il che si verifica se non ci sono altre attività in grado di gestire l'intent dell'app:

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Dopo aver individuato l'eccezione, decidi cosa deve fare l'app. Il passaggio successivo dipende dalle caratteristiche specifiche dell'intent che hai provato a richiamare. Ad esempio, se conosci un'app specifica in grado di gestire l'intent, fornisci un link che consenta all'utente di scaricare l'app. Scopri di più su come eseguire il collegamento al tuo prodotto su Google Play.

Finestra di dialogo di disambiguazione

Se il sistema identifica più attività in grado di gestire l'intent, mostra una finestra di dialogo (talvolta definita "finestra di dialogo di disambiguazione") in cui l'utente può selezionare l'app da utilizzare, come mostrato nella Figura 1. Se esiste una sola attività che gestisce l'intent, il sistema la avvia immediatamente.

Nella parte inferiore dello schermo viene visualizzato un riquadro. In questo riquadro sono elencate le diverse app che potrebbero gestire l'intent.

Figura 1. Esempio della finestra di dialogo di selezione che viene visualizzata quando più app sono in grado di gestire un intent.

Esempio completo

Ecco un esempio completo che mostra come creare un intent per visualizzare una mappa, verificare che esista un'app per gestire l'intent, quindi avviarlo:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Mostra un selettore di app

Figura 2. Una finestra di dialogo di selezione.

Tieni presente che quando avvii un'attività passando il tuo Intent a startActivity() e più di un'app risponde all'intent, l'utente può selezionare l'app da utilizzare per impostazione predefinita (selezionando una casella di controllo nella parte inferiore della finestra di dialogo; vedi la figura 1). Ciò è utile quando l'utente compie un'azione per la quale generalmente l'utente vuole usare sempre la stessa app, ad esempio quando apre una pagina web (gli utenti probabilmente usano un solo browser web) o quando scatta una foto (gli utenti probabilmente preferiscono una sola fotocamera).

Tuttavia, se l'azione da eseguire potrebbe essere gestita da più app e l'utente potrebbe preferire un'app diversa ogni volta, ad esempio un'azione di "condivisione", per la quale gli utenti potrebbero avere diverse app con cui potrebbero condividere un elemento, dovresti mostrare esplicitamente una finestra di dialogo del selettore, come mostrato nella Figura 2. La finestra di dialogo del selettore costringe l'utente a selezionare ogni volta l'app da utilizzare per l'azione (l'utente non può selezionare un'app predefinita per l'azione).

Per visualizzare il selettore, crea un Intent con createChooser() e passalo a startActivity(). Ecco alcuni esempi:

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Viene visualizzata una finestra di dialogo con un elenco di app che rispondono all'intent trasmesso al metodo createChooser(). Il parametro title può essere fornito se l'azione non è ACTION_SEND o ACTION_SEND_MULTIPLE