מערכות 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, גישה לתוכן שלכם, השירות צריך להחזיר ערך שאינו null 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 Assistant להתחבר אל MediaBrowserService
. ל-Google Assistant יש שמות חבילה נפרדים
לשימוש בטלפון, כולל 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 OS. המידע הזה מועבר אל 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.
לדוגמה, אם בדרך כלל מציגים פריט שניתן להפעלה ברמת הבסיס, יכול להיות שתרצו להציג אותו כפריט משנה של פריט שניתן לעיון ברמת הבסיס, בהתאם לערך של רמז הדגלים הנתמכים.
בנוסף לרמזים לגבי שורש, כדאי להשתמש בהנחיות האלה כדי להציג כרטיסיות בצורה אופטימלית:
סמלים מונוכרומטיים (רצוי לבנים) לכל פריט בכרטיסייה
תוויות קצרות ומשמעותיות לכל פריט בכרטיסייה (תוויות קצרות מקטינות את הסיכוי שהתוויות ייחתכו)