Für viele Autofahrer ist es wichtig, durch Nachrichten in Verbindung zu bleiben. Chat-Apps können Nutzer darüber informieren, ob ein Kind abgeholt werden muss oder der Ort für das Abendessen geändert wurde. Mit dem Android-Framework können Messaging-Apps ihre Dienste auf das Fahrerlebnis erweitern. Dazu wird eine standardmäßige Benutzeroberfläche verwendet, mit der Fahrer den Straßenverkehr im Auge behalten können.
Apps, die Messaging unterstützen, können ihre Benachrichtigungen so erweitern, dass Android Auto sie nutzen kann, wenn Auto ausgeführt wird. Diese Benachrichtigungen werden in der automatischen Version angezeigt und bieten Nutzern die Möglichkeit, Nachrichten auf einer einheitlichen Oberfläche mit geringer Ablenkung zu lesen und zu beantworten. Wenn Sie die MessagingStyle API verwenden, erhalten Sie optimierte Nachrichtenbenachrichtigungen für alle Android-Geräte, einschließlich Android Auto. Zu den Optimierungen gehören eine Benutzeroberfläche speziell für Nachrichtenbenachrichtigungen, verbesserte Animationen und Unterstützung von Inline-Bildern.
In diesem Leitfaden wird beschrieben, wie du eine App, die Nachrichten für den Nutzer anzeigt und die Antworten des Nutzers empfängt (z. B. eine Chat-App), so erweitert, dass Nachrichten angezeigt und Empfangsbestätigungen an ein Auto-Gerät gesendet werden. Entsprechende Anleitungen finden Sie unter Messaging-Apps auf der Website „Design for Driving“.
Erste Schritte
Damit du den Nachrichtendienst für Android Auto-Geräte nutzen kannst, muss deine App im Manifest die Unterstützung für Android Auto deklarieren und folgende Aktionen ausführen:
- Erstellen und senden Sie
NotificationCompat.MessagingStyle
-Objekte, die Antwort- und „Als gelesen markieren“-Action
-Objekte enthalten. - Mit
Service
kannst du auf Unterhaltungen antworten und Unterhaltungen als gelesen markieren.
Konzepte und Objekte
Bevor du mit dem Entwerfen deiner App beginnst, solltest du wissen, wie Android Auto Nachrichten verarbeitet.
Ein einzelner Kommunikationsblock wird als Nachricht bezeichnet und durch die Klasse MessagingStyle.Message
dargestellt. Eine Nachricht enthält einen Absender, den Nachrichteninhalt und die Uhrzeit, zu der die Nachricht gesendet wurde.
Die Kommunikation zwischen Nutzern wird als Unterhaltung bezeichnet und durch ein MessagingStyle
-Objekt dargestellt. Eine Unterhaltung oder MessagingStyle
enthält einen Titel, die Nachrichten und Informationen dazu, ob die Unterhaltung zu einer Gruppe von Nutzern gehört.
Apps posten Notification
an das Android-System, um Nutzer über Aktualisierungen einer Unterhaltung zu informieren, z. B. über eine neue Nachricht.
Notification
verwendet das MessagingStyle
-Objekt, um eine nachrichtenspezifische UI in der Benachrichtigungsleiste anzuzeigen. Die Android-Plattform übergibt diese Notification
auch an Android Auto, die MessagingStyle
wird extrahiert und verwendet, um eine Benachrichtigung über das Display des Autos zu posten.
In Android Auto müssen Apps außerdem Action
-Objekte zu einer Notification
hinzufügen, damit der Nutzer schnell auf eine Nachricht antworten oder sie direkt über die Benachrichtigungsleiste als gelesen markieren kann.
Eine einzelne Unterhaltung wird also durch ein Notification
-Objekt mit einem MessagingStyle
-Objekt dargestellt. MessagingStyle
enthält alle Nachrichten in dieser Unterhaltung in einem oder mehreren MessagingStyle.Message
-Objekten. Um Android Auto-konform zu sein, muss eine App außerdem Antwort- und „Als gelesen markieren“-Action
-Objekte an das Notification
anhängen.
Kommunikationsablauf
In diesem Abschnitt wird ein typischer Nachrichtenfluss zwischen Ihrer App und Android Auto beschrieben.
- Ihre App empfängt eine Nachricht.
- Ihre App generiert eine
MessagingStyle
-Benachrichtigung mit Antwort- undAction
-Objekten als gelesen markieren. - Android Auto empfängt das Ereignis „Neue Benachrichtigung“ vom Android-System und findet
MessagingStyle
, antwortet mitAction
und als gelesen markieren (Action
). - Android Auto generiert eine Benachrichtigung im Auto und zeigt sie an.
- Wenn der Nutzer auf die Benachrichtigung auf dem Display des Autos tippt, löst Android Auto das „Als gelesen markieren“
Action
aus.- Ihre App muss dieses „Als gelesen markieren“-Ereignis im Hintergrund verarbeiten.
- Wenn der Nutzer per Spracheingabe auf die Benachrichtigung antwortet, fügt Android Auto ein Transkript der Nutzerantwort in das Antwort-
Action
ein und löst es dann aus.- Ihre App muss dieses Antwortereignis im Hintergrund verarbeiten.
Vorläufige Annahmen
Diese Seite führt dich nicht durch die Erstellung einer vollständigen Messaging-App. Das folgende Codebeispiel enthält einige der Dinge, die deine App benötigt, bevor du die Nachrichtenfunktion mit Android Auto unterstützen kannst:
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)
Android Auto-Unterstützung deklarieren
Wenn Android Auto eine Benachrichtigung von einer Messaging-App erhält, wird geprüft, ob die App Unterstützung für Android Auto erklärt hat. Füge den folgenden Eintrag in das Manifest deiner App ein, um diese Unterstützung zu aktivieren:
<application>
...
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
Dieser Manifesteintrag verweist auf eine andere XML-Datei, die Sie mit dem folgenden Pfad erstellen müssen: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml
.
Gib in automotive_app_desc.xml
die Android Auto-Funktionen an, die deine App unterstützt. So können Sie beispielsweise die Unterstützung für Benachrichtigungen deklarieren:
<automotiveApp>
<uses name="notification" />
</automotiveApp>
Wenn Ihre App als Standard-SMS-Handler festgelegt werden kann, fügen Sie das folgende <uses>
-Element hinzu. Andernfalls wird ein in Android Auto integrierter Standard-Handler zur Verarbeitung eingehender SMS/MMS verwendet, wenn Ihre App als Standard-SMS-Handler festgelegt ist. Dies kann zu doppelten Benachrichtigungen führen.
<automotiveApp>
...
<uses name="sms" />
</automotiveApp>
AndroidX-Kernbibliothek importieren
Zum Erstellen von Benachrichtigungen zur Verwendung mit Auto-Geräten ist die AndroidX-Kernbibliothek erforderlich. Importieren Sie die Bibliothek wie folgt in Ihr Projekt:
- Fügen Sie in der Datei
build.gradle
auf oberster Ebene eine Abhängigkeit vom Maven-Repository von Google ein, wie im folgenden Beispiel gezeigt:
Groovig
allprojects { repositories { google() } }
Kotlin
allprojects { repositories { google() } }
- Füge in die Datei
build.gradle
deines App-Moduls die AndroidX Core-Bibliotheksabhängigkeit ein, wie im folgenden Beispiel gezeigt:
Groovig
dependencies { // If your app is written in Java implementation 'androidx.core:core:1.13.1' // If your app is written in Kotlin implementation 'androidx.core:core-ktx:1.13.1' }
Kotlin
dependencies { // If your app is written in Java implementation("androidx.core:core:1.13.1") // If your app is written in Kotlin implementation("androidx.core:core-ktx:1.13.1") }
Nutzeraktionen verarbeiten
Deine Messaging-App benötigt eine Möglichkeit, eine Unterhaltung über Action
zu aktualisieren. Für Android Auto gibt es zwei Arten von Action
-Objekten, die deine App verarbeiten muss: Antworten und Als gelesen markieren. Wir empfehlen, sie mit einem IntentService
zu verarbeiten. Dadurch können potenziell teure Aufrufe im Hintergrund ausgeführt werden und der Hauptthread der Anwendung wird frei.
Intent-Aktionen definieren
Intent
-Aktionen sind einfache Strings, die angeben, wofür die Intent
bestimmt ist.
Da ein einzelner Dienst mehrere Intent-Typen verarbeiten kann, ist es einfacher, mehrere Aktionsstrings zu definieren, anstatt mehrere IntentService
-Komponenten zu definieren.
Die beispielhafte Messaging-App dieses Leitfadens enthält die zwei erforderlichen Aktionstypen: „Antworten“ und „Als gelesen markieren“, wie im folgenden Codebeispiel gezeigt.
private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"
Dienst erstellen
Zum Erstellen eines Dienstes, der diese Action
-Objekte verarbeitet, benötigen Sie die Unterhaltungs-ID. Dabei handelt es sich um eine beliebige Datenstruktur, die von Ihrer Anwendung definiert wird und die Unterhaltung identifiziert. Sie benötigen außerdem einen Remote-Eingabeschlüssel, der weiter unten in diesem Abschnitt ausführlich erläutert wird. Im folgenden Codebeispiel wird ein Dienst erstellt, um die erforderlichen Aktionen zu verarbeiten:
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()
}
}
}
Um diesen Dienst mit Ihrer Anwendung zu verknüpfen, müssen Sie den Dienst auch im Manifest Ihrer Anwendung registrieren, wie im folgenden Beispiel gezeigt:
<application>
<service android:name="com.example.MessagingService" />
...
</application>
Intents generieren und verarbeiten
Andere Apps, einschließlich Android Auto, haben keine Möglichkeit, das Intent
abzurufen, das MessagingService
auslöst, weil Intent
s über eine PendingIntent
an andere Apps übergeben werden. Aufgrund dieser Einschränkung müssen Sie ein RemoteInput
-Objekt erstellen, damit andere Apps den Antworttext an Ihre App zurückgeben können, wie im folgenden Beispiel gezeigt:
/**
* 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
}
Extrahieren Sie wie im folgenden Beispiel in der ACTION_REPLY
-Schalterklausel innerhalb von MessagingService
die Informationen, die in die Intent
-Antwort eingegeben werden:
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)
}
Intent
wird auf ähnliche Weise verarbeitet. RemoteInput
ist jedoch nicht erforderlich, wie im folgenden Beispiel gezeigt:
/** 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
}
Die Wechselklausel ACTION_MARK_AS_READ
in der MessagingService
erfordert keine weitere Logik, wie im folgenden Beispiel gezeigt:
// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()
Nutzer über Nachrichten informieren
Sobald die Verarbeitung der Unterhaltungsaktionen abgeschlossen ist, müssen Sie als Nächstes Benachrichtigungen generieren, die mit Android Auto kompatibel sind.
Aktionen erstellen
Action
-Objekte können mithilfe eines Notification
an andere Apps übergeben werden, um Methoden in der ursprünglichen App auszulösen. Auf diese Weise kann Android Auto eine Unterhaltung als gelesen oder beantworten.
Wenn Sie ein Action
-Objekt erstellen möchten, beginnen Sie mit einem Intent
. Das folgende Beispiel zeigt, wie du eine Antwort-Intent
erstellst:
fun createReplyAction(
context: Context, appConversation: YourAppConversation): Action {
val replyIntent: Intent = createReplyIntent(context, appConversation)
// ...
Verpacken Sie dann diese Intent
in eine PendingIntent
, die sie für die externe Anwendungsnutzung vorbereitet. Ein PendingIntent
sperrt den gesamten Zugriff auf das umschlossene Intent
, indem nur ausgewählte Methoden verfügbar gemacht werden, mit denen die empfangende App das Intent
auslösen oder den Paketnamen der ursprünglichen App abrufen kann. Die externe Anwendung kann niemals auf das zugrunde liegende Intent
oder die darin enthaltenen Daten zugreifen.
// ...
val replyPendingIntent = PendingIntent.getService(
context,
createReplyId(appConversation), // Method explained later.
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
// ...
Bevor du die Antwort-Action
einrichtest, beachte, dass Android Auto drei Anforderungen für die Antwort-Action
hat:
- Die semantische Aktion muss auf
Action.SEMANTIC_ACTION_REPLY
festgelegt sein. - Die
Action
muss angeben, dass beim Auslösen keine Benutzeroberfläche angezeigt wird. Action
muss ein einzelnesRemoteInput
-Element enthalten.
Im folgenden Codebeispiel wird eine Antwort-Action
eingerichtet, die die oben aufgeführten Anforderungen erfüllt:
// ...
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
}
Die Aktion „Als gelesen markieren“ wird ähnlich verarbeitet, es wird jedoch kein RemoteInput
-Objekt verwendet.
Android Auto hat daher zwei Anforderungen für das „Mark-as-read“-Action
:
- Die semantische Aktion ist auf
Action.SEMANTIC_ACTION_MARK_AS_READ
festgelegt. - Die Aktion gibt an, dass beim Auslösen keine Benutzeroberfläche angezeigt wird.
Im folgenden Codebeispiel wird eine „Mark-as-Read“-Action
eingerichtet, die diese Anforderungen erfüllt:
fun createMarkAsReadAction(
context: Context, appConversation: YourAppConversation): Action {
val markAsReadIntent = createMarkAsReadIntent(context, appConversation)
val markAsReadPendingIntent = PendingIntent.getService(
context,
createMarkAsReadId(appConversation), // Method explained below.
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
}
Beim Generieren der ausstehenden Intents werden zwei Methoden verwendet: createReplyId()
und createMarkAsReadId()
. Diese Methoden dienen als Anfragecodes für jeden PendingIntent
, die von Android zur Steuerung vorhandener ausstehender Intents verwendet werden. Die create()
-Methoden müssen eindeutige IDs für jede Unterhaltung zurückgeben, wiederholte Aufrufe für dieselbe Unterhaltung müssen jedoch die bereits generierte eindeutige ID zurückgeben.
Nehmen wir ein Beispiel mit zwei Unterhaltungen, A und B: Die Antwort-ID von Unterhaltung A lautet 100 und die Mark-as-Read-ID 101. Die Antwort-ID von Konversation B lautet 102 und die Mark-as-Read-ID 103. Wenn Konversation A aktualisiert wird, sind die IDs für Antwort und Mark-as-Read weiterhin 100 und 101. Weitere Informationen findest du unter PendingIntent.FLAG_UPDATE_CURRENT
.
MessagingStyle erstellen
MessagingStyle
ist der Träger der Nachrichteninformationen und wird von Android Auto verwendet, um jede Nachricht in einer Unterhaltung vorzulesen.
Zuerst muss der Nutzer des Geräts in Form eines Person
-Objekts angegeben werden, wie im folgenden Beispiel gezeigt:
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()
// ...
Sie können dann das MessagingStyle
-Objekt erstellen und einige Details zur Unterhaltung angeben.
// ...
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)
// ...
Fügen Sie abschließend die ungelesenen Nachrichten hinzu.
// ...
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
}
Benachrichtigung verpacken und per Push übertragen
Nachdem Sie die Objekte Action
und MessagingStyle
generiert haben, können Sie die Notification
erstellen und hochladen.
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)
}
Zusätzliche Ressourcen
Problem mit Android Auto Messaging melden
Wenn bei der Entwicklung der Messaging-App für Android Auto ein Problem auftritt, kannst du es über den Google Issue Tracker melden. Geben Sie in der Problemvorlage alle erforderlichen Informationen an.
Bevor Sie ein neues Problem melden, prüfen Sie, ob es bereits in der Problemliste aufgeführt ist. Sie können Themen abonnieren und für sie abstimmen, indem Sie im Tracker auf den Stern für ein Problem klicken. Weitere Informationen finden Sie unter Ausgaben abonnieren.