إنشاء التدرّج الهرمي للمحتوى

تستدعي خدمة متصفّح الوسائط في تطبيقك كلاً من Android Auto ونظام التشغيل Android Automotive (AAOS) لاكتشاف المحتوى المتاح. ولإتاحة ذلك، عليك تنفيذ هاتَين الطريقتَين في خدمة متصفّح الوسائط.

تنفيذ طريقة onGetRoot

تعرض طريقة onGetRoot في خدمتك معلومات عن العقدة الجذرية لتسلسل المحتوى الهرمي. يستخدم كل من Android Auto ونظام التشغيل AAOS هذه العقدة الجذرية لطلب بقية المحتوى باستخدام طريقة onLoadChildren يوضّح مقتطف الرمز البرمجي هذا عملية تنفيذ طريقة onGetRoot:

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? =
    // Verify that the specified package is allowed to access your
    // content. You'll need to write your own logic to do this.
    if (!isValid(clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return null.
        // No further calls will be made to other media browsing methods.

        null
    } else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {

    // Verify that the specified package is allowed to access your
    // content. You'll need to write your own logic to do this.
    if (!isValid(clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return null.
        // No further calls will be made to other media browsing methods.

        return null;
    }

    return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null);
}

للاطّلاع على مثال مفصّل لهذه الطريقة، يُرجى مراجعة onGetRoot في نموذج تطبيق Universal Android Music Player على GitHub.

إضافة عملية التحقّق من الحزمة

عند إجراء مكالمة إلى طريقة onGetRoot في خدمتك، تمرِّر الحزمة التي تجري المكالمة معلومات تكشف الهوية إلى خدمتك. يمكن أن تستخدم خدمتك هذه المعلومات لتحديد ما إذا كان بإمكان تلك الحزمة الوصول إلى المحتوى.

على سبيل المثال، يمكنك حصر إمكانية الوصول إلى محتوى تطبيقك في قائمة بالحِزم المسموح بها:

  • قارِن clientPackageName بالقائمة المسموح بها.
  • تحقَّق من الشهادة المستخدَمة لتوقيع حزمة APK.

إذا تعذّر التحقّق من الحزمة، عليك عرض null لرفض الوصول إلى المحتوى.

لمنح تطبيقات النظام، مثل Android Auto ونظام التشغيل AAOS، إمكانية الوصول إلى المحتوى، يجب أن تعرض خدمتك عنصر BrowserRoot غير فارغ عندما تستدعي تطبيقات النظام هذه طريقة onGetRoot.

يختلف توقيع تطبيق نظام التشغيل AAOS حسب ماركة السيارة وطرازها. احرص على السماح بالاتصالات من جميع تطبيقات النظام لإتاحة استخدام نظام التشغيل AAOS.

يوضّح مقتطف الرمز البرمجي هذا كيف يمكن لخدمتك التحقّق من أنّ الحزمة التي تجري المكالمة هي تطبيق نظام:

fun isKnownCaller(
    callingPackage: String,
    callingUid: Int
): Boolean {
    ...
    val isCallerKnown = when {
       // If the system is making the call, allow it.
       callingUid == Process.SYSTEM_UID -> true
       // If the app was signed by the same certificate as the platform
       // itself, also allow it.
       callerSignature == platformSignature -> true
       // ... more cases
    }
    return isCallerKnown
}

مقتطف الرمز البرمجي هذا مأخوذ من فئة PackageValidator في نموذج تطبيق Universal Android Music Player على GitHub. يمكنك الاطّلاع على هذه الفئة للحصول على مثال أكثر تفصيلاً حول كيفية تنفيذ عملية التحقّق من الحزمة لطريقة onGetRoot في خدمتك.

بالإضافة إلى السماح لتطبيقات النظام، عليك السماح لـ "مساعد Google" بالاتصال بـ MediaBrowserService. يستخدم "مساعد Google" أسماء حِزم مختلفة لتطبيقاته على الأجهزة الجوّالة وتطبيقاته على نظام التشغيل AAOS.

تنفيذ طريقة onLoadChildren

بعد تلقّي عنصر العقدة الجذرية، ينشئ كل من Android Auto ونظام التشغيل AAOS قائمة ذات مستوى أعلى من خلال استدعاء onLoadChildren على عنصر العقدة الجذرية للحصول على العناصر التابعة لها. تنشئ تطبيقات العميل قوائم فرعية من خلال استدعاء الطريقة نفسها باستخدام عناصر العقدة التابعة.

يتم تمثيل كل عقدة في تسلسل المحتوى الهرمي بعنصر MediaBrowserCompat.MediaItem. يتم تعريف كل عنصر من عناصر الوسائط هذه من خلال سلسلة معرّف فريدة. تتعامل تطبيقات العميل مع سلاسل المعرّفات هذه على أنّها رموز مميزة غير شفافة.

عندما يريد تطبيق العميل الانتقال إلى قائمة فرعية أو تشغيل عنصر وسائط، يمرِّر الرمز المميّز. عليك ربط الرمز المميّز بعنصر الوسائط المناسب.

يوضّح مقتطف الرمز البرمجي هذا عملية تنفيذ onLoadChildren

Kotlin

override fun onLoadChildren(
    parentMediaId: String,
    result: Result<List<MediaBrowserCompat.MediaItem>>
) {
    // Assume for example that the music catalog is already loaded/cached.

    val mediaItems: MutableList&lt;MediaBrowserCompat.MediaItem> = mutableListOf()

    // Check if this is the root menu:
    if (MY_MEDIA_ROOT_ID == parentMediaId) {

        // Build the MediaItem objects for the top level
        // and put them in the mediaItems list.
    } else {

        // Examine the passed parentMediaId to see which submenu we're at
        // and put the descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result&lt;List&lt;MediaBrowserCompat.MediaItem>> result) {

    // Assume for example that the music catalog is already loaded/cached.

    List&lt;MediaBrowserCompat.MediaItem> mediaItems = new ArrayList&lt;>();

    // Check if this is the root menu:
    if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {

        // Build the MediaItem objects for the top level
        // and put them in the mediaItems list.
    } else {

        // Examine the passed parentMediaId to see which submenu we're at
        // and put the descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems);
}

للاطّلاع على مثال لهذه الطريقة، يُرجى مراجعة onLoadChildren في نموذج تطبيق Universal Android Music Player على GitHub.

تنظيم القائمة الجذرية

يفرض كل من Android Auto ونظام التشغيل Android Automotive قيودًا معيّنة على بنية القائمة الجذرية. يتم إرسال هذه القيود إلى MediaBrowserService من خلال تلميحات جذرية يمكن قراءتها من خلال وسيطة الحزمة التي يتم تمريرها إلى onGetRoot(). عند اتّباع هذه التلميحات، يتيح ذلك للنظام عرض المحتوى الجذري كعلامات تبويب تنقّل. إذا لم تتّبع هذه التلميحات، قد يتم إسقاط بعض المحتوى الجذري أو يصبح أقل قابلية للاكتشاف من قِبل النظام.

عرض المحتوى الأساسي على شكل علامات تبويب للتنقّل

الشكل 1: المحتوى الجذري المعروض كعلامات تبويب تنقّل

من خلال تطبيق هذه التلميحات، يعرض النظام المحتوى الجذري كعلامات تبويب تنقّل. إذا لم يتم تطبيق هذه التلميحات، قد يتم إسقاط بعض المحتوى الجذري أو يصبح أقل قابلية للاكتشاف. يتم إرسال هذه التلميحات:

Kotlin

import androidx.media.utils.MediaConstants

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle
): BrowserRoot {

  val maximumRootChildLimit = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
      /* defaultValue= */ 4)
  val supportedRootChildFlags = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
      /* defaultValue= */ MediaItem.FLAG_BROWSABLE)

  // Rest of method...
}

Java

import androidx.media.utils.MediaConstants;

// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
    String clientPackageName, int clientUid, Bundle rootHints) {

    int maximumRootChildLimit = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
        /* defaultValue= */ 4);
    int supportedRootChildFlags = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
        /* defaultValue= */ MediaItem.FLAG_BROWSABLE);

    // Rest of method...
}

يمكنك اختيار تقسيم منطق بنية تسلسل المحتوى الهرمي استنادًا إلى قيم هذه التلميحات، خاصةً إذا كان التسلسل الهرمي يختلف بين عمليات دمج MediaBrowser خارج Android Auto ونظام التشغيل AAOS.

على سبيل المثال، إذا كنت تعرض عادةً عنصرًا قابلاً للتشغيل في الجذر، قد ترغب في وضعه ضِمن عنصر قابل للتصفّح في الجذر بدلاً من ذلك بسبب قيمة تلميح العلامات المتوافقة.

بالإضافة إلى التلميحات الجذرية، استخدِم هذه الإرشادات لعرض علامات التبويب على النحو الأمثل:

  • رموز أحادية اللون (يفضّل أن تكون بيضاء) لكل عنصر من عناصر علامات التبويب

  • تصنيفات قصيرة وذات معنى لكل عنصر من عناصر علامات التبويب (تقلّل التصنيفات القصيرة من احتمالية اقتطاع التصنيفات)