Bạn không thể cài đặt trực tiếp các ứng dụng nhắn tin mới và hiện có dưới dạng ứng dụng được tối ưu hoá cho người lái xenon trên android automotive bone. Các ứng dụng này chỉ có thể được phân phối thông qua android car. Để biết thêm thông can, hãy xem phần Danh mục ứng dụng được hỗ trợ
Để cung cấp dịch vụ nhắn can cho thiết bị car, ứng dụng của bạn phải khai báo tính năng hỗ trợ android car trong tệp kê khai và có thể thực hiện những tác vụ sau :
NotificationCompat.MessagingStyle
chứa các đối tượng Action
trả lời và đánh dấu là đã đọc.Service
. Trước chi bắt đầu thiết kế ứng dụng, bạn cần nắm được cách android car xử lý thao tác nhắn canister .
Một đoạn thông tin trao đổi riêng lẻ được gọi là canister nhắn và được biểu thị bằng lớp MessagingStyle.Message
. can nhắn chứa người gửi, nội dung tin nhắn và thời gian gửi can nhắn .
Hoạt động giao tiếp giữa những người dùng được gọi là cuộc trò chuyện và được biểu thị bằng đối tượng MessagingStyle
. Một cuộc trò chuyện ( MessagingStyle
) chứa tiêu đề, can nhắn và thông tin cho biết liệu đó có phải là cuộc trò chuyện giữa một nhóm người dùng hay không .
Để thông báo cho người dùng về nội dung cập nhật của cuộc trò chuyện ( chẳng hạn như một tin nhắn mới ), các ứng dụng sẽ đăng Notification
lên hệ thống android. Notification
này sử dụng đối tượng MessagingStyle
để hiển thị giao diện người dùng dành riêng cho tính năng nhắn can trong ngăn thông báo. Nền tảng android cũng truyền Notification
này whistle android car, còn MessagingStyle
được trích xuất và dùng để đăng thông báo qua màn hình của ô tô .
android car cũng yêu cầu ứng dụng thêm các đối tượng Action
vào Notification
để cho phép người dùng nhanh chóng trả lời tin nhắn hoặc đánh dấu tin nhắn là đã đọc trực tiếp trong ngăn thông báo .
Tóm lại, một cuộc trò chuyện được biểu thị bằng đối tượng Notification
. Đối tượng này được tạo kiểu bằng một đối tượng MessagingStyle
. MessagingStyle
chứa tất cả tin nhắn trong cuộc trò chuyện đó, trong một hoặc nhiều đối tượng MessagingStyle.Message
. Ngoài radium, để tương thích với android car, ứng dụng phải đính kèm đối tượng Action
trả lời và đánh dấu là đã đọc vào Notification
.
Phần này mô tả quy trình nhắn canister thông thường giữa ứng dụng của bạn và android car .
MessagingStyle
có các đối tượng Action
trả lời và đánh dấu là đã đọc.MessagingStyle
, Action
trả lời cũng như Action
đánh dấu là đã đọc.Action
đánh dấu là đã đọc.
Action
trả lời rồi kích hoạt đối tượng đó.
Trang này không hướng dẫn bạn cách tạo một ứng dụng nhắn tin hoàn chỉnh. Mã mẫu sau đây cho biết một số việc bạn cần thực hiện đối với ứng dụng của mình để có thể bắt đầu hỗ trợ tính năng nhắn can qua android car :
data class YourAppConversation(
val id: Int,
val title: String,
val recipients: MutableList,
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 { 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)
chi nhận được thông báo từ một ứng dụng nhắn can, android car sẽ kiểm tra để đảm bảo ứng dụng đó đã khai báo tính năng hỗ trợ android car. Để bật tính năng hỗ trợ này, hãy thêm mục sau vào tệp kê khai của ứng dụng :
...
...
Mục kê khai này là một tệp XML khác mà bạn cần tạo bằng đường dẫn sau : YourAppProject/app/src/main/res/xml/automotive_app_desc.xml
. Trong automotive_app_desc.xml
, hãy khai báo các tính năng của android car mà ứng dụng của bạn hỗ trợ. Ví dụ : để khai báo tính năng hỗ trợ cho thông báo, hãy thêm nội dung sau :
Nếu có thể đặt ứng dụng làm trình xử lý canister nhắn master of science mặc định, hãy nhớ thêm phần tử
sau. Nếu không, trình xử lý mặc định tích hợp trong android car sẽ xử lý tin nhắn SMS/MMS đến chi ứng dụng của bạn được đặt làm trình xử lý tin nhắn samarium mặc định. Điều này có thể dẫn đến thông báo trùng lặp .
...
chi tạo thông báo để sử dụng với thiết bị car, bạn phải có thư viện AndroidX congress of racial equality. Nhập thư viện này vào dự án của bạn theo cách dưới đây :
build.gradle
cấp cao nhất, hãy đưa phần phụ thuộc vào kho lưu trữ Maven của Google, như trong ví dụ sau:allprojects { repositories { google() } }
allprojects { repositories { google() } }
build.gradle
của mô-đun ứng dụng, hãy thêm phần phụ thuộc thư viện AndroidX Core, như trong ví dụ sau:dependencies { // If your app is written in Java implementation 'androidx.core:core:1.10.1' // If your app is written in Kotlin implementation 'androidx.core:core-ktx:1.10.1' }
dependencies { // If your app is written in Java implementation("androidx.core:core:1.10.1") // If your app is written in Kotlin implementation("androidx.core:core-ktx:1.10.1") }
Ứng dụng nhắn canister của bạn cần có cách thức xử lý thao tác cập nhật cuộc trò chuyện thông qua Action
. Đối với android car, ứng dụng của bạn cần xử lý two loại đối tượng Action
: trả lời và đánh dấu là đã đọc. Bạn nên xử lý các đối tượng này bằng IntentService
, cho phép bạn xử lý linh hoạt các lệnh gọi có khả năng tốn nhiều tài nguyên ở chế độ nền, giúp giải phóng luồng chính của ứng dụng .
Cảnh báo: Không sử dụng Activity
hoặc Fragment
để xử lý Action
. Chúng không chỉ chạy ở nền trước mà còn gây right ascension các sự cố về giao diện người dùng khiến ứng dụng của bạn bị chặn khỏi android car .
Thao tác Intent
là các chuỗi đơn giản xác định mục đích của Intent
. Vì một dịch vụ có thể xử lý nhiều loại ý định nên việc xác định nhiều chuỗi hành động thay vì xác định nhiều thành phần IntentService
sẽ dễ dàng hơn .
Ứng dụng nhắn tin trong hướng dẫn này có two loại thao tác bắt buộc : trả lời và đánh dấu là đã đọc, như minh hoạ trong mã mẫu sau .
private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"
Để tạo một dịch vụ xử lý những đối tượng Action
này, bạn cần có mã nhận dạng cuộc trò chuyện – một cấu trúc dữ liệu tuỳ ý do ứng dụng của bạn xác định để nhận dạng cuộc trò chuyện. Bạn cũng cần có một khoá nhập từ xa. Điều này sẽ được thảo luận qi tiết sau trong phần này. Mã mẫu sau đây sẽ tạo một dịch vụ để xử lý các hành động bắt buộc :
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()
}
}
}
Để liên kết dịch vụ này với ứng dụng của bạn, bạn cũng cần đăng ký dịch vụ trong tệp kê khai của ứng dụng, như trong ví dụ sau :
...
Các ứng dụng khác, bao gồm cả android car, không thể có được Intent
kích hoạt MessagingService
, vì Intent
được truyền đến các ứng dụng khác thông qua PendingIntent
. do giới hạn này, bạn cần tạo đối tượng RemoteInput
để cho phép các ứng dụng khác gửi văn bản trả lời về ứng dụng của bạn, như trong ví dụ sau :
/**
* 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
}
Trong mệnh đề chuyển đổi ACTION_REPLY
trong MessagingService
, hãy trích xuất thông tin chuyển đến Intent
trả lời, như trong ví dụ sau :
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)
}
Bạn sẽ xử lý Intent
đánh dấu là đã đọc theo cách tương tự. Tuy nhiên, đối tượng này không yêu cầu RemoteInput
, như trong ví dụ sau :
/** 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
}
Mệnh đề chuyển đổi ACTION_MARK_AS_READ
trong MessagingService
không cần thêm logic, như trong ví dụ sau :
// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()
Sau chi xử lý xong tác vụ cuộc hội thoại, bước tiếp theo là tạo thông báo tương thích với android car .
Bạn có thể chuyển đối tượng Action
đến các ứng dụng khác bằng Notification
để kích hoạt các phương thức trong ứng dụng bachelor of arts in nursing đầu. Đây là cách android car có thể đánh dấu cuộc trò chuyện là đã đọc hoặc trả lời cuộc trò chuyện đó .
Để tạo Action
, hãy bắt đầu bằng Intent
. Ví dụ sau cho biết cách tạo một Intent
“ trả lời ” :
fun createReplyAction(
context: Context, appConversation: YourAppConversation): Action {
val replyIntent: Intent = createReplyIntent(context, appConversation)
// ...
Sau đó, hãy gói Intent
này trong một PendingIntent
để chuẩn bị cho việc sử dụng ứng dụng bên ngoài. PendingIntent
sẽ chặn mọi quyền truy cập vào Intent
đã gói bằng cách chỉ hiển thị một nhóm phương thức chọn lọc cho phép ứng dụng nhận kích hoạt Intent
hoặc lấy tên gói của ứng dụng gốc. Ứng dụng bên ngoài tuyệt đối không truy cập được vào Intent
cơ bản hoặc dữ liệu có trong đó .
// ...
val replyPendingIntent = PendingIntent.getService(
context,
createReplyId(appConversation), // Method explained later.
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
// ...
Trước chi bạn thiết lập Action
trả lời, hãy lưu ý rằng android car có three yêu cầu đối với Action
trả lời :
Action.SEMANTIC_ACTION_REPLY
.Action
phải cho biết rằng khi được kích hoạt, thao tác này sẽ không hiển thị giao diện người dùng nào.Action
phải chứa một RemoteInput
duy nhất. Mã mẫu sau đây thiết lập một Action
trả lời đáp ứng các yêu cầu nêu trên :
// ...
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
}
Việc xử lý hành động đánh dấu là đã đọc cũng tương tự như vậy, ngoại trừ việc không có RemoteInput
. do đó, android car có two yêu cầu đối với Action
đánh dấu là đã đọc :
Action.SEMANTIC_ACTION_MARK_AS_READ
. Mã mẫu sau đây thiết lập một Action
đánh dấu là đã đọc, đáp ứng các yêu cầu sau :
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
}
chi tạo ý định đang chờ xử lý, bạn có thể dùng two hai phương thức sau : createReplyId()
và createMarkAsReadId()
. Các phương thức này đóng vai trò là mã yêu cầu cho từng PendingIntent
( được android sử dụng để kiểm soát các ý định đang chờ xử lý hiện có ). Các phương thức create()
phải trả về mã nhận dạng duy nhất cho mỗi cuộc trò chuyện, nhưng các lệnh gọi lặp lại cho cùng một cuộc trò chuyện phải trả về mã nhận dạng duy nhất đã tạo .
Hãy xem xét ví dụ với two cuộc trò chuyện, ampere và bacillus : Mã trả lời của cuộc trò chuyện ampere là hundred và mã đánh dấu là đã đọc là hundred and one. Mã trả lời của cuộc trò chuyện boron là 102 và mã đánh dấu là đã đọc là 103. Nếu cuộc trò chuyện adenine được cập nhật, thì mã trả lời vẫn là hundred và mã đánh dấu là đã đọc vẫn là hundred and one. Để biết thêm thông tin, hãy xem PendingIntent.FLAG_UPDATE_CURRENT
.
MessagingStyle
là phần tử mang thông tin nhắn tin. android car sử dụng phần tử này để đọc to từng can nhắn trong một cuộc trò chuyện .
Trước tiên, bạn phải chỉ định người dùng thiết bị ở dạng đối tượng Person
, như trong ví dụ sau :
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()
// ...
Sau đó, bạn có thể tạo đối tượng MessagingStyle
và cung cấp một số thông canister qi tiết về cuộc trò chuyện .
// ...
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)
// ...
Cuối cùng, hãy thêm các tin nhắn chưa đọc .
// ...
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
}
Sau chi tạo các đối tượng Action
và MessagingStyle
, bạn có thể tạo và đăng 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)
}
Nếu gặp sự cố trong chi phát triển ứng dụng nhắn canister cho android car, bạn có thể báo cáo sự cố đó bằng Công cụ theo dõi lỗi của google. Hãy nhớ điền tất cả thông tin được yêu cầu vào mẫu báo cáo lỗi .
Báo lỗi mới
Trước chi báo lỗi mới, hãy kiểm tra xem lỗi đó đã được báo cáo trong danh sách lỗi hay chưa. Bạn có thể đăng ký theo dõi và bình chọn cho các lỗi bằng cách nhấp vào dấu sao cho một lỗi trong công cụ theo dõi. Để biết thêm thông tin, hãy xem bài viết Đăng ký theo dõi lỗi .