Tworzenie aplikacji do obsługi wiadomości na Androida Auto

Kategoria „Komunikacja” pojawi się już wkrótce
Rozszerzamy kategorię Wiadomości, aby obejmowała nowe funkcje, w tym historię wiadomości i funkcje połączeń.

Dla wielu kierowców pozostawanie w kontakcie za pomocą wiadomości jest ważne. Aplikacje do obsługi czatu mogą umożliwiać użytkownikom czy dziecko trzeba odebrać lub czy zostało zmienione miejsce kolacji. Platforma Androida pozwala aplikacjom do obsługi wiadomości wzbogacić do funkcji jazdy za pomocą standardowego interfejsu, który pozwala kierowcom zachować na drogę.

Aplikacje obsługujące wiadomości mogą przedłużyć działanie powiadomień o wiadomościach, aby umożliwić Androida Auto zużywają ich, gdy jest włączona opcja Automatyczna. Te powiadomienia są wyświetlane w trybie automatycznym i pozwalają użytkownikom do odczytywania wiadomości i odpowiadania na nie przy użyciu spójnego interfejsu, który nie rozprasza uwagi. A gdy używasz MessagingStyle API, będziesz otrzymywać zoptymalizowane powiadomienia o wiadomościach na urządzenia z Androidem. np. z Androidem Auto. Optymalizacje obejmują interfejs stworzony specjalnie pod kątem powiadomienia o wiadomościach, ulepszone animacje i obsługę obrazów w tekście.

Z tego przewodnika dowiesz się, jak rozszerzyć aplikację, która wyświetla wiadomości użytkownikowi, otrzymują odpowiedzi użytkownika (np. z aplikacji do obsługi czatu), aby wyświetlić wiadomość potwierdzenie odpowiedzi na nie. Wskazówki dotyczące projektowania znajdziesz w artykule Obsługa wiadomości w witrynie Dla kierowców.

Rozpocznij

Aby zapewnić usługę do przesyłania wiadomości na urządzenia z Androidem, aplikacja musi zadeklarować obsługa Androida Auto w pliku manifestu i wykonanie tych czynności:

  • Utwórz i wyślij NotificationCompat.MessagingStyle , które zawierają obiekty odpowiedzi i oznaczenia jako przeczytane Action.
  • Obsługa odpowiadania na wiadomości i oznaczania rozmów jako przeczytanych za pomocą funkcji Service.

Pojęcia i obiekty

Zanim zaczniesz projektować aplikację, warto dowiedzieć się, jak Android Auto obsługuje wiadomości.

Pojedynczy fragment komunikacji to wiadomość i jest reprezentowana przez zajęcia MessagingStyle.Message. Wiadomość zawiera nadawcę. Wiadomość treść oraz czas wysłania wiadomości.

Komunikacja między użytkownikami to rozmowa, która jest reprezentowana MessagingStyle obiekt. Wątek (MessagingStyle) zawiera tytuł, wiadomości oraz to, czy wątek należy do grupy użytkowników.

Aby powiadamiać użytkowników o aktualizacjach rozmowy, np. o nowej wiadomości, aplikacje publikują Notification na Androida. Ten interfejs Notification używa obiektu MessagingStyle do wyświetlania związanych z wiadomościami Interfejs w obszarze powiadomień. Platforma Android przekazuje również ten Notification na Androida Auto, a MessagingStyle jest wyodrębniany i używany do opublikowania na wyświetlaczu w samochodzie.

Android Auto wymaga też, aby aplikacje dodawały obiekty Action do: Notification pozwalają użytkownikowi szybko odpowiedzieć na wiadomość lub oznaczyć ją jako przeczytaną bezpośrednio z w obszarze powiadomień.

Podsumowując, pojedynczy wątek jest reprezentowany przez Notification. którego styl jest zgodny z obiektem MessagingStyle. MessagingStyle zawiera wszystkie wiadomości z tego wątku w co najmniej jednym MessagingStyle.Message obiektów. Aby zachować zgodność z Androidem Auto, musisz też musi dołączać odpowiedź i obiekty mark-as-read Action do klasy Notification.

Przepływ wiadomości

W tej sekcji opisujemy typowy przepływ wiadomości między aplikacją a Androidem Auto.

  1. Aplikacja otrzyma wiadomość.
  2. Twoja aplikacja wygeneruje powiadomienie w aplikacji MessagingStyle z odpowiedzią i Oznacz obiekty jako odczytywane jako Action.
  3. Android Auto otrzymuje zdarzenie „nowe powiadomienie” z systemu Android i znajduje MessagingStyle, odpowiedź Action i oznaczenie jako przeczytane: Action.
  4. Android Auto generuje i wyświetla powiadomienie w samochodzie.
  5. Jeśli użytkownik kliknie powiadomienie na wyświetlaczu w samochodzie, Android Auto aktywuje funkcję Action do oznaczenia jako przeczytany.
    • Aplikacja musi obsługiwać w tle to zdarzenie oznaczenia jako odczytywane.
  6. Jeśli użytkownik zareaguje na powiadomienie głosowo, Android Auto przekaże transkrypcję odpowiedzi użytkownika na odpowiedź Action, a następnie uruchamia ją.
    • Aplikacja musi obsługiwać w tle to zdarzenie odpowiedzi.

Założenia wstępne

Na tej stronie nie znajdziesz instrukcji tworzenia całej aplikacji do obsługi wiadomości. ten przykładowy kod zawiera niektóre rzeczy, których potrzebuje Twoja aplikacja zanim zaczniesz obsługiwać wiadomości w Androidzie 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)

Deklarowanie obsługi Androida Auto

Gdy Android Auto otrzymuje powiadomienie z aplikacji do obsługi wiadomości, sprawdza, czy aplikacja zadeklarowała obsługę Androida Auto. Aby włączyć tę funkcję, dołącz ten wpis w pliku manifestu aplikacji:

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

Ten wpis manifestu odnosi się do innego pliku XML, który musisz utworzyć za pomocą ta ścieżka: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml. W sekcji automotive_app_desc.xml zadeklaruj możliwości Androida Auto. obsługuje. Aby na przykład zadeklarować obsługę powiadomień, dołącz parametr :

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

Jeśli aplikację można ustawić jako domyślną aplikację do obsługi SMS-ów, pamiętaj o dodaniu tego elementu <uses>. Jeśli tego nie zrobisz, zostanie użyta domyślna do obsługi przychodzących SMS-ów i MMS-ów będzie wbudowany moduł obsługi Androida Auto gdy aplikacja jest ustawiona jako domyślny moduł obsługi SMS-ów, co może prowadzić do zduplikowania powiadomienia.

<automotiveApp>
    ...
    <uses name="sms" />
</automotiveApp>

Importowanie podstawowej biblioteki AndroidaX

Tworzenie powiadomień na potrzeby urządzeń automatycznych wymaga: AndroidX. Zaimportuj bibliotekę do projektu w następujący sposób:

  1. W pliku build.gradle najwyższego poziomu uwzględnij zależność od narzędzia Google Maven. Jak w tym przykładzie:

Odlotowe

allprojects {
    repositories {
        google()
    }
}

Kotlin

allprojects {
    repositories {
        google()
    }
}
  1. W pliku build.gradle modułu aplikacji umieść AndroidX Core w zależności od biblioteki, jak pokazano w tym przykładzie:

Odlotowe

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

Obsługa działań użytkowników

Aplikacja do obsługi wiadomości musi mieć sposób aktualizowania rozmowy za pomocą Action W Androidzie Auto są dostępne 2 typy obiektów Action. musi obsługiwać: odpowiedź i oznaczenie jako przeczytane. Zalecamy korzystanie z nich za pomocą IntentService, zapewnia elastyczność w obsłudze potencjalnie kosztownych w tle, zwalniając główny wątek aplikacji.

Zdefiniuj działania związane z intencjami

Działania Intent to proste ciągi znaków, które określają, do czego służy pole Intent. Pojedyncza usługa może obsługiwać wiele typów intencji, więc łatwiej jest definiowanie wielu ciągów działań zamiast definiowania wielu IntentService komponentu.

Przykładowa aplikacja do obsługi wiadomości z tego przewodnika zawiera 2 wymagane typy działań: odpowiedzi i oznaczenia jako przeczytane, zgodnie z tym przykładowym kodem.

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

Tworzenie usługi

Aby utworzyć usługę, która obsługuje te obiekty Action, potrzebujesz identyfikatora rozmowy. czyli dowolną strukturę danych zdefiniowaną przez aplikację, która identyfikuje rozmowę. Potrzebujesz też zdalnego klucza wprowadzania danych, co zostało omówione w szczegóły w dalszej części tej sekcji. Następujący przykładowy kod tworzy usługę wykonanie wymaganych działań:

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

Aby powiązać tę usługę z aplikacją, musisz też ją zarejestrować w pliku manifestu aplikacji, jak w tym przykładzie:

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

Generowanie i obsługa intencji

Inne aplikacje, w tym Android Auto, nie mają możliwości uzyskaniaIntent który aktywuje działanie MessagingService, ponieważ elementy Intent są przekazywane do innych aplikacji za pomocą PendingIntent. Z powodu to ograniczenie, musisz utworzyć RemoteInput możesz umożliwić innym aplikacjom przekazywanie tekstu odpowiedzi do aplikacji, w tym przykładzie:

/**
 * 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
}

W klauzuli przełącznika ACTION_REPLY w elemencie MessagingService wyodrębnij informacje znajdujące się w odpowiedzi Intent, tak jak to widać w następujący przykład:

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

W podobny sposób postępuje się z oznaczeniem Intent jako przeczytane. Nie powoduje to jednak wymaga RemoteInput, jak w tym przykładzie:

/** 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
}

Klauzula przełączania ACTION_MARK_AS_READ w elemencie MessagingService nie wymaga żadnej logiki, jak widać w tym przykładzie:

// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()

Powiadamianie użytkowników o wiadomościach

Po zakończeniu obsługi czynności związanej z rozmową generowanie powiadomień zgodnych z Androidem Auto.

Utwórz działania

Obiekty Action można przekazywać do innych aplikacji za pomocą parametru Notification metod aktywowania w pierwotnej aplikacji. W ten sposób Android Auto może oznaczyć jako przeczytane lub na nie odpowiesz.

Aby utworzyć Action, zacznij od Intent. Następujący przykład pokazuje: Jak utworzyć odpowiedź? Intent:

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

Następnie zapakuj Intent w PendingIntent, aby przygotować je do wyświetlania na zewnątrz korzystanie z aplikacji. Element PendingIntent blokuje cały dostęp do opakowanego elementu Intent przez udostępniając jedynie zestaw metod, które pozwalają aplikacji docelowej uruchomić Intent lub sprawdź nazwę pakietu aplikacji, z której pochodzą. Aplikacja zewnętrzna nie może nigdy uzyskać dostępu do bazowego zasobu Intent ani zawartych w nim danych.

    // ...
    val replyPendingIntent = PendingIntent.getService(
        context,
        createReplyId(appConversation), // Method explained later.
        replyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
    // ...

Zanim skonfigurujesz odpowiedź Action, pamiętaj, że w Androidzie Auto są dostępne wymagania dotyczące odpowiedzi Action:

  • Działanie semantyczne musi być ustawione na Action.SEMANTIC_ACTION_REPLY.
  • Pole Action musi wskazywać, że po uruchomieniu nie wyświetla się żaden interfejs.
  • Pole Action musi zawierać pojedynczy element RemoteInput.

Następujący przykładowy kod konfiguruje odpowiedź Action adresowaną do wymagania wymienione powyżej:

    // ...
    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
}

Obsługa działania Oznacz jako przeczytane jest podobna, z tą różnicą, że nie ma atrybutu RemoteInput. Android Auto ma więc 2 wymagania dotyczące oznaczenia Action jako przeczytane:

  • Działanie semantyczne jest ustawione na Action.SEMANTIC_ACTION_MARK_AS_READ.
  • Oznacza to, że po uruchomieniu nie wyświetli się żaden interfejs.

Następujący przykładowy kod konfiguruje element Action „oznacz jako odczyt”, który rozwiązuje te problemy wymagania:

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
}

Do generowania intencji oczekujących używane są 2 metody: createReplyId() i createMarkAsReadId(). Metody te służą jako żądania kodów dla każdego PendingIntent, które są używane przez Androida do sterowania oczekujące intencje. Metody create() muszą zwracają unikalne identyfikatory dla każdej rozmowy, ale powtarzające się wywołania tego samego Rozmowa musi zwracać wygenerowany wcześniej unikalny identyfikator.

Przyjrzyjmy się przykładowi z 2 wątkami, A i B. Identyfikator odpowiedzi rozmowy A to 100, a identyfikator ten to 101. Identyfikator odpowiedzi wątku B to 102, a jego identyfikator oznaczenia jako odczytywany to 103. Jeśli wątek A jest zaktualizowany, parametr identyfikatory odpowiedzi i oznaczenia jako przeczytane to nadal 100 i 101. Więcej informacji: PendingIntent.FLAG_UPDATE_CURRENT

Tworzenie stylu wiadomości

MessagingStyle jest dostawcą informacji i czym jest to, co Android Automatyczne używanie do czytania na głos każdej wiadomości w rozmowie.

Po pierwsze użytkownik urządzenia musi być określony za pomocą Person, jak widać w tabeli następujący przykład:

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()
    // ...

Następnie możesz utworzyć obiekt MessagingStyle i podać kilka szczegółów o tej rozmowie.

    // ...
    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)
    // ...

Na koniec dodaj nieprzeczytane wiadomości.

    // ...
    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
}

Zapakuj i wypchnij powiadomienie

Po wygenerowaniu obiektów Action i MessagingStyle możesz tworzyć i publikować 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)
}

Dodatkowe materiały

Zgłaszanie problemu z funkcją Android Auto Messaging

Jeśli podczas tworzenia aplikacji do obsługi wiadomości na Androida Auto napotkasz problem, możesz ją zgłosić za pomocą Google Issue Tracker. Pamiętaj, aby w szablonie problemu podać wszystkie wymagane informacje.

Tworzenie nowego numeru

Zanim zgłosisz nowy problem, sprawdź, czy został już zgłoszony w problemach z listy. Możesz zasubskrybować kanał i głosować na problemy, klikając gwiazdkę przy problemie w lokalizatora. Więcej informacji: Subskrybowanie problemu.