تستدعي خدمة متصفّح الوسائط في تطبيقك كلاً من 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<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...
}
يمكنك اختيار تقسيم منطق بنية تسلسل المحتوى الهرمي استنادًا إلى قيم هذه التلميحات، خاصةً إذا كان التسلسل الهرمي يختلف بين عمليات دمج MediaBrowser خارج Android Auto ونظام التشغيل AAOS.
على سبيل المثال، إذا كنت تعرض عادةً عنصرًا قابلاً للتشغيل في الجذر، قد ترغب في وضعه ضِمن عنصر قابل للتصفّح في الجذر بدلاً من ذلك بسبب قيمة تلميح العلامات المتوافقة.
بالإضافة إلى التلميحات الجذرية، استخدِم هذه الإرشادات لعرض علامات التبويب على النحو الأمثل:
رموز أحادية اللون (يفضّل أن تكون بيضاء) لكل عنصر من عناصر علامات التبويب
تصنيفات قصيرة وذات معنى لكل عنصر من عناصر علامات التبويب (تقلّل التصنيفات القصيرة من احتمالية اقتطاع التصنيفات)