Aplikasi yang mendukung pesan dapat mengirim notifikasi pesannya ke Android Auto untuk digunakan saat Android Auto sedang berjalan. Notifikasi ini ditampilkan oleh Android Auto dan memungkinkan pengguna membaca dan membalas pesan dalam antarmuka yang konsisten dan minim gangguan. Selain itu, jika menggunakan MessagingStyle API, Anda akan mendapatkan notifikasi pesan yang dioptimalkan untuk semua perangkat Android, termasuk Android Auto. Pengoptimalan mencakup UI yang dikhususkan untuk notifikasi
pesan, animasi yang ditingkatkan, dan dukungan untuk gambar inline.
Panduan ini menunjukkan cara memperluas aplikasi yang menampilkan pesan kepada pengguna dan menerima balasan pengguna, seperti aplikasi chat, untuk memberikan tampilan pesan dan membalas tanda terima ke Android Auto. Melalui integrasi ini, pengguna hanya dapat melihat histori pesan dari notifikasi yang diterima selama sesi Android Auto aktif. Untuk menampilkan pesan dari sebelum sesi Android Auto aktif dimulai, Anda dapat membuat pengalaman pesan berbasis template.
Untuk panduan desain terkait, lihat Aplikasi komunikasi di hub Desain untuk Mobil.
Memulai
Untuk menyediakan layanan pesan bagi Android Auto, aplikasi Anda harus mendeklarasikan dukungannya untuk Android Auto dalam manifes dan dapat melakukan hal berikut:
- Mendeklarasikan dukungan untuk Android Auto
- Buat dan kirim objek
NotificationCompat.MessagingStyleyang berisi objekActionbalas dan tandai sudah dibaca. - Menangani proses membalas pesan dan menandai percakapan sebagai sudah dibaca dengan
Service.
Konsep dan objek
Sebelum mulai mendesain aplikasi, sebaiknya pahami terlebih dahulu cara Android Auto menangani pesan.
Setiap bagian komunikasi disebut sebagai pesan dan direpresentasikan oleh
class MessagingStyle.Message. Pesan menyertakan informasi pengirim, isi pesan, dan waktu pengiriman.
Komunikasi antarpengguna disebut percakapan dan direpresentasikan oleh
objek MessagingStyle. Percakapan, atau MessagingStyle, berisi judul,
pesan, dan apakah percakapan merupakan bagian dari grup pengguna.
Untuk memberi tahu pengguna tentang informasi baru dalam percakapan, seperti pesan baru, aplikasi akan memposting
Notification ke sistem Android. Notification ini menggunakan objek
MessagingStyle untuk menampilkan UI khusus pesan di menu
notifikasi. Platform Android juga meneruskan Notification ini ke Android Auto, kemudian MessagingStyle diekstrak dan digunakan untuk memposting notifikasi di layar mobil.
Android Auto juga mengharuskan aplikasi menambahkan objek Action ke Notification agar pengguna dapat membalas pesan atau menandainya sebagai telah dibaca, langsung dari layar mobil.
Singkatnya, satu percakapan direpresentasikan oleh objek Notification yang diberi gaya dengan objek MessagingStyle. MessagingStyle berisi semua pesan dalam percakapan tersebut di satu atau beberapa objek MessagingStyle.Message. Agar mematuhi Android Auto, aplikasi harus melampirkan objek Action balas dan tandai telah dibaca ke Notification.
Alur pesan
Bagian ini menjelaskan alur pesan standar antara aplikasi Anda dan Android Auto.
- Aplikasi Anda menerima pesan.
- Aplikasi membuat notifikasi
MessagingStyledengan objekActionbalas dan tandai telah dibaca. - Android Auto menerima peristiwa "notifikasi baru" dari sistem Android
serta menemukan
MessagingStyle,Actionbalas, danActiontandai telah dibaca. - Android Auto menghasilkan dan menampilkan notifikasi di mobil.
- Jika pengguna mengetuk notifikasi di layar mobil, Android Auto
akan memicu
Actiontandai telah dibaca.- Di latar belakang, aplikasi Anda harus menangani peristiwa tandai sudah dibaca ini.
- Jika pengguna merespons notifikasi menggunakan suara, Android Auto akan menempatkan
transkripsi respons pengguna ke dalam
Actionbalas, lalu memicunya.- Di latar belakang, aplikasi Anda harus menangani peristiwa balas ini.
Asumsi awal
Halaman ini tidak memandu Anda dalam membuat seluruh aplikasi pesan. Contoh kode berikut menyertakan beberapa hal yang dibutuhkan aplikasi Anda sebelum Anda mulai mendukung pesan dengan 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)
Mendeklarasikan dukungan Android Auto
Saat menerima notifikasi dari aplikasi pesan, Android Auto akan memeriksa apakah aplikasi tersebut telah mendeklarasikan dukungan untuk Android Auto atau belum. Untuk memungkinkan dukungan ini, sertakan entri berikut dalam manifes aplikasi Anda:
<application>
...
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
Entri manifes ini mengacu pada file XML lain, automotive_app_desc.xml, yang
perlu Anda buat di direktori res/xml modul aplikasi. Di
automotive_app_desc.xml, deklarasikan kemampuan Android Auto yang didukung
aplikasi Anda. Untuk mendeklarasikan dukungan untuk notifikasi, sertakan hal berikut:
<automotiveApp>
<uses name="notification" />
</automotiveApp>
Jika aplikasi Anda dapat ditetapkan sebagai pengendali SMS default, pastikan untuk menyertakan
elemen <uses> berikut. Jika tidak, Android Auto akan menggunakan pengendali default bawaannya untuk menangani pesan SMS/MMS yang masuk saat aplikasi Anda ditetapkan sebagai pengendali SMS default, yang dapat menyebabkan notifikasi duplikat.
<automotiveApp>
...
<uses name="sms" />
</automotiveApp>
Mengimpor library inti AndroidX
Membuat notifikasi untuk digunakan dengan Android Auto memerlukan library inti AndroidX. Impor library ke project Anda sebagai berikut:
- Di file
build.gradletingkat atas, sertakan dependensi pada repositori Maven Google, seperti ditunjukkan pada contoh berikut:
Groovy
allprojects { repositories { google() } }
Kotlin
allprojects { repositories { google() } }
- Dalam file
build.gradlemodul aplikasi, sertakan dependensi library AndroidX Core, seperti ditunjukkan dalam contoh berikut:
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") }
Menangani tindakan pengguna
Aplikasi pesan memerlukan cara untuk menangani pembaruan percakapan melalui
Action. Untuk Android Auto, ada dua jenis objek Action yang perlu ditangani
oleh aplikasi Anda: balas dan tandai sudah dibaca. Sebaiknya tangani menggunakan
IntentService, yang memberikan fleksibilitas untuk menangani panggilan yang berpotensi
makin mahal di latar belakang sehingga membebaskan thread utama aplikasi Anda.
Menentukan tindakan intent
Tindakan Intent adalah string dasar pilihan Anda yang mengidentifikasi kegunaan
Intent. Karena satu layanan dapat menangani beberapa jenis intent,
akan lebih mudah untuk menentukan beberapa string tindakan daripada menentukan beberapa
komponen IntentService.
Contoh aplikasi pesan dalam panduan ini memiliki dua jenis tindakan yang diperlukan: balas dan tandai telah dibaca, seperti ditunjukkan pada contoh kode berikut:
private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"
Membuat layanan
Untuk membuat layanan yang menangani objek Action ini, Anda memerlukan
ID percakapan, yang merupakan struktur data arbitrer yang ditentukan oleh aplikasi Anda yang
mengidentifikasi percakapan. Anda juga memerlukan kunci input jarak jauh, yang akan dibahas secara mendetail di bagian ini nanti. Contoh kode berikut membuat
layanan untuk menangani tindakan yang diperlukan:
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()
}
}
}
Untuk mengaitkan layanan ini dengan aplikasi Anda, Anda juga perlu mendaftarkan layanan dalam manifes aplikasi, seperti ditunjukkan dalam contoh berikut:
<application>
<service android:name="com.example.MessagingService" />
...
</application>
Membuat dan menangani intent
Aplikasi lain, termasuk Android Auto, tidak dapat memperoleh Intent yang memicu
MessagingService karena intent diteruskan ke aplikasi lain melalui
PendingIntent. Karena batasan ini, buat objek RemoteInput
agar aplikasi lain dapat memberikan teks balasan ke aplikasi Anda, seperti yang ditunjukkan dalam
contoh berikut:
/**
* 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
}
Dalam klausa tombol ACTION_REPLY dalam MessagingService, ekstrak
informasi yang masuk ke Intent balas, seperti ditunjukkan dalam
contoh berikut:
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)
}
Anda menangani Intent tandai telah dibaca dengan cara yang sama. Namun, metode ini tidak
memerlukan RemoteInput, seperti ditunjukkan dalam contoh berikut:
/** 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
}
Klausa tombol ACTION_MARK_AS_READ dalam MessagingService tidak memerlukan
logika lebih lanjut, seperti ditunjukkan dalam contoh berikut:
// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()
Memberitahukan pesan kepada pengguna
Setelah penanganan tindakan percakapan selesai, langkah berikutnya adalah membuat notifikasi yang mematuhi Android Auto.
Membuat tindakan
Objek Action dapat diteruskan ke aplikasi lain menggunakan Notification untuk memicu
metode di aplikasi asli. Ini adalah cara Android Auto dapat menandai percakapan sebagai
sudah dibaca atau membalasnya.
Untuk membuat Action, mulailah dengan Intent. Contoh berikut menunjukkan cara membuat Intent "balas" menggunakan metode createReplyIntent() dari bagian sebelumnya:
fun createReplyAction(
context: Context, appConversation: YourAppConversation): Action {
val replyIntent: Intent = createReplyIntent(context, appConversation)
// ...
Selanjutnya, gabungkan Intent ini dalam PendingIntent yang menyiapkannya untuk penggunaan
aplikasi eksternal. PendingIntent mengunci semua akses ke Intent yang digabungkan hanya
dengan mengekspos sekumpulan metode tertentu yang memungkinkan aplikasi penerima mengaktifkan
Intent atau mendapatkan nama paket aplikasi asal. Aplikasi eksternal tidak dapat
mengakses Intent yang mendasarinya atau data di dalamnya.
// ...
val replyPendingIntent = PendingIntent.getService(
context,
createReplyId(appConversation), // Method explained later.
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
// ...
Sebelum menyiapkan Action balas, perlu diketahui bahwa Android Auto memiliki tiga
persyaratan untuk Action balas:
- Tindakan semantik harus ditetapkan ke
Action.SEMANTIC_ACTION_REPLY. Actionharus menunjukkan bahwa antarmuka pengguna tidak akan ditampilkan saat diaktifkan.Actionharus berisi satuRemoteInput.
Contoh kode berikut menyiapkan Action balas yang memenuhi
persyaratan yang tercantum sebelumnya:
// ...
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
}
Penanganan tindakan tandai sudah dibaca serupa, tetapi tidak ada RemoteInput.
Oleh karena itu, Android Auto memiliki dua persyaratan untuk Action tandai sudah dibaca:
- Tindakan semantik ditetapkan ke
Action.SEMANTIC_ACTION_MARK_AS_READ. - Tindakan tersebut menunjukkan bahwa antarmuka pengguna tidak akan ditampilkan saat diaktifkan.
Contoh kode berikut menyiapkan Action tandai sudah dibaca yang memenuhi
persyaratan ini:
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
}
Saat membuat intent yang tertunda, Anda menggunakan dua metode: createReplyId() dan createMarkAsReadId(). Metode ini berfungsi sebagai kode permintaan untuk setiap
PendingIntent, yang digunakan oleh Android untuk mengontrol intent tertunda yang ada.
Metode create() harus menampilkan ID unik untuk setiap percakapan, tetapi
panggilan berulang untuk percakapan yang sama harus menampilkan ID unik yang sudah
dibuat.
Pertimbangkan contoh dengan dua percakapan, A dan B: ID balasan Percakapan A adalah 100, dan ID tandai sudah dibaca adalah 101. ID balasan Percakapan B adalah 102, dan
ID tandai sudah dibaca adalah 103. Jika percakapan A diperbarui, ID balas dan tandai sudah dibaca tetap 100 dan 101. Untuk mengetahui informasi selengkapnya, lihat
PendingIntent.FLAG_UPDATE_CURRENT.
Membuat MessagingStyle
MessagingStyle adalah operator informasi pesan yang digunakan oleh Android
Auto untuk membaca setiap pesan dalam percakapan dengan keras.
Pertama, Anda harus menentukan pengguna perangkat sebagai objek Person, seperti
yang ditunjukkan dalam contoh berikut:
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()
// ...
Lalu, Anda dapat membuat objek MessagingStyle dan menambahkan beberapa detail
tentang percakapan.
// ...
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)
// ...
Terakhir, tambahkan pesan yang belum dibaca.
// ...
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
}
Memaketkan dan mengirim notifikasi
Setelah membuat objek Action dan MessagingStyle, Anda dapat membuat
dan memposting 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)
}
Referensi lainnya
Melaporkan masalah notifikasi pesan Android Auto
Jika mengalami masalah dengan pengembangan notifikasi pesan untuk Android Auto, Anda dapat melaporkannya menggunakan Issue Tracker Google. Pastikan untuk mengisi semua informasi yang diminta pada template masalah.
Sebelum mengajukan masalah baru, periksa apakah masalah tersebut sudah dilaporkan dalam daftar masalah. Anda bisa berlangganan dan memberi suara pada masalah dengan mengklik bintang untuk masalah di tracker. Untuk mengetahui informasi selengkapnya, lihat Berlangganan pada topik Masalah.