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 arama deneyimleri gibi yeni özellikler için destek içerecek şekilde genişletiliyor

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çeren NotificationCompat.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 Notificationi 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.

  1. Uygulamanız bir ileti aldığında
  2. Uygulamanız, yanıt ve okunmuş olarak işaretle Action nesneleri içeren bir MessagingStyle bildirimi oluşturur.
  3. Android Auto, Android sisteminden "yeni bildirim" etkinliğini alır ve MessagingStyle, yanıtla Action ve okunmuş olarak işaretle Action seçeneklerini bulur.
  4. Android Auto, araçta bildirim oluşturur ve gösterir.
  5. 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.
  6. 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:

  1. Ü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()
    }
}
  1. 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 bir RemoteInput 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 sorun oluşturma

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.