Le app che supportano la messaggistica possono estendere le notifiche di messaggistica per consentire
ad Android Auto di utilizzarle quando è in esecuzione. Queste notifiche vengono visualizzate
da Android Auto e consentono agli utenti di leggere e rispondere ai messaggi in un'interfaccia coerente
e con poche distrazioni. Inoltre, quando utilizzi l'API MessagingStyle, ricevi notifiche dei messaggi ottimizzate per tutti i dispositivi Android, incluso Android Auto. Le ottimizzazioni includono un'interfaccia utente specializzata per le notifiche dei messaggi, animazioni migliorate e supporto per le immagini in linea.
Questa guida mostra come estendere un'app che mostra messaggi all'utente e riceve le risposte dell'utente, ad esempio un'app di chat, per trasferire la visualizzazione dei messaggi e la ricezione delle risposte ad Android Auto. Tramite questa integrazione, gli utenti possono visualizzare la cronologia dei messaggi solo dalle notifiche ricevute durante la sessione Android Auto attiva. Per visualizzare i messaggi precedenti all'inizio della sessione Android Auto attiva, puoi creare un'esperienza di messaggistica basata su modelli.
Per indicazioni di progettazione correlate, vedi App di comunicazione nell'hub Design per le auto.
Inizia
Per fornire un servizio di messaggistica per Android Auto, la tua app deve dichiarare il proprio supporto per Android Auto nel manifest e deve essere in grado di svolgere le seguenti operazioni:
- Dichiarare il supporto di Android Auto
- Crea e invia oggetti
NotificationCompat.MessagingStyleche contengono oggettiActiondi risposta e contrassegna come letto. - Gestisci le risposte e contrassegna una conversazione come letta con un
Service.
Concetti e oggetti
Prima di iniziare a progettare la tua app, è utile capire come Android Auto gestisce i messaggi.
Un singolo blocco di comunicazione è chiamato messaggio ed è rappresentato dalla classe MessagingStyle.Message. Un messaggio contiene un mittente, i
contenuti e l'ora di invio.
La comunicazione tra gli utenti è chiamata conversazione ed è rappresentata da un oggetto
MessagingStyle. Una conversazione, o MessagingStyle, contiene un titolo,
i messaggi e indica se la conversazione è tra un gruppo di utenti.
Per informare gli utenti degli aggiornamenti di una conversazione, ad esempio un nuovo messaggio, le app pubblicano un
Notification nel sistema Android. Questo Notification utilizza l'oggetto
MessagingStyle per visualizzare l'interfaccia utente specifica per la messaggistica nella
barra delle notifiche. La piattaforma Android trasmette anche questo Notification ad Android Auto e
l'MessagingStyle viene estratto e utilizzato per pubblicare una notifica sul display
dell'auto.
Android Auto richiede inoltre che le app aggiungano oggetti Action a un Notification
per consentire all'utente di rispondere a un messaggio o contrassegnarlo come letto direttamente dal display
dell'auto.
In sintesi, una singola conversazione è rappresentata da un oggetto Notification
con uno stile definito da un oggetto MessagingStyle. MessagingStyle contiene tutti i
messaggi all'interno della conversazione in uno o più oggetti MessagingStyle.Message. Inoltre, per essere conforme ad Android Auto, un'app deve allegare oggetti di risposta e
segna come letto Action all'Notification.
Flusso di messaggistica
Questa sezione descrive un flusso di messaggistica tipico tra la tua app e Android Auto.
- La tua app riceve un messaggio.
- La tua app genera una notifica
MessagingStylecon oggetti di risposta e segna come lettoAction. - Android Auto riceve l'evento "nuova notifica" dal sistema Android
e trova
MessagingStyle, rispostaActione contrassegna come lettoAction. - Android Auto genera e mostra una notifica nell'auto.
- Se l'utente tocca la notifica sul display dell'auto, Android Auto
attiva la funzionalità Segna come letto
Action.- In background, la tua app deve gestire questo evento di contrassegno come letto.
- Se l'utente risponde alla notifica tramite comandi vocali, Android Auto inserisce una
trascrizione della risposta dell'utente nella risposta
Actione poi la attiva.- In background, l'app deve gestire questo evento di risposta.
Ipotesi preliminari
Questa pagina non ti guida nella creazione di un'intera app di messaggistica. Il seguente esempio di codice include alcuni elementi necessari alla tua app prima di iniziare a supportare la messaggistica con Android Auto:
data class YourAppConversation(
val id: Int,
val title: String,
val recipients: MutableList<YourAppUser>,
val icon: Bitmap) {
companion object {
/** Fetches [YourAppConversation] by its [id]. */
fun getById(id: Int): YourAppConversation = // ...
}
/** Replies to this conversation with the given [message]. */
fun reply(message: String) {}
/** Marks this conversation as read. */
fun markAsRead() {}
/** Retrieves all unread messages from this conversation. */
fun getUnreadMessages(): List<YourAppMessage> { return /* ... */ }
}
data class YourAppUser(val id: Int, val name: String, val icon: Uri)
data class YourAppMessage(
val id: Int,
val sender: YourAppUser,
val body: String,
val timeReceived: Long)
Dichiara il supporto di Android Auto
Quando Android Auto riceve una notifica da un'app di messaggistica, verifica che l'app abbia dichiarato il supporto di Android Auto. Per attivarlo, includi la seguente voce nel manifest dell'app:
<application>
...
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
Questa voce del manifest fa riferimento a un altro file XML, automotive_app_desc.xml, che
devi creare nella directory res/xml del modulo dell'app. In
automotive_app_desc.xml, dichiara le funzionalità di Android Auto supportate dalla tua app. Per dichiarare il supporto delle notifiche, includi quanto segue:
<automotiveApp>
<uses name="notification" />
</automotiveApp>
Se la tua app può essere impostata come gestore SMS predefinito, assicurati di includere il seguente elemento <uses>. In caso contrario, Android Auto utilizza il gestore predefinito
integrato per gestire i messaggi SMS/MMS in arrivo quando la tua app è impostata come gestore
SMS predefinito, il che può portare a notifiche duplicate.
<automotiveApp>
...
<uses name="sms" />
</automotiveApp>
Importa la libreria principale AndroidX
La creazione di notifiche da utilizzare con Android Auto richiede la libreria principale AndroidX. Importa la libreria nel tuo progetto come segue:
- Nel file
build.gradledi primo livello, includi una dipendenza dal repository Maven di Google, come mostrato nell'esempio seguente:
Groovy
allprojects { repositories { google() } }
Kotlin
allprojects { repositories { google() } }
- Nel file
build.gradledel modulo dell'app, includi la dipendenza della libreria AndroidX Core, come mostrato nell'esempio seguente:
Groovy
dependencies { // If your app is written in Java implementation 'androidx.core:core:1.17.0' // If your app is written in Kotlin implementation 'androidx.core:core-ktx:1.17.0' }
Kotlin
dependencies { // If your app is written in Java implementation("androidx.core:core:1.17.0") // If your app is written in Kotlin implementation("androidx.core:core-ktx:1.17.0") }
Gestire le azioni utente
La tua app di messaggistica deve gestire l'aggiornamento di una conversazione tramite un
Action. Per Android Auto, la tua app deve gestire due tipi di oggetti Action: risposta e contrassegna come letto. Ti consigliamo di gestirli utilizzando un
IntentService, che offre la flessibilità di gestire chiamate potenzialmente
costose in background, liberando il thread principale dell'app.
Definisci le azioni intent
Le azioni Intent sono stringhe di base a tua scelta che identificano lo scopo dell'Intent. Poiché un singolo servizio può gestire più tipi di intent, è più facile definire più stringhe di azioni anziché definire più componenti IntentService.
L'app di messaggistica di esempio di questa guida ha i due tipi di azioni richiesti: risposta e contrassegna come letto, come mostrato nel seguente codice campione:
private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"
Creare il servizio
Per creare un servizio che gestisca questi oggetti Action, devi disporre dell'ID conversazione, ovvero una struttura di dati arbitraria definita dalla tua app che identifica la conversazione. Hai anche bisogno di una chiave di input remoto, di cui
parleremo in dettaglio più avanti in questa sezione. Il seguente esempio di codice crea un servizio per gestire le azioni richieste:
private const val EXTRA_CONVERSATION_ID_KEY = "conversation_id"
private const val REMOTE_INPUT_RESULT_KEY = "reply_input"
/**
* An [IntentService] that handles reply and mark-as-read actions for
* [YourAppConversation]s.
*/
class MessagingService : IntentService("MessagingService") {
override fun onHandleIntent(intent: Intent?) {
// Fetches internal data.
val conversationId = intent!!.getIntExtra(EXTRA_CONVERSATION_ID_KEY, -1)
// Searches the database for that conversation.
val conversation = YourAppConversation.getById(conversationId)
// Handles the action that was requested in the intent. The TODOs
// are addressed in a later section.
when (intent.action) {
ACTION_REPLY -> TODO()
ACTION_MARK_AS_READ -> TODO()
}
}
}
Per associare questo servizio alla tua app, devi anche registrarlo nel manifest dell'app, come mostrato nell'esempio seguente:
<application>
<service android:name="com.example.MessagingService" />
...
</application>
Generare e gestire intent
Altre app, tra cui Android Auto, non possono ottenere Intent che attiva
MessagingService perché gli intent vengono passati ad altre app tramite un
PendingIntent. A causa di questa limitazione, crea un oggetto RemoteInput
per consentire ad altre app di fornire il testo di risposta alla tua app, come mostrato
nell'esempio seguente:
/**
* Creates a [RemoteInput] that lets remote apps provide a response string
* to the underlying [Intent] within a [PendingIntent].
*/
fun createReplyRemoteInput(context: Context): RemoteInput {
// RemoteInput.Builder accepts a single parameter: the key to use to store
// the response in.
return RemoteInput.Builder(REMOTE_INPUT_RESULT_KEY).build()
// Note that the RemoteInput has no knowledge of the conversation. This is
// because the data for the RemoteInput is bound to the reply Intent using
// static methods in the RemoteInput class.
}
/** Creates an [Intent] that handles replying to the given [appConversation]. */
fun createReplyIntent(
context: Context, appConversation: YourAppConversation): Intent {
// Creates the intent backed by the MessagingService.
val intent = Intent(context, MessagingService::class.java)
// Lets the MessagingService know this is a reply request.
intent.action = ACTION_REPLY
// Provides the ID of the conversation that the reply applies to.
intent.putExtra(EXTRA_CONVERSATION_ID_KEY, appConversation.id)
return intent
}
Nella clausola switch ACTION_REPLY all'interno di MessagingService, estrai le informazioni che vanno nella risposta Intent, come mostrato nell'esempio seguente:
ACTION_REPLY -> {
// Extracts reply response from the intent using the same key that the
// RemoteInput uses.
val results: Bundle = RemoteInput.getResultsFromIntent(intent)
val message = results.getString(REMOTE_INPUT_RESULT_KEY)
// This conversation object comes from the MessagingService.
conversation.reply(message)
}
Gestisci il segno di lettura Intent in modo simile. Tuttavia, non
richiede un RemoteInput, come mostrato nell'esempio seguente:
/** Creates an [Intent] that handles marking the [appConversation] as read. */
fun createMarkAsReadIntent(
context: Context, appConversation: YourAppConversation): Intent {
val intent = Intent(context, MessagingService::class.java)
intent.action = ACTION_MARK_AS_READ
intent.putExtra(EXTRA_CONVERSATION_ID_KEY, appConversation.id)
return intent
}
La clausola switch ACTION_MARK_AS_READ all'interno di MessagingService non richiede
ulteriore logica, come mostrato nell'esempio seguente:
// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()
Notificare i messaggi agli utenti
Una volta completata la gestione delle azioni di conversazione, il passaggio successivo è generare notifiche conformi ad Android Auto.
Creare azioni
Gli oggetti Action possono essere passati ad altre app utilizzando un Notification per attivare
metodi nell'app originale. In questo modo Android Auto può contrassegnare una conversazione come
letta o rispondere.
Per creare un Action, inizia con un Intent. L'esempio seguente mostra come creare una risposta Intent utilizzando il metodo createReplyIntent() della sezione precedente:
fun createReplyAction(
context: Context, appConversation: YourAppConversation): Action {
val replyIntent: Intent = createReplyIntent(context, appConversation)
// ...
Poi, racchiudi questo Intent in un PendingIntent, che lo prepara per l'utilizzo di app esterne. Un PendingIntent blocca l'accesso a tutto il Intent sottoposto a wrapping
esponendo solo un insieme selezionato di metodi che consentono all'app ricevente di attivare l'intent
Intent o ottenere il nome del pacchetto dell'app di origine. L'app esterna non può
accedere al Intent sottostante o ai dati al suo interno.
// ...
val replyPendingIntent = PendingIntent.getService(
context,
createReplyId(appConversation), // Method explained later.
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
// ...
Prima di configurare la risposta Action, tieni presente che Android Auto ha tre
requisiti per la risposta Action:
- L'azione semantica deve essere impostata su
Action.SEMANTIC_ACTION_REPLY. - L'
Actiondeve indicare che non mostrerà alcuna interfaccia utente quando viene attivato. - L'elemento
Actiondeve contenere un solo elementoRemoteInput.
Il seguente esempio di codice configura un Action di risposta che soddisfa i
requisiti elencati in precedenza:
// ...
val replyAction = Action.Builder(R.drawable.reply, "Reply", replyPendingIntent)
// Provides context to what firing the Action does.
.setSemanticAction(Action.SEMANTIC_ACTION_REPLY)
// The action doesn't show any UI, as required by Android Auto.
.setShowsUserInterface(false)
// Don't forget the reply RemoteInput. Android Auto will use this to
// make a system call that will add the response string into
// the reply intent so it can be extracted by the messaging app.
.addRemoteInput(createReplyRemoteInput(context))
.build()
return replyAction
}
La gestione dell'azione di contrassegna come letta è simile, tranne per il fatto che non è presente RemoteInput.
Pertanto, Android Auto ha due requisiti per la funzionalità Segna come letto Action:
- L'azione semantica è impostata su
Action.SEMANTIC_ACTION_MARK_AS_READ. - L'azione indica che non mostrerà alcuna interfaccia utente quando viene attivata.
Il seguente esempio di codice configura un Action contrassegnato come letto che soddisfa questi
requisiti:
fun createMarkAsReadAction(
context: Context, appConversation: YourAppConversation): Action {
val markAsReadIntent = createMarkAsReadIntent(context, appConversation)
val markAsReadPendingIntent = PendingIntent.getService(
context,
createMarkAsReadId(appConversation), // Method explained later.
markAsReadIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val markAsReadAction = Action.Builder(
R.drawable.mark_as_read, "Mark as Read", markAsReadPendingIntent)
.setSemanticAction(Action.SEMANTIC_ACTION_MARK_AS_READ)
.setShowsUserInterface(false)
.build()
return markAsReadAction
}
Quando generi gli intent in attesa, utilizzi due metodi: createReplyId() e createMarkAsReadId(). Questi metodi fungono da codici di richiesta per ogni
PendingIntent, che vengono utilizzati da Android per controllare gli intent in attesa esistenti.
I metodi create() devono restituire ID univoci per ogni conversazione, ma
le chiamate ripetute per la stessa conversazione devono restituire l'ID univoco già
generato.
Considera un esempio con due conversazioni, A e B: l'ID risposta della conversazione A è 100 e il suo ID contrassegna come letta è 101. L'ID risposta della conversazione B è 102 e
il suo ID contrassegna come letto è 103. Se la conversazione A viene aggiornata, gli ID di risposta e contrassegna come letta rimangono 100 e 101. Per ulteriori informazioni, vedi
PendingIntent.FLAG_UPDATE_CURRENT.
Crea un MessagingStyle
MessagingStyle è l'operatore delle informazioni di messaggistica ed è ciò che Android
Auto utilizza per leggere ad alta voce ogni messaggio in una conversazione.
Innanzitutto, devi specificare l'utente del dispositivo come oggetto Person, come
mostrato nell'esempio seguente:
fun createMessagingStyle(
context: Context, appConversation: YourAppConversation): MessagingStyle {
// Method defined by the messaging app.
val appDeviceUser: YourAppUser = getAppDeviceUser()
val devicePerson = Person.Builder()
// The display name (also the name that's read aloud in Android auto).
.setName(appDeviceUser.name)
// The icon to show in the notification shade in the system UI (outside
// of Android Auto).
.setIcon(appDeviceUser.icon)
// A unique key in case there are multiple people in this conversation with
// the same name.
.setKey(appDeviceUser.id)
.build()
// ...
Puoi quindi creare l'oggetto MessagingStyle e fornire alcuni dettagli
sulla conversazione.
// ...
val messagingStyle = MessagingStyle(devicePerson)
// Sets the conversation title. If the app's target version is lower
// than P, this will automatically mark the conversation as a group (to
// maintain backward compatibility). Use `setGroupConversation` after
// setting the conversation title to explicitly override this behavior. See
// the documentation for more information.
messagingStyle.setConversationTitle(appConversation.title)
// Group conversation means there is more than 1 recipient, so set it as such.
messagingStyle.setGroupConversation(appConversation.recipients.size > 1)
// ...
Infine, aggiungi i messaggi da leggere.
// ...
for (appMessage in appConversation.getUnreadMessages()) {
// The sender is also represented using a Person object.
val senderPerson = Person.Builder()
.setName(appMessage.sender.name)
.setIcon(appMessage.sender.icon)
.setKey(appMessage.sender.id)
.build()
// Adds the message. More complex messages, like images,
// can be created and added by instantiating the MessagingStyle.Message
// class directly. See documentation for details.
messagingStyle.addMessage(
appMessage.body, appMessage.timeReceived, senderPerson)
}
return messagingStyle
}
Pacchettizzare e inviare la notifica
Dopo aver generato gli oggetti Action e MessagingStyle, puoi creare
e pubblicare Notification.
fun notify(context: Context, appConversation: YourAppConversation) {
// Creates the actions and MessagingStyle.
val replyAction = createReplyAction(context, appConversation)
val markAsReadAction = createMarkAsReadAction(context, appConversation)
val messagingStyle = createMessagingStyle(context, appConversation)
// Creates the notification.
val notification = NotificationCompat.Builder(context, channel)
// A required field for the Android UI.
.setSmallIcon(R.drawable.notification_icon)
// Shows in Android Auto as the conversation image.
.setLargeIcon(appConversation.icon)
// Adds MessagingStyle.
.setStyle(messagingStyle)
// Adds reply action.
.addAction(replyAction)
// Makes the mark-as-read action invisible, so it doesn't appear
// in the Android UI but the app satisfies Android Auto's
// mark-as-read Action requirement. Both required actions can be made
// visible or invisible; it is a stylistic choice.
.addInvisibleAction(markAsReadAction)
.build()
// Posts the notification for the user to see.
val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.notify(appConversation.id, notification)
}
Risorse aggiuntive
Segnalare un problema di notifica della messaggistica di Android Auto
Se riscontri un problema durante lo sviluppo delle notifiche di messaggistica per Android Auto, puoi segnalarlo utilizzando Google Issue Tracker. Assicurati di compilare tutte le informazioni richieste nel modello di problema.
Prima di segnalare un nuovo problema, controlla se è già stato segnalato nell'elenco dei problemi. Puoi iscriverti e votare i problemi facendo clic sulla stella corrispondente nel tracker. Per saperne di più, consulta Abbonarsi a un problema.