تستدعي كلّ من Android Auto وAndroid Automotive OS (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, nu
ll)
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
.
تختلف توقيعات تطبيقات نظام التشغيل Android Automotive حسب ماركة السيارة وطرازها. احرص على السماح بالاتصالات من جميع تطبيقات النظام لتوفير الدعم لنظام التشغيل Android Automotive.
تعرض مقتطفة الرمز البرمجي هذه كيف يمكن لخدمتك التحقّق من أنّ الحزمة التي يتم استدعاؤها هي تطبيق نظام:
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" أسماء حِزم منفصلة للهاتف، بما في ذلك Android Auto وAndroid 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<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<List<MediaBrowserCompat.MediaItem>> result) {
// Assume for example that the music catalog is already loaded/cached.
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// 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. المحتوى الأساسي المعروض كعلامات تبويب للتنقّل
من خلال تطبيق هذه التلميحات، يعرض النظام المحتوى الأساسي على شكل علامات تبويب خاصة بالتنقل. في حال عدم تطبيق هذه التلميحات، قد يتم تجاهل بعض المحتوى الأساسي أو يصبح أقل قابلية للاكتشاف. يتم إرسال هذه التلميحات:
الحدّ الأقصى لعدد العناصر الفرعية الرئيسية: في معظم الحالات، من المتوقّع أن يكون هذا العدد أربعة، ما يعني أنّه يمكن عرض أربعة علامات تبويب (أو أقل) فقط.
العلامات المتوافقة مع العناصر الفرعية الجذر: من المتوقّع أن تكون هذه القيمة
MediaItem#FLAG_BROWSABLE
، ما يعني أنّه يمكن عرض العناصر التي يمكن تصفّحها فقط (وليس العناصر التي يمكن تشغيلها) كعلامات تبويب.الحدّ الأقصى لعدد إجراءات التصفّح المخصّصة: تحقَّق من عدد إجراءات التصفّح المخصّصة المتاحة.
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...
}
يمكنك اختيار تقسيم منطق بنية تسلسل المحتوى الهرمي استنادًا إلى قيم هذه التلميحات، خاصةً إذا كان التسلسل الهرمي يختلف بين عمليات الدمج خارج Android Auto وAAOS.MediaBrowser
على سبيل المثال، إذا كنت تعرض عادةً عنصرًا قابلاً للتشغيل على المستوى الأعلى، قد تحتاج إلى تضمينه ضمن عنصر قابل للتصفّح على المستوى الأعلى بدلاً من ذلك بسبب قيمة تلميح العلامات المتوافقة.
بالإضافة إلى تلميحات الجذر، اتّبِع الإرشادات التالية لعرض علامات التبويب على النحو الأمثل:
رموز أحادية اللون (يفضّل أن تكون بيضاء) لكل عنصر من عناصر علامات التبويب
تصنيفات قصيرة وذات معنى لكل عنصر من عناصر علامات التبويب (تقلّل التصنيفات القصيرة من احتمالية اقتطاع التصنيفات)