Messaging-Apps für Android Auto entwickeln

Die Kategorie „Kommunikation“ ist bald verfügbar
Die Kategorie „Messaging“ wird um die Unterstützung neuer Funktionen erweitert, darunter Nachrichtenverlauf und Anruffunktionen.

Für viele Fahrer ist es wichtig, per Nachricht erreichbar zu sein. Chat-Apps können Nutzer darüber informieren, ob ein Kind abgeholt werden muss oder sich der Ort für ein Abendessen geändert hat. Mit dem Android-Framework können Messaging-Apps ihre Dienste auf das Autofahren ausweiten. Dazu wird eine standardmäßige Benutzeroberfläche verwendet, die es Fahrern ermöglicht, den Blick auf die Straße zu richten.

Apps, die Messaging unterstützen, können ihre Messaging-Benachrichtigungen erweitern, damit Android Auto sie nutzen kann, wenn Auto aktiv ist. Diese Benachrichtigungen werden im Modus „Auto“ angezeigt. Nutzer können Nachrichten dann auf einer einheitlichen, ablenkungsfreien Oberfläche lesen und 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, die speziell für Benachrichtigungen zu Nachrichten entwickelt wurde, verbesserte Animationen und die Unterstützung für Inline-Bilder.

In diesem Leitfaden erfahren Sie, wie Sie eine App erweitern, die Nachrichten an den Nutzer sendet und die Antworten des Nutzers empfängt, z. B. eine Chat-App, um die Anzeige von Nachrichten und den Empfang von Antworten an ein Autogerät weiterzuleiten. Entsprechende Designrichtlinien finden Sie auf der Website „Design for Driving“ unter Messaging-Apps.

Erste Schritte

Wenn Sie einen Messaging-Dienst für Auto-Geräte bereitstellen möchten, muss Ihre App die Unterstützung für Android Auto im Manifest deklarieren und Folgendes können:

  • Erstellen und senden Sie NotificationCompat.MessagingStyle-Objekte, die Action-Objekte zum Antworten und als gelesen kennzeichnen enthalten.
  • Antworten und Unterhaltungen mit Service als gelesen markieren

Konzepte und Objekte

Bevor Sie mit dem Design Ihrer App beginnen, ist es hilfreich, zu verstehen, wie Android Auto mit Nachrichten umgeht.

Ein einzelner Kommunikationsblock wird als Nachricht bezeichnet und durch die Klasse MessagingStyle.Message dargestellt. Eine Nachricht enthält einen Absender, den Inhalt der Nachricht 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 (MessagingStyle) enthält einen Titel, die Nachrichten und ob es sich um eine Unterhaltung zwischen mehreren Nutzern handelt.

Wenn Nutzer über Aktualisierungen einer Unterhaltung informiert werden sollen, z. B. über eine neue Nachricht, posten Apps eine Notification in das Android-System. In diesem Notification wird das MessagingStyle-Objekt verwendet, um eine Messaging-spezifische Benutzeroberfläche im Benachrichtigungs-Schieberegler anzuzeigen. Die Android-Plattform gibt diese Notification auch an Android Auto weiter. Die MessagingStyle wird extrahiert und verwendet, um eine Benachrichtigung über das Display des Autos zu senden.

Außerdem müssen Apps in Android Auto einem Notification Action-Objekte hinzufügen, damit Nutzer direkt über den Benachrichtigungs-Schirm auf eine Nachricht antworten oder sie als gelesen markieren können.

Zusammenfassend wird eine einzelne Unterhaltung durch ein Notification-Objekt dargestellt, das mit einem MessagingStyle-Objekt formatiert ist. Das MessagingStyle-Objekt enthält alle Nachrichten in dieser Unterhaltung in einem oder mehreren MessagingStyle.Message-Objekten. Damit eine App Android Auto-kompatibel ist, muss sie dem Notification Antwort- und „Als gelesen markieren“-Action-Objekte anhängen.

Messaging-Ablauf

In diesem Abschnitt wird ein typischer Nachrichtenablauf zwischen Ihrer App und Android Auto beschrieben.

  1. Ihre App erhält eine Nachricht.
  2. Ihre App generiert eine MessagingStyle-Benachrichtigung mit Action-Objekten zum Antworten und als gelesen kennzeichnen.
  3. Android Auto empfängt das Ereignis „Neue Benachrichtigung“ vom Android-System und sucht nach MessagingStyle, Antwort Action und als gelesen markieren Action.
  4. Android Auto generiert und zeigt eine Benachrichtigung im Auto an.
  5. Wenn der Nutzer auf die Benachrichtigung auf dem Display des Autos tippt, löst Android Auto die Markierung als gelesen Action aus.
    • Im Hintergrund muss Ihre App dieses Ereignis verarbeiten.
  6. Wenn der Nutzer per Sprachbefehl auf die Benachrichtigung antwortet, fügt Android Auto eine Transkription der Antwort des Nutzers in die Antwort Action ein und löst sie dann aus.
    • Im Hintergrund muss Ihre App dieses Antwortereignis verarbeiten.

Vorläufige Annahmen

Auf dieser Seite erfahren Sie nicht, wie Sie eine vollständige Messaging-App erstellen. Das folgende Codebeispiel enthält einige der Funktionen, die Ihre App benötigt, bevor Sie die Messaging-Funktion mit Android Auto unterstützen können:

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)

Unterstützung für Android Auto angeben

Wenn Android Auto eine Benachrichtigung von einer Messaging-App erhält, wird geprüft, ob die App die Unterstützung für Android Auto erklärt hat. Fügen Sie zum Aktivieren dieser Unterstützung den folgenden Eintrag in das Manifest Ihrer App ein:

<application>
    ...
    <meta-data
        android:name="com.google.android.gms.car.application"
        android:resource="@xml/automotive_app_desc"/>
    ...
</application>

Dieser Manifesteintrag bezieht sich auf eine andere XML-Datei, die Sie mit dem folgenden Pfad erstellen müssen: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml. Deklarieren Sie in automotive_app_desc.xml die Android Auto-Funktionen, die von Ihrer App unterstützt werden. Wenn Sie beispielsweise die Unterstützung von Benachrichtigungen angeben möchten, geben Sie Folgendes an:

<automotiveApp>
    <uses name="notification" />
</automotiveApp>

Wenn Ihre App als Standard-SMS-Handler festgelegt werden kann, müssen Sie das folgende <uses>-Element einfügen. Andernfalls wird ein in Android Auto integrierter Standard-Handler für eingehende SMS/MMS-Nachrichten 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

Für die Erstellung von Benachrichtigungen zur Verwendung mit Auto-Geräten ist die AndroidX-Kernbibliothek erforderlich. So importieren Sie die Bibliothek in Ihr Projekt:

  1. Fügen Sie in der Datei build.gradle auf oberster Ebene eine Abhängigkeit vom Maven-Repository von Google hinzu, wie im folgenden Beispiel gezeigt:

Groovy

allprojects {
    repositories {
        google()
    }
}

Kotlin

allprojects {
    repositories {
        google()
    }
}
  1. Fügen Sie in der build.gradle-Datei Ihres App-Moduls die Bibliothek AndroidX Core als Abhängigkeit hinzu, wie im folgenden Beispiel gezeigt:

Groovy

dependencies {
    // If your app is written in Java
    implementation 'androidx.core:core:1.15.0'

    // If your app is written in Kotlin
    implementation 'androidx.core:core-ktx:1.15.0'
}

Kotlin

dependencies {
    // If your app is written in Java
    implementation("androidx.core:core:1.15.0")

    // If your app is written in Kotlin
    implementation("androidx.core:core-ktx:1.15.0")
}

Nutzeraktionen verarbeiten

Ihre Messaging-App muss die Aktualisierung einer Unterhaltung über eine Action unterstützen. Für Android Auto gibt es zwei Arten von Action-Objekten, die Ihre App verarbeiten muss: „Antworten“ und „Als gelesen markieren“. Wir empfehlen, sie mit einem IntentService zu verarbeiten. So können Sie potenziell teure Aufrufe im Hintergrund verarbeiten und den Hauptthread Ihrer App entlasten.

Intent-Aktionen definieren

Intent-Aktionen sind einfache Strings, die angeben, wozu die Intent dient. Da ein einzelner Dienst mehrere Arten von Intents verarbeiten kann, ist es einfacher, mehrere Aktionsstrings anstelle mehrerer IntentService-Komponenten zu definieren.

Die Beispiel-Messaging-App in diesem Leitfaden bietet die beiden erforderlichen Aktionstypen: „Antworten“ und „Als gelesen markieren“, wie im folgenden Codebeispiel zu sehen.

private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"

Dienst erstellen

Wenn Sie einen Dienst erstellen möchten, der diese Action-Objekte verarbeitet, benötigen Sie die Unterhaltungs-ID. Das ist eine beliebige Datenstruktur, die von Ihrer App definiert wird und die Unterhaltung identifiziert. Außerdem benötigen Sie einen Remote-Eingabeschlüssel, der weiter unten in diesem Abschnitt ausführlich beschrieben wird. Im folgenden Codebeispiel wird ein Dienst zum Ausführen der erforderlichen Aktionen erstellt:

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()
        }
    }
}

Wenn Sie diesen Dienst mit Ihrer App verknüpfen möchten, müssen Sie ihn auch im Manifest Ihrer App registrieren, wie im folgenden Beispiel gezeigt:

<application>
    <service android:name="com.example.MessagingService" />
    ...
</application>

Intents generieren und verarbeiten

Andere Apps, einschließlich Android Auto, können die Intent, die die MessagingService auslöst, nicht abrufen, da Intents ü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
}

Ermitteln Sie in der ACTION_REPLY-Wechselklausel innerhalb der MessagingService die Informationen, die in die Antwort Intent einfließen sollen, wie im folgenden Beispiel gezeigt:

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)
}

Die Funktion „Als gelesen markieren“ Intent funktioniert ähnlich. Es ist jedoch keine RemoteInput 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 ACTION_MARK_AS_READ-Switch-Klausel innerhalb 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 benachrichtigen

Sobald die Verarbeitung von Unterhaltungsaktionen abgeschlossen ist, besteht der nächste Schritt darin, Android Auto-kompatible Benachrichtigungen zu generieren.

Aktionen erstellen

Action-Objekte können mithilfe eines Notification an andere Apps übergeben werden, um Methoden in der ursprünglichen App auszulösen. So kann Android Auto eine Unterhaltung als gelesen markieren oder darauf antworten.

Wenn Sie eine Action erstellen möchten, beginnen Sie mit einer Intent. Im folgenden Beispiel wird gezeigt, wie eine Intent vom Typ „Antwort“ erstellt wird:

fun createReplyAction(
        context: Context, appConversation: YourAppConversation): Action {
    val replyIntent: Intent = createReplyIntent(context, appConversation)
    // ...

Anschließend muss dieser Intent in einen PendingIntent-Block gepackt werden, um ihn für die Verwendung in externen Apps vorzubereiten. Ein PendingIntent sperrt den gesamten Zugriff auf die gewrappte Intent, indem nur eine ausgewählte Gruppe von Methoden freigegeben wird, mit denen die empfangende App die Intent auslösen oder den Paketnamen der ursprünglichen App abrufen kann. Die externe App kann niemals auf die 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 Sie die Antwort Action einrichten, beachten Sie, dass Android Auto drei Anforderungen an die Antwort Action stellt:

  • 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 einen einzelnen RemoteInput enthalten.

Im folgenden Codebeispiel wird eine Antwort-Action eingerichtet, die den oben aufgeführten Anforderungen entspricht:

    // ...
    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 Verarbeitung der Markierung als gelesen funktioniert ähnlich, es gibt jedoch keine RemoteInput. Für Android Auto gelten daher zwei Anforderungen für die Funktion „Als gelesen markieren“ 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 Markierung als gelesen 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 jede PendingIntent, die von Android verwendet werden, um vorhandene ausstehende Intents zu steuern. Die create()-Methoden müssen für jede Unterhaltung eindeutige IDs zurückgeben. Wiederholte Aufrufe für dieselbe Unterhaltung müssen jedoch die bereits generierte eindeutige ID zurückgeben.

Angenommen, Sie haben zwei Unterhaltungen, A und B. Die Antwort-ID von Unterhaltung A ist 100 und die Markierung als gelesen-ID ist 101. Die Antwort-ID von Unterhaltung B lautet 102 und die Markieren-als-gelesen-ID 103. Wenn Konversation A aktualisiert wird, bleiben die IDs für die Antwort und das Markieren als gelesen weiterhin 100 und 101. Weitere Informationen finden Sie 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 laut 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 senden

Nachdem Sie die Action- und MessagingStyle-Objekte generiert haben, können Sie die Notification erstellen und veröffentlichen.

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)
}

Weitere Informationen

Problem mit Android Auto-Messaging melden

Wenn bei der Entwicklung Ihrer Messaging-App für Android Auto ein Problem auftritt, können Sie es über den Google Issue Tracker melden. Achten Sie darauf, in der Vorlage für Probleme alle angeforderten Informationen anzugeben.

Neues Problem erstellen

Bevor Sie ein neues Problem melden, prüfen Sie, ob es bereits in der Liste der Probleme aufgeführt ist. Sie können Probleme abonnieren und dafür stimmen, indem Sie im Tracker auf den Stern für ein Problem klicken. Weitere Informationen finden Sie unter Probleme abonnieren.