Mesajlaşma üzerinden bağlantıda kalmak birçok sürücü için önemlidir. Chat uygulamaları, kullanıcıların bir çocuğun okuldan alınması gerektiğini veya akşam yemeği yerinin değiştirildiğini öğrenmesine olanak tanıyabilir. Android çerçevesi, sürücülerin gözlerini yoldan ayırmamasını sağlayan standart bir kullanıcı arayüzü kullanarak mesajlaşma uygulamalarının hizmetlerini sürüş deneyimine genişletmesine olanak tanır.
Mesajlaşmayı destekleyen uygulamalar, mesajlaşma bildirimlerini Android Auto çalışırken Android Auto'nun kullanmasına izin verecek şekilde genişletebilir. Bu bildirimler Otomatik modda gösterilir ve kullanıcıların mesajları tutarlı ve dikkat dağıtıcı olmayan bir arayüzde okumasına ve yanıtlamasına olanak tanır. MessagingStyle API'yi kullandığınızda Android Auto da dahil olmak üzere tüm Android cihazlar için optimize edilmiş mesaj bildirimleri alırsınız. Optimizasyonlar arasında mesaj bildirimleri için özelleştirilmiş bir kullanıcı arayüzü, iyileştirilmiş animasyonlar ve satır içi resim desteği yer alıyor.
Bu kılavuzda, kullanıcıya mesaj gösteren ve kullanıcının yanıtlarını alan bir uygulamanın (ör. sohbet uygulaması) mesaj görüntüleme ve yanıt alma işlemlerini bir Auto cihaza devretmesi için nasıl genişletileceği gösterilmektedir. İlgili tasarım kılavuzları için sürüş sırasında mesajlaşma uygulamalarına yönelik Design for Driving sitesine göz atın.
Başlayın
Auto cihazlar için mesajlaşma hizmeti sunmak istiyorsanız uygulamanızın manifest dosyasında Android Auto desteğini belirtmesi ve aşağıdakileri yapabilmesi gerekir:
- Yanıt ve okunmuş olarak işaretle
Action
nesneleri içerenNotificationCompat.MessagingStyle
nesneleri oluşturup gönderin. - İleti dizilerini yanıtlama ve
Service
ile okundu olarak işaretleme işlemlerini gerçekleştirin.
Kavramlar ve nesneler
Uygulamanızı tasarlamaya başlamadan önce Android Auto'nun mesajlaşmayı nasıl işlediğini anlamanız faydalı olacaktır.
İletişimin tek bir parçasına mesaj adı verilir ve MessagingStyle.Message
sınıfıyla temsil edilir. İletiler göndereni, ileti içeriğini ve iletinin gönderildiği zamanı içerir.
Kullanıcılar arasındaki iletişime sohbet denir ve MessagingStyle
nesnesi ile temsil edilir. İleti dizisi veya MessagingStyle
, bir başlık, iletileri ve ileti dizisinin bir kullanıcı grubu arasında olup olmadığını içerir.
Uygulamalar, kullanıcıları bir ileti dizisindeki güncellemeler (ör. yeni mesaj) hakkında bilgilendirmek için Android sistemine Notification
yayınlar.
Bu Notification
, bildirim gölgesinde mesajlaşmaya özel kullanıcı arayüzünü görüntülemek için MessagingStyle
nesnesini kullanır. Android platformu bu Notification
i Android Auto'ya da iletir. MessagingStyle
, ayıklanır ve aracın ekranında bildirim yayınlamak için kullanılır.
Android Auto, kullanıcının bir mesajı hızlıca yanıtlamasına veya doğrudan bildirim gölgesinden okunmuş olarak işaretlemesine olanak tanımak için uygulamaların Notification
öğelerini Notification
'a eklemesini de zorunlu kılar.Action
Özet olarak, tek bir ileti dizisi MessagingStyle
nesnesi ile stillendirilmiş bir Notification
nesnesi ile temsil edilir. MessagingStyle
, bir veya daha fazla MessagingStyle.Message
nesnesinde ilgili ileti dizisindeki tüm iletileri içerir. Ayrıca, Android Auto ile uyumlu olmak için bir uygulamanın Notification
'a yanıt ve okunmuş olarak işaretle Action
nesneleri eklemesi gerekir.
Mesaj akışı
Bu bölümde, uygulamanız ile Android Auto arasındaki tipik mesaj akışı açıklanmaktadır.
- Uygulamanız bir ileti aldığında
- Uygulamanız, yanıt ve okunmuş olarak işaretle
Action
nesneleri içeren birMessagingStyle
bildirimi oluşturur. - Android Auto, Android sisteminden "yeni bildirim" etkinliğini alır ve
MessagingStyle
, yanıtlaAction
ve okunmuş olarak işaretleAction
seçeneklerini bulur. - Android Auto, araçta bildirim oluşturur ve gösterir.
- Kullanıcı, aracın ekranındaki bildirime dokunursa Android Auto, okunmuş olarak işaretle
Action
seçeneğini tetikler.- Uygulamanız, arka planda bu "okundu olarak işaretle" etkinliğini işlemelidir.
- Kullanıcı bildirime sesli olarak yanıt verirse Android Auto, kullanıcının yanıtının transkriptini yanıta
Action
ekler ve ardından yanıtı tetikler.- Uygulamanız, arka planda bu yanıt etkinliğini işlemelidir.
İlk varsayımlar
Bu sayfada, mesajlaşma uygulamasının tamamının nasıl oluşturulacağı açıklanmamaktadır. Aşağıdaki kod örneğinde, Android Auto ile mesajlaşmayı desteklemeye başlamadan önce uygulamanızın ihtiyaç duyduğu bazı öğeler yer almaktadır:
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)
Android Auto desteğini beyan etme
Android Auto, bir mesajlaşma uygulamasından bildirim aldığında uygulamanın Android Auto desteğini beyan edip etmediğini kontrol eder. Bu desteği etkinleştirmek için uygulamanızın manifest dosyasına aşağıdaki girişi ekleyin:
<application>
...
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
Bu manifest girişi, şu yolu kullanarak oluşturmanız gereken başka bir XML dosyasını ifade eder: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml
.
automotive_app_desc.xml
dosyasında, uygulamanızın desteklediği Android Auto özelliklerini belirtin. Örneğin, bildirimleri desteklediğinizi belirtmek için aşağıdakileri ekleyin:
<automotiveApp>
<uses name="notification" />
</automotiveApp>
Uygulamanız varsayılan SMS işleyici olarak ayarlanabiliyorsa aşağıdaki <uses>
öğesini eklediğinizden emin olun. Aksi takdirde, uygulamanız varsayılan SMS işleyici olarak ayarlandığında gelen SMS/MMS mesajlarını işlemek için Android Auto'ya yerleşik bir varsayılan işleyici kullanılır. Bu da yinelenen bildirimlere neden olabilir.
<automotiveApp>
...
<uses name="sms" />
</automotiveApp>
AndroidX çekirdek kitaplığını içe aktarma
Auto cihazlarla kullanılacak bildirimler oluşturmak için AndroidX çekirdek kitaplığı gerekir. Kitaplığı projenize aşağıdaki şekilde aktarın:
- Üst düzey
build.gradle
dosyasına, aşağıdaki örnekte gösterildiği gibi Google'ın Maven deposuna bağımlılık ekleyin:
Groovy
allprojects { repositories { google() } }
Kotlin
allprojects { repositories { google() } }
- Uygulama modülünüzün
build.gradle
dosyasına, aşağıdaki örnekte gösterildiği gibi AndroidX Core kitaplık bağımlılığını ekleyin:
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") }
Kullanıcı işlemlerini işleme
Mesajlaşma uygulamanızın, bir görüşmeyi Action
üzerinden güncellemenin bir yolunu bulması gerekir. Android Auto için uygulamanızın işlemesi gereken iki tür Action
nesnesi vardır: yanıtlama ve okunmuş olarak işaretleme. Bu işlemleri, IntentService
kullanarak gerçekleştirmenizi öneririz. Bu yöntem, pahalı olabilecek çağrıları arka planda işleme esnekliği sunarak uygulamanızın ana iş parçasını serbest bırakır.
Intent işlemlerini tanımlama
Intent
işlemleri, Intent
'ün ne işe yaradığını tanımlayan basit dizelerdir.
Tek bir hizmet birden fazla intent türünü işleyebileceğinden, birden fazla IntentService
bileşeni tanımlamak yerine birden fazla işlem dizesi tanımlamak daha kolaydır.
Bu kılavuzun örnek mesajlaşma uygulamasında, aşağıdaki kod örneğinde gösterildiği gibi yanıtlama ve okunmuş olarak işaretleme olmak üzere iki zorunlu işlem türü vardır.
private const val ACTION_REPLY = "com.example.REPLY"
private const val ACTION_MARK_AS_READ = "com.example.MARK_AS_READ"
Hizmeti oluşturun
Bu Action
nesnelerini işleyen bir hizmet oluşturmak için görüşme kimliğine ihtiyacınız vardır. Görüşme kimliği, uygulamanız tarafından tanımlanan ve görüşmeyi tanımlayan rastgele bir veri yapısıdır. Ayrıca, bu bölümde ayrıntılı olarak açıklanan uzaktan giriş anahtarına da ihtiyacınız vardır. Aşağıdaki kod örneği, gerekli işlemleri gerçekleştirmek için bir hizmet oluşturur:
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()
}
}
}
Bu hizmeti uygulamanızla ilişkilendirmek için hizmeti, aşağıdaki örnekte gösterildiği gibi uygulamanızın manifest dosyasına da kaydetmeniz gerekir:
<application>
<service android:name="com.example.MessagingService" />
...
</application>
Intent oluşturma ve işleme
Intent
'ler PendingIntent
aracılığıyla diğer uygulamalara iletildiğinden Android Auto da dahil olmak üzere diğer uygulamaların MessagingService
'yi tetikleyen Intent
'yi elde etmesi mümkün değildir. Bu sınırlama nedeniyle, diğer uygulamaların yanıt metnini uygulamanıza geri sağlamasına izin vermek için aşağıdaki örnekte gösterildiği gibi bir RemoteInput
nesnesi oluşturmanız gerekir:
/**
* 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
}
MessagingService
içindeki ACTION_REPLY
anahtarlama yan tümcesinde, aşağıdaki örnekte gösterildiği gibi yanıt Intent
'ye eklenen bilgileri ayıklayın:
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)
}
Okundu olarak işaretle Intent
seçeneğini de benzer şekilde kullanırsınız. Ancak aşağıdaki örnekte gösterildiği gibi RemoteInput
gerektirmez:
/** 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
}
MessagingService
içindeki ACTION_MARK_AS_READ
anahtarlama yan tümcesi için aşağıdaki örnekte gösterildiği gibi başka mantık gerekmez:
// Marking as read has no other logic.
ACTION_MARK_AS_READ -> conversation.markAsRead()
Kullanıcılara mesaj gönderme
İleti dizisi işleminin işlenmesi tamamlandıktan sonra, sonraki adım Android Auto uyumlu bildirimler oluşturmaktır.
İşlem oluşturma
Action
nesneleri, orijinal uygulamadaki yöntemleri tetiklemek için Notification
kullanılarak diğer uygulamalara iletilebilir. Android Auto, bir ileti dizisini okundu olarak işaretleyebilir veya yanıtlayabilir.
Action
oluşturmak için Intent
ile başlayın. Aşağıdaki örnekte, "yanıt" Intent
oluşturma işlemi gösterilmektedir:
fun createReplyAction(
context: Context, appConversation: YourAppConversation): Action {
val replyIntent: Intent = createReplyIntent(context, appConversation)
// ...
Ardından bu Intent
öğesini, harici uygulama kullanımına hazırlayan bir PendingIntent
içine yerleştirin. PendingIntent
, yalnızca alıcı uygulamanın Intent
'yi tetiklemesine veya kaynak uygulamanın paket adını almasına olanak tanıyan belirli bir yöntem grubunu göstererek sarmalanmış Intent
'ye tüm erişimi kilitler. Harici uygulama, temel Intent
'e veya içindeki verilere hiçbir zaman erişemez.
// ...
val replyPendingIntent = PendingIntent.getService(
context,
createReplyId(appConversation), // Method explained later.
replyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
// ...
Action
yanıtını oluşturmadan önce Android Auto'nun Action
yanıtı için üç koşulu olduğunu unutmayın:
- Anlamsal işlem
Action.SEMANTIC_ACTION_REPLY
olarak ayarlanmalıdır. Action
, etkinleştirildiğinde herhangi bir kullanıcı arayüzü göstermeyeceğini belirtmelidir.Action
, tek birRemoteInput
içermelidir.
Aşağıdaki kod örneği, yukarıda listelenen koşulları karşılayan bir yanıt Action
oluşturur:
// ...
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
}
Okundu olarak işaretle işleminin işlenmesi benzerdir. Tek fark, RemoteInput
olmamasıdır.
Bu nedenle Android Auto'nun okunmuş olarak işaretleme Action
için iki koşulu vardır:
- Anlamsal işlem
Action.SEMANTIC_ACTION_MARK_AS_READ
olarak ayarlanır. - İşlem, tetiklendiğinde herhangi bir kullanıcı arayüzü göstermeyeceğini belirtir.
Aşağıdaki kod örneği, aşağıdaki koşulları karşılayan bir "okundu olarak işaretle" Action
işlemi oluşturur:
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
}
Beklemedeki intent'ler oluşturulurken iki yöntem kullanılır:
createReplyId()
ve createMarkAsReadId()
. Bu yöntemler, Android tarafından bekleyen mevcut intent'leri kontrol etmek için kullanılan her PendingIntent
için istek kodları olarak işlev görür. create()
yöntemleri her sohbet için benzersiz kimlikler döndürmelidir ancak aynı sohbet için tekrarlanan çağrılar, önceden oluşturulmuş benzersiz kimliği döndürmelidir.
A ve B olmak üzere iki ileti dizisi içeren bir örnek düşünün: A ileti dizisinin yanıt kimliği 100, okunmuş olarak işaretleme kimliği ise 101'dir. B ileti dizisinin yanıt kimliği 102, okunmuş olarak işaretleme kimliği ise 103'tür. A ileti dizisi güncellenirse yanıt ve okunmuş olarak işaretle kimlikleri 100 ve 101 olarak kalır. Daha fazla bilgi için PendingIntent.FLAG_UPDATE_CURRENT
başlıklı makaleyi inceleyin.
MessagingStyle oluşturma
MessagingStyle
, mesajlaşma bilgilerinin taşıyıcısıdır ve Android Auto'nun bir görüşmedeki her mesajı sesli okumak için kullandığı şeydir.
Öncelikle, cihazın kullanıcısı aşağıdaki örnekte gösterildiği gibi bir Person
nesnesi biçiminde belirtilmelidir:
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()
// ...
Ardından MessagingStyle
nesnesini oluşturabilir ve sohbet hakkında bazı ayrıntılar sağlayabilirsiniz.
// ...
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)
// ...
Son olarak, okunmamış mesajları ekleyin.
// ...
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
}
Bildirimi paketleme ve gönderme
Action
ve MessagingStyle
nesnelerini oluşturduktan sonra Notification
öğesini derleyip yayınlayabilirsiniz.
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)
}
Ek kaynaklar
Android Auto Mesajlaşma ile ilgili sorunları bildirme
Android Auto için mesajlaşma uygulamanızı geliştirirken sorunla karşılaşırsanız Google Sorun Takip Aracı'nı kullanarak sorunu bildirebilirsiniz. Sorun şablonunda istenen tüm bilgileri doldurduğunuzdan emin olun.
Yeni bir sorun bildirmeden önce, sorunun sorun listesinde bildirilip bildirilmediğini kontrol edin. İzleyicideki bir sorunun yıldızını tıklayarak sorunlara abone olabilir ve oy verebilirsiniz. Daha fazla bilgi için Bir soruna abone olma başlıklı makaleyi inceleyin.