Le notifiche forniscono informazioni brevi e tempestive sugli eventi nella tua app mentre non è in uso. Questo documento mostra come creare una notifica con varie funzionalità. Per un'introduzione alla modalità di visualizzazione delle notifiche su Android, consulta la panoramica delle notifiche. Per un codice campione che utilizza le notifiche, consulta l'esempio di SociaLite su GitHub.
Il codice in questa pagina utilizza le API NotificationCompat della libreria AndroidX. Queste API ti consentono di aggiungere funzionalità disponibili solo nelle versioni più recenti di Android, garantendo al contempo la compatibilità con Android 9 (livello API 28).
Tuttavia, alcune funzionalità, come l'azione di risposta in linea, non funzionano nelle versioni precedenti.
Crea una notifica di base
Una notifica nella sua forma più semplice e compatta, nota anche come forma compressa, mostra un'icona, un titolo e una piccola quantità di contenuti di testo. Questa sezione mostra come creare una notifica che l'utente può toccare per avviare un'attività nella tua app.
Figura 1. Una notifica con un'icona, un titolo e del testo.
Per maggiori dettagli su ogni parte di una notifica, consulta l'articolo sull'anatomia delle notifiche.
Dichiara l'autorizzazione di runtime
Android 13 (livello API 33) e versioni successive supportano un'autorizzazione di runtime per la pubblicazione di notifiche non esenti (incluse quelle dei servizi in primo piano, FGS) da un'app.
L'autorizzazione che devi dichiarare nel file manifest dell'app viene visualizzata nello snippet di codice seguente:
<manifest ...> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <application ...> ... </application> </manifest>
Per maggiori dettagli sulle autorizzazioni di runtime, consulta Autorizzazione di runtime per le notifiche.
Imposta i contenuti delle notifiche
Per iniziare, imposta i contenuti e il canale della notifica utilizzando un oggetto NotificationCompat.Builder. L'esempio seguente mostra come creare una notifica con:
Un'icona piccola, impostata da
setSmallIcon(). Questo è l'unico contenuto visibile all'utente obbligatorio.Un titolo, impostato da
setContentTitle().Il corpo del testo, impostato da
setContentText().La priorità della notifica, impostata da
setPriority(). La priorità determina l'invasività della notifica su Android 7.1 e versioni precedenti. Per Android 8.0 e versioni successive, imposta invece l'importanza del canale come mostrato nella sezione successiva.
val textTitle = "Title" val textContent = "Content" val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle(textTitle) .setContentText(textContent) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
Il costruttore NotificationCompat.Builder richiede di fornire un ID canale. Questo è necessario per la compatibilità con Android 8.0 (livello API 26) e versioni successive, ma viene ignorato dalle versioni precedenti.
Per impostazione predefinita, i contenuti di testo della notifica vengono troncati per adattarsi a una riga. Puoi mostrare informazioni aggiuntive creando una notifica espandibile.
Figura 2. Una notifica espandibile nelle sue forme compressa ed espansa.
Se vuoi che la notifica sia più lunga, puoi attivare una notifica espandibile aggiungendo un modello di stile con setStyle(). Ad esempio, il codice seguente crea un'area di testo più grande:
val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Much longer text that cannot fit one line...") .setStyle(NotificationCompat.BigTextStyle() .bigText("Much longer text that cannot fit one line...")) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
Per ulteriori informazioni su altri stili di notifica di grandi dimensioni, tra cui come aggiungere un'immagine e i controlli di riproduzione dei contenuti multimediali, consulta Crea una notifica espandibile.
Crea un canale e imposta l'importanza
Prima di poter inviare la notifica su Android 8.0 e versioni successive, registra il canale di notifica della tua app nel sistema passando un'istanza di NotificationChannel a createNotificationChannel(). Il seguente codice è bloccato da una condizione nella versione SDK_INT:
fun createNotificationChannel(context: Context) { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is not in the Support Library. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val name = context.getString(R.string.channel_name) val descriptionText = context.getString(R.string.channel_description) val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel(CHANNEL_ID, name, importance).apply { description = descriptionText } // Register the channel with the system. val notificationManager: NotificationManager = context.getSystemService(NotificationManager::class.java) as NotificationManager notificationManager.createNotificationChannel(channel) } }
Poiché devi creare il canale di notifica prima di pubblicare notifiche su Android 8.0 e versioni successive, esegui questo codice all'avvio dell'app. È sicuro chiamarlo ripetutamente perché la creazione di un canale esistente non ha alcun effetto.
Il costruttore NotificationChannel richiede un livello di importanza utilizzando una costante NotificationManager. Questo determina come interrompere l'utente. Per supportare Android 7.1 e versioni precedenti, imposta anche la priorità con setPriority(), come mostrato nell'esempio precedente.
Anche se devi impostare l'importanza o la priorità, il sistema non garantisce il comportamento dell'avviso. Il sistema potrebbe regolarlo in base ad altri fattori e l'utente può sempre personalizzare il livello di importanza del canale.
Per saperne di più sul significato dei diversi livelli, leggi l'articolo sui livelli di importanza delle notifiche.
Imposta l'azione di tocco della notifica
Ogni notifica deve rispondere a un tocco, di solito per aprire un'attività nella tua app che corrisponde alla notifica. Per farlo, specifica un intent dei contenuti definito con un oggetto PendingIntent e passalo a setContentIntent().
Lo snippet seguente mostra come creare un intent di base per aprire un'attività quando l'utente tocca la notifica:
// Create an explicit intent for an Activity in your app. val intent = Intent(context, AlertDetails::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that fires when the user taps the notification. .setContentIntent(pendingIntent) .setAutoCancel(true)
Questo codice chiama setAutoCancel(), che rimuove automaticamente la notifica quando l'utente la tocca.
I flag di intent nell'esempio precedente preservano l'esperienza di navigazione prevista per l'utente dopo che quest'ultimo apre l'app utilizzando la notifica. Potresti volerlo utilizzare a seconda del tipo di attività che stai avviando, che può essere uno dei seguenti:
Un'attività che esiste esclusivamente per le risposte alla notifica. Non c'è motivo per cui l'utente debba accedere a questa attività durante il normale utilizzo dell'app, quindi l'attività avvia una nuova attività anziché essere aggiunta all'attività e al back stack esistenti dell'app. Questo è il tipo di intent creato nell'esempio precedente.
Un'attività che esiste nel normale flusso dell'app. In questo caso, l'avvio dell'attività crea un back stack in modo che le aspettative dell'utente per i pulsanti Indietro e Su vengano preservate.
Mostra la notifica
Per far apparire la notifica, chiama
NotificationManagerCompat.notify(), passando un ID univoco per la
notifica e il risultato di NotificationCompat.Builder.build(). Questo è mostrato nell'esempio seguente:
with(NotificationManagerCompat.from(context)) { if (ActivityCompat.checkSelfPermission( context, Manifest.permission.POST_NOTIFICATIONS ) != PackageManager.PERMISSION_GRANTED ) { // TODO: Consider calling ActivityCompat#requestPermissions here // to request the missing permissions, and then overriding // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, // grantResults: IntArray) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return@with } // notificationId is a unique int for each notification that you must define. notify(notificationId, builder.build())
Salva l'ID notifica che passi a NotificationManagerCompat.notify(), perché ti servirà quando vorrai aggiornare o rimuovere la notifica.
Inoltre, per testare le notifiche di base sui dispositivi con Android 13 e versioni successive, attiva le notifiche manualmente o crea una finestra di dialogo per richiederle.
Aggiungi pulsanti di azione
Una notifica può offrire fino a tre pulsanti di azione che consentono all'utente di rispondere rapidamente, ad esempio per posticipare un promemoria o rispondere a un messaggio. Tuttavia, questi pulsanti di azione non devono duplicare l'azione eseguita quando l'utente tocca la notifica.
Figura 3. Una notifica con un pulsante di azione.
Per aggiungere un pulsante di azione, passa un PendingIntent al metodo addAction(). È come impostare l'azione di tocco predefinita della notifica, ma
anziché avviare un'attività, puoi eseguire altre operazioni, ad esempio avviare un
BroadcastReceiver che esegue un job in background in modo che l'azione non interrompa l'app già aperta.
Ad esempio, il seguente codice mostra come inviare una trasmissione a un ricevitore specifico:
val ACTION_SNOOZE = "snooze" val snoozeIntent = Intent(context, MyBroadcastReceiver::class.java).apply { action = ACTION_SNOOZE putExtra(EXTRA_NOTIFICATION_ID, 0) } val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(context, 0, snoozeIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .addAction(R.drawable.snooze, context.getString(R.string.snooze), snoozePendingIntent)
Per saperne di più sulla creazione di un BroadcastReceiver per eseguire attività in background, consulta la panoramica delle trasmissioni.
Se invece stai cercando di creare una notifica con pulsanti di riproduzione multimediale, ad esempio per mettere in pausa e saltare le tracce, scopri come creare una notifica con controlli multimediali.
Aggiungi un'azione di risposta diretta
L'azione di risposta diretta, introdotta in Android 7.0 (livello API 24), consente agli utenti di inserire testo direttamente nella notifica. Il testo viene quindi inviato alla tua app senza aprire un'attività. Ad esempio, puoi utilizzare un'azione di risposta diretta per consentire agli utenti di rispondere ai messaggi o aggiornare gli elenchi di attività direttamente dalla notifica.
Figura 4. Toccando il pulsante "Rispondi" si apre l'input di testo.
L'azione di risposta diretta viene visualizzata come un pulsante aggiuntivo nella notifica che apre un campo di immissione di testo. Quando l'utente termina di digitare, il sistema allega la risposta di testo all'intent specificato per l'azione di notifica e invia l'intent alla tua app.
Aggiungi il pulsante di risposta
Per creare un'azione di notifica che supporti la risposta diretta, segui questi passaggi:
Crea un'istanza di RemoteInput.Builder che puoi aggiungere all'azione di notifica. Il costruttore di questa classe accetta una stringa che il sistema utilizza come chiave per l'input di testo. In un secondo momento, l'app utilizza questa chiave per recuperare il testo dell'input.
// Key for the string that's delivered in the action's intent. val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run { setLabel(replyLabel) build() }
Crea un PendingIntent per l'azione di risposta.
// Build a PendingIntent for the reply action to trigger. val replyPendingIntent: PendingIntent = PendingIntent.getBroadcast(context, conversationId, getMessageReplyIntent(conversationId), PendingIntent.FLAG_MUTABLE)
Collega l'oggetto RemoteInput a un'azione utilizzando
addRemoteInput().
// Create the reply action and add the remote input. val action: NotificationCompat.Action = NotificationCompat.Action.Builder(R.drawable.reply, context.getString(R.string.reply_label), replyPendingIntent) .addRemoteInput(remoteInput) .build()
Applica l'azione a una notifica e invia la notifica.
// Build the notification and add the action.
val newMessageNotification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(context.getString(R.string.title))
.setContentText(context.getString(R.string.content))
.addAction(action)
.build()
// Issue the notification.
NotificationManagerCompat.from(context).notify(notificationId, newMessageNotification)
Il sistema chiede all'utente di inserire una risposta quando attiva l'azione di notifica, come mostrato nella Figura 4.
Recupera l'input dell'utente dalla risposta
Per ricevere l'input dell'utente dalla UI di risposta della notifica, chiama RemoteInput.getResultsFromIntent(), passando l'Intent ricevuto dal tuo BroadcastReceiver:
private fun getMessageText(intent: Intent): CharSequence? { return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY) }
Dopo aver elaborato il testo, aggiorna la notifica chiamando
NotificationManagerCompat.notify() con lo stesso ID e tag, se utilizzato. Questo è necessario per nascondere l'interfaccia utente di risposta diretta e confermare all'utente che la sua risposta è stata ricevuta ed elaborata correttamente.
// Build a new notification, which informs the user that the system // handled their interaction with the previous notification. val repliedNotification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.message) .setContentText(context.getString(R.string.replied)) .build() // Issue the new notification. NotificationManagerCompat.from(context).notify(notificationId, repliedNotification)
Recupera altri dati
La gestione di altri tipi di dati funziona in modo simile con RemoteInput. L'esempio seguente utilizza l'immagine come input.
val replyLabel: String = context.resources.getString(R.string.reply_label) val remoteInput: RemoteInput = RemoteInput.Builder(KEY_REPLY).run { setLabel(replyLabel) // Allow for image data types in the input. // This method can be used again to allow for other data types. setAllowDataType("image/*", true) build() }
Chiama RemoteInput#getDataResultsFromIntent ed estrai i dati corrispondenti.
class ReplyReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val dataResults = RemoteInput.getDataResultsFromIntent(intent, KEY_REPLY) val imageUri: Uri? = dataResults?.get("image/*") as? Uri if (imageUri != null) { // Extract the image context.contentResolver.openInputStream(imageUri)?.use { inputStream -> val bitmap = BitmapFactory.decodeStream(inputStream) // Display the image // ... } } } companion object { const val KEY_REPLY = "key_reply" const val KEY_TEXT_REPLY = "key_text_reply" } }
Quando utilizzi questa nuova notifica, usa il contesto passato al metodo onReceive() del ricevitore.
Aggiungi la risposta in fondo alla notifica chiamando setRemoteInputHistory(). Tuttavia, se stai creando un'app di messaggistica, crea una notifica di tipo messaggistica e aggiungi il nuovo messaggio alla conversazione.
Per ulteriori consigli sulle notifiche delle app di messaggistica, consulta la sezione sulle best practice per le app di messaggistica.
Mostra un messaggio urgente
L'app potrebbe dover mostrare un messaggio urgente e sensibile al fattore tempo, ad esempio una chiamata in arrivo o una sveglia che suona. In queste situazioni, puoi associare un intent a schermo intero alla notifica.
Quando la notifica viene richiamata, gli utenti vedono una delle seguenti opzioni, a seconda dello stato di blocco del dispositivo:
- Se il dispositivo dell'utente è bloccato, viene visualizzata un'attività a schermo intero che copre la schermata di blocco.
- Se il dispositivo dell'utente è sbloccato, la notifica viene visualizzata in un formato espanso che include opzioni per la gestione o la chiusura della notifica.
Il seguente snippet di codice mostra come associare la notifica a un intent a schermo intero:
val fullScreenIntent = Intent(context, ImportantActivity::class.java) val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, PendingIntent.FLAG_IMMUTABLE) val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setFullScreenIntent(fullScreenPendingIntent, true)
Imposta la visibilità della schermata di blocco
Per controllare il livello di dettaglio visibile nella notifica dalla schermata di blocco, chiama setVisibility() e specifica uno dei seguenti valori:
VISIBILITY_PUBLIC: i contenuti completi della notifica vengono visualizzati nella schermata di blocco.VISIBILITY_SECRET: nessuna parte della notifica viene visualizzata nella schermata di blocco.VISIBILITY_PRIVATE: nella schermata di blocco vengono visualizzate solo le informazioni di base, come l'icona della notifica e il titolo dei contenuti. I contenuti completi della notifica non vengono visualizzati.
Quando imposti VISIBILITY_PRIVATE, puoi anche fornire una versione alternativa dei contenuti della notifica che nasconde determinati dettagli. Ad esempio, un'app per SMS potrebbe mostrare una notifica con il testo "Hai 3 nuovi messaggi", ma nascondere i contenuti e i mittenti dei messaggi. Per fornire questa notifica alternativa, innanzitutto creala con NotificationCompat.Builder come di consueto. Poi, collega la notifica alternativa
alla notifica normale con setPublicVersion().
Tieni presente che l'utente ha sempre il controllo finale sulla visibilità delle notifiche nella schermata di blocco e può controllarle in base ai canali di notifica della tua app.
Aggiorna una notifica
Per aggiornare una notifica dopo averla inviata, chiama di nuovo NotificationManagerCompat.notify(), passando lo stesso ID utilizzato in precedenza. Se la notifica precedente viene ignorata, viene creata una nuova notifica.
Facoltativamente, puoi chiamare setOnlyAlertOnce() in modo che la notifica interrompa l'utente, con suoni, vibrazioni o segnali visivi, solo la prima volta che viene visualizzata e non per gli aggiornamenti successivi.
Rimuovi una notifica
Le notifiche rimangono visibili finché non si verifica una delle seguenti condizioni:
- L'utente chiude la notifica.
- L'utente tocca la notifica, se chiami
setAutoCancel()quando crei la notifica. - Chiami
cancel()per un ID notifica specifico. Questo metodo elimina anche le notifiche in corso. - Chiami
cancelAll(), che rimuove tutte le notifiche che hai emesso in precedenza. - Trascorre la durata specificata, se hai impostato un timeout durante la creazione della notifica utilizzando
setTimeoutAfter(). Se necessario, puoi annullare una notifica prima che trascorra la durata del timeout specificata.
Best practice per le app di messaggistica
Quando crei notifiche per le tue app di messaggistica e chat, tieni conto delle best practice elencate di seguito.
Utilizza MessagingStyle
A partire da Android 7.0 (livello API 24), Android fornisce un modello di stile di notifica specifico per i contenuti dei messaggi. Utilizzando la classe NotificationCompat.MessagingStyle, puoi modificare diverse etichette visualizzate nella notifica, tra cui il titolo della conversazione, i messaggi aggiuntivi e la visualizzazione dei contenuti della notifica.
Il seguente snippet di codice mostra come personalizzare lo stile di una notifica utilizzando la classe MessagingStyle.
val message1 = NotificationCompat.MessagingStyle.Message( messages[0].text, messages[0].time, messages[0].sender ) val message2 = NotificationCompat.MessagingStyle.Message( messages[1].text, messages[1].time, messages[1].sender ) notification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_logo) .setStyle( NotificationCompat.MessagingStyle(Person.Builder().setName("Me").build()) .addMessage(message1) .addMessage(message2) ) .build()
A partire da Android 9.0 (livello API 28), è inoltre necessario utilizzare la classe Person per ottenere un rendering ottimale della notifica e dei relativi avatar.
Quando utilizzi NotificationCompat.MessagingStyle, procedi nel seguente modo:
- Chiama
MessagingStyle.setConversationTitle()per impostare un titolo per le chat di gruppo con più di due persone. Un buon titolo per la conversazione potrebbe essere il nome della chat di gruppo o, se non ha un nome, un elenco dei partecipanti alla conversazione. In caso contrario, il messaggio potrebbe essere scambiato per una conversazione 1:1 con il mittente del messaggio più recente della conversazione. - Utilizza il metodo
MessagingStyle.setData()per includere messaggi multimediali, come le immagini. Sono supportati i tipi MIME del pattern image/*.
Utilizza la risposta diretta
La risposta diretta consente a un utente di rispondere direttamente a un messaggio.
- Dopo che un utente ha risposto con l'azione di risposta in linea, utilizza
MessagingStyle.addMessage()per aggiornare la notificaMessagingStylee non ritirare o annullare la notifica. Se non annulli la notifica, l'utente può inviare più risposte dalla notifica. - Per rendere l'azione di risposta in linea compatibile con Wear OS, chiama
Action.WearableExtender.setHintDisplayInlineAction(true). - Utilizza il metodo
addHistoricMessage()per fornire il contesto a una conversazione con risposta diretta aggiungendo messaggi storici alla notifica.
Attiva Risposta rapida
- Per attivare la Risposta rapida, chiama
setAllowGeneratedResponses(true)nell'azione di risposta. In questo modo, le risposte rapide sono disponibili per gli utenti quando la notifica viene trasferita a un dispositivo Wear OS. Le risposte rapide vengono generate da un modello di machine learning interamente sullo smartwatch utilizzando il contesto fornito dalla notifica diNotificationCompat.MessagingStylee non vengono caricati dati su internet per generare le risposte.
Aggiungi i metadati della notifica
- Assegna i metadati delle notifiche per indicare al sistema come gestire le notifiche dell'app quando il dispositivo è in modalità Non disturbare. Ad esempio, utilizza il metodo
addPerson()osetCategory(Notification.CATEGORY_MESSAGE)per ignorare la modalità Non disturbare.