Tetap terhubung melalui pesan menjadi kebutuhan penting bagi banyak pengemudi. Aplikasi chat dapat memberi tahu pengguna jika ada anak yang perlu dijemput atau jika lokasi makan malam berubah. Framework Android memungkinkan aplikasi pesan memperluas layanannya ke dalam pengalaman mengemudi menggunakan antarmuka pengguna standar yang memungkinkan pengemudi tetap memfokuskan perhatian ke jalan.
Aplikasi yang mendukung pesan dapat mengirim notifikasi pesannya ke Android Auto untuk digunakan saat Auto sedang berjalan. Notifikasi ini ditampilkan di Auto dan memungkinkan pengguna untuk 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 perangkat Auto. Untuk panduan desain terkait, lihat Aplikasi pesan di situs Design for Driving.
Memulai
Untuk menyediakan layanan pesan bagi perangkat Auto, aplikasi Anda harus mendeklarasikan dukungannya untuk Android Auto dalam manifes dan dapat melakukan hal berikut:
- Membuat dan mengirim
objek
NotificationCompat.MessagingStyle
yang berisi objekAction
balas 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
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 melalui layar di mobil.
Android Auto juga mengharuskan aplikasi menambahkan objek Action
ke Notification
agar
pengguna dapat membalas pesan dengan cepat atau menandainya sebagai telah dibaca, langsung dari
menu notifikasi.
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
MessagingStyle
dengan objekAction
balas dan tandai telah dibaca. - Android Auto menerima peristiwa “notifikasi baru” dari sistem Android
serta menemukan
MessagingStyle
,Action
balas, danAction
tandai telah dibaca. - Android Auto menghasilkan dan menampilkan notifikasi di mobil.
- Jika pengguna mengetuk notifikasi di layar mobil, Android Auto
akan memicu
Action
tandai 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
Action
balas, 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 merujuk ke file XML lain yang perlu Anda buat dengan
jalur berikut: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml
.
Di automotive_app_desc.xml
, deklarasikan kemampuan Android Auto yang didukung
aplikasi Anda. Misalnya, guna 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, pengendali
default bawaan Android Auto akan digunakan 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 perangkat Auto memerlukan library inti AndroidX. Impor library ke project Anda sebagai berikut:
- Di file
build.gradle
tingkat atas, sertakan dependensi pada repositori Maven Google, seperti ditunjukkan pada contoh berikut:
Groovy
allprojects { repositories { google() } }
Kotlin
allprojects { repositories { google() } }
- Dalam file
build.gradle
modul 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.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") }
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 sederhana 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
Tidak ada cara bagi aplikasi lain, termasuk Android Auto, untuk mendapatkan Intent
yang memicu MessagingService
, karena Intent
diteruskan ke aplikasi lain
melalui PendingIntent
. Karena
batasan ini, Anda perlu membuat objek RemoteInput
agar aplikasi lain dapat mengembalikan teks balasan ke aplikasi Anda, seperti 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 telah dibaca atau membalasnya.
Untuk membuat Action
, mulailah dengan Intent
. Contoh berikut menunjukkan
cara membuat Intent
"balas":
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 akan 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
. Action
harus menunjukkan bahwa antarmuka pengguna tidak akan ditampilkan saat diaktifkan.Action
harus berisi satuRemoteInput
.
Contoh kode berikut menyiapkan Action
balas yang memenuhi
persyaratan yang tercantum di atas:
// ...
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 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
}
Saat membuat intent yang tertunda, ada dua metode yang digunakan:
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 diupdate,
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, pengguna perangkat harus ditentukan dalam bentuk objek
Person
, seperti 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 Fitur Pesan Android Auto
Jika mengalami masalah dengan pengembangan aplikasi 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.