Android Auto için mesajlaşma uygulamaları geliştirme

İletişim kategorisi yakında kullanıma sunulacak
Mesajlaşma kategorisi, mesaj geçmişi ve görüşme deneyimleri de dahil olmak üzere yeni özellikler için destek içerecek şekilde genişletiliyor

Mesajlar üzerinden iletişim kurmak birçok sürücü için önemlidir. Chat uygulamaları, kullanıcılara bir çocuğun gelmesi gerekip gerekmediğini veya akşam yemeği konumunun değişip değişmediğini bildirebilir. Android çerçevesi, sürücülerin gözlerini yoldan ayırmamasını sağlayan standart bir kullanıcı arayüzü aracılığıyla mesajlaşma uygulamalarının hizmetlerini sürüş deneyimine genişletmesini sağlar.

Mesajlaşmayı destekleyen uygulamalar, Android Auto'nun Auto çalışırken bunları kullanmasına izin vermek için mesajlaşma bildirimlerinin kapsamını genişletebilir. Bu bildirimler Otomatik'te gösterilir ve kullanıcıların mesajları tutarlı, dikkat dağıtıcı bir arayüzde okuyup yanıtlamasını sağlar. MessagingStyle API'yi kullandığınızda, Android Auto dahil tüm Android cihazlar için optimize edilmiş mesaj bildirimleri alırsınız. Optimizasyonlar; mesaj bildirimleri, iyileştirilmiş animasyonlar ve satır içi resim desteği için uzmanlaşmış bir kullanıcı arayüzü içeriyor.

Bu kılavuzda, kullanıcıya mesaj gösteren ve kullanıcının yanıtlarını (ör. sohbet uygulaması) alan bir uygulamanın mesaj görüntüleme ve yanıtlama makbuzunu bir Auto cihaza aktarmak için nasıl genişletileceği gösterilmektedir. İlgili tasarım kılavuzu için Sürüş için Tasarım sitesindeki Mesajlaşma uygulamaları'na bakın.

Başlayın

Auto cihazlara mesajlaşma hizmeti sağlamak için uygulamanızın, manifest dosyasında Android Auto'yu desteklediğini beyan etmesi ve aşağıdakileri yapabilmesi gerekir:

Kavramlar ve nesneler

Uygulamanızı tasarlamaya başlamadan önce, Android Auto'nun mesajları nasıl işlediğini anlamanız faydalı olacaktır.

Tek bir iletişim parçasına mesaj adı verilir ve bu parça, MessagingStyle.Message sınıfıyla temsil edilir. Bir ileti göndereni, iletinin içeriğini ve mesajın gönderilme zamanını içerir.

Kullanıcılar arasındaki iletişim ileti dizisi olarak adlandırılır ve MessagingStyle nesnesiyle temsil edilir. Bir ileti dizisi veya MessagingStyle; başlığı, mesajları ve görüşmenin bir kullanıcı grubu arasında olup olmadığını içerir.

Uygulamalar, bir görüşmede yapılan yeni mesaj gibi güncellemeleri kullanıcılara bildirmek için Android sistemine bir Notification gönderir. 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 da bu Notification bilgisini Android Auto'ya iletir. Ardından MessagingStyle çıkarılıp arabanın ekranından bildirim yayınlamak için kullanılır.

Android Auto, kullanıcının bir mesajı hızlıca yanıtlayabilmesi veya doğrudan bildirim gölgesinden okundu olarak işaretlenebilmesi için uygulamaların Notification öğesine Action nesneleri eklemesini de gerektirir.

Özetle, tek bir ileti dizisi, stili MessagingStyle nesnesine sahip Notification nesnesiyle temsil edilir. MessagingStyle, bir veya daha fazla MessagingStyle.Message nesnede bu ileti dizisindeki tüm mesajları içerir. Ayrıca, uygulamaların Android Auto ile uyumlu olması için Notification öğesine yanıt ve okundu olarak işaretle Action nesnelerini eklemesi gerekir.

Mesajlaşma akışı

Bu bölümde, uygulamanız ile Android Auto arasındaki tipik bir mesajlaşma akışı açıklanmaktadır.

  1. Uygulamanız bir mesaj alır.
  2. Uygulamanız, yanıt ve okundu olarak işaretle Action nesneleri içeren bir MessagingStyle bildirimi oluşturur.
  3. Android Auto, Android sisteminden "yeni bildirim" etkinliğini alarak MessagingStyle, yanıtla Action ve okundu olarak işaretle Action özelliklerini bulur.
  4. Android Auto, arabada bir bildirim oluşturup görüntüler.
  5. Kullanıcı araba ekranındaki bildirime dokunursa Android Auto, okundu olarak işaretleme Action özelliğini tetikler.
    • Arka planda, uygulamanız bu okundu olarak işaretleme etkinliğini işlemelidir.
  6. Kullanıcı bildirime ses kullanarak yanıt verirse Android Auto, kullanıcının yanıtının transkriptini Action yanıtına ekler ve ardından tetikler.
    • Arka planda, uygulamanızın bu yanıtlama etkinliğini işlemesi gerekir.

Ön varsayımlar

Bu sayfa, bir mesajlaşma uygulamasının tamamını oluşturma konusunda size yol göstermemektedir. Aşağıdaki kod örneği, Android Auto ile mesajlaşmayı desteklemeye başlamadan önce uygulamanızın ihtiyaç duyduğu şeylerden bazılarını içerir:

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'yu desteklediğ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 yolla oluşturmanız gereken başka bir XML dosyasına başvurur: YourAppProject/app/src/main/res/xml/automotive_app_desc.xml. automotive_app_desc.xml içinde, uygulamanızın desteklediği Android Auto özelliklerini beyan edin. Örneğin, bildirimleri desteklediğinizi beyan etmek 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. Bunu yapmazsanız uygulamanız varsayılan SMS işleyici olarak ayarlandığında, gelen SMS/MMS mesajlarını işlemek için Android Auto'da yerleşik olarak bulunan varsayılan işleyici kullanılır. Bu da yinelenen bildirimlere yol açabilir.

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

AndroidX temel kitaplığını içe aktarma

Auto cihazlarla kullanılmak üzere bildirim oluşturmak için AndroidX temel kitaplığı gerekir. Kitaplığı, aşağıdaki adımları uygulayarak projenize aktarın:

  1. Üst düzey build.gradle dosyasına, aşağıdaki örnekte gösterildiği gibi Google'ın Maven deposuna bir bağımlılık ekleyin:

Modern

allprojects {
    repositories {
        google()
    }
}

Kotlin

allprojects {
    repositories {
        google()
    }
}
  1. Uygulama modülünüzün build.gradle dosyasında, aşağıdaki örnekte gösterildiği gibi AndroidX Core kitaplık bağımlılığını ekleyin:

Modern

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

Kullanıcı işlemlerini işleme

Mesajlaşma uygulamanız, görüşmenin Action üzerinden güncellenebilmesi için bir yönteme ihtiyaç duyuyor. Android Auto için uygulamanızın işlemesi gereken iki tür Action nesnesi vardır: yanıtla ve okundu olarak işaretle. Yüksek maliyetli aramaları arka planda yönetme esnekliği sunan ve uygulamanızın ana iş parçacığını serbest bırakan IntentService kullanarak bunları ele almanızı öneririz.

Amaç işlemlerini tanımlayın

Intent işlemleri, Intent öğesinin ne işe yaradığını tanımlayan basit dizelerdir. Tek bir hizmet birden fazla amaç türünü işleyebileceğinden birden fazla IntentService bileşeni tanımlamak yerine birden çok işlem dizesi tanımlamak daha kolaydır.

Bu kılavuzun örnek mesajlaşma uygulaması, aşağıdaki kod örneğinde gösterildiği gibi zorunlu iki işlem türüne sahiptir: yanıtla ve okundu olarak işaretle.

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

Hizmeti oluşturma

Bu Action nesnelerini işleyen bir hizmet oluşturmak için konuşma kimliğine ihtiyacınız vardır. Bu, uygulamanız tarafından tanımlanan ve konuşmayı tanımlayan rastgele bir veri yapısıdır. Ayrıca, bu bölümün ilerleyen kısımlarında ayrıntılı olarak açıkladığımız bir uzak giriş anahtarına da ihtiyacınız vardır. Aşağıdaki kod örneği, gerekli işlemleri yapmak 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 aşağıdaki örnekte gösterildiği gibi, hizmeti uygulamanızın manifest dosyasına da kaydetmeniz gerekir:

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

Amaç oluşturma ve işleme

Intent öğeleri bir PendingIntent aracılığıyla diğer uygulamalara aktarıldığından, Android Auto dahil olmak üzere diğer uygulamaların MessagingService işlemini tetikleyen Intent'yi alması mümkün değildir. Bu sınırlama nedeniyle, aşağıdaki örnekte gösterildiği gibi, diğer uygulamaların yanıt metnini uygulamanıza geri sağlaması için 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
}

Aşağıdaki örnekte gösterildiği gibi, MessagingService içindeki ACTION_REPLY Switch ifadesinde, Intent yanıtına giren bilgileri çıkarı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şaretleme Intent için de aynı şekilde işlem yaparsınız. Ancak aşağıdaki örnekte gösterildiği gibi bu 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
}

Aşağıdaki örnekte gösterildiği gibi MessagingService içindeki ACTION_MARK_AS_READ geçiş ifadesi başka bir mantık gerektirmez:

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

Mesajları kullanıcılara bildirme

Görüşme işleminin işlenmesi tamamlandıktan sonraki adım, Android Auto ile uyumlu bildirimler oluşturmaktır.

İşlem oluştur

Orijinal uygulamada yöntemleri tetiklemek için Notification kullanılarak diğer uygulamalara Action nesne aktarılabilir. Android Auto bir görüşmeyi bu şekilde okundu veya yanıtlandı olarak işaretleyebilir.

Action oluşturmak için Intent ile başlayın. Aşağıdaki örnekte, nasıl "yanıt" Intent oluşturulacağı gösterilmektedir:

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

Ardından bu Intent öğesini, harici uygulama kullanımı için hazırlayan bir PendingIntent içine sarmalayın. PendingIntent, yalnızca alıcı uygulamanın Intent öğesini tetiklemesine veya kaynak uygulamanın paket adını almasına izin veren belirli bir dizi yöntemi göstererek sarmalanmış Intent öğesine tüm erişimi kilitler. Harici uygulama, temeldeki Intent öğesine 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ı ayarlamadan önce, Android Auto'nun Action yanıtı için üç gereksinimi olduğunu unutmayın:

  • Anlamsal işlem Action.SEMANTIC_ACTION_REPLY olarak ayarlanmalıdır.
  • Action, tetiklendiğinde herhangi bir kullanıcı arayüzü göstermeyeceğini belirtmelidir.
  • Action, tek bir RemoteInput içermelidir.

Aşağıdaki kod örneği, yukarıda listelenen gereksinimleri karşılayan bir Action yanıtı oluşturmaktadır:

    // ...
    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şlemi, RemoteInput özelliğinin olmaması dışında benzer şekilde işlenir. Bu nedenle Android Auto'nun okundu olarak işaretleme Action için iki gereksinimi vardır:

  • Anlamsal işlem Action.SEMANTIC_ACTION_MARK_AS_READ olarak ayarlandı.
  • Bu işlem, tetiklendiğinde herhangi bir kullanıcı arayüzü göstermeyeceğini belirtiyor.

Aşağıdaki kod örneği, bu gereksinimleri ele alan bir okundu olarak işaretle Action özelliğini ayarlar:

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 amaçlar oluşturulurken, iki yöntem kullanılır: createReplyId() ve createMarkAsReadId(). Bu yöntemler, her bir PendingIntent için istek kodu görevi görür. Android bu kodları, mevcut bekleyen amaçları kontrol etmek amacıyla kullanır. create() yöntemleri her görüşme için benzersiz kimlikler döndürmelidir ancak aynı görüşme 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 örneği ele alalım: İleti dizisinin A'nın yanıt kimliği 100, okundu olarak işaretleme kimliği ise 101'dir. Görüşme B'nin yanıt kimliği 102 ve okundu olarak işaretleme kimliği 103'tür. İleti dizisi A güncellenirse yanıt ve okundu olarak işaretleme kimlikleri hâlâ 100 ve 101 olur. Daha fazla bilgi için PendingIntent.FLAG_UPDATE_CURRENT adresini inceleyin.

MessagingStyle oluşturma

Mesajlaşma bilgileri için operatör MessagingStyle ve Android Auto, bir görüşmedeki her mesajı sesli okumak için bunu kullanır.

Öncelikle, cihazın kullanıcısı aşağıdaki örnekte gösterildiği gibi 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()
    // ...

Daha sonra, MessagingStyle nesnesini oluşturabilir ve görüşme 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ış iletileri 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
}

Paketleyin ve bildirimi aktarın

Action ve MessagingStyle nesnelerini oluşturduktan sonra Notification öğesini oluşturup 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 sorunu bildir

Android Auto için mesajlaşma uygulamanızı geliştirirken bir sorunla karşılaşırsanız Google Issue Tracker'ı kullanarak bu sorunu bildirebilirsiniz. Sorun şablonunda istenen tüm bilgileri doldurduğunuzdan emin olun.

Yeni sayı oluşturma

Yeni bir sorun bildirmeden önce, sorunun zaten sorunlar listesinde bildirilip bildirilmediğini kontrol edin. İzleyicideki bir sorunla ilgili yıldızı tıklayarak abone olabilir ve sorunlar için oy verebilirsiniz. Daha fazla bilgi için Bir soruna abone olma bölümüne bakın.