אפליקציות מדיה שמשתמשות בתבניות של Car App Library יכולות להתאים אישית את חוויית הצפייה וההשמעה של המדיה, תוך הקפדה על חוויה אופטימלית למסכי רכב וצמצום הסחות הדעת בזמן הנהיגה.
המדריך הזה מניח שכבר יש לכם אפליקציית מדיה שמפעילה אודיו בטלפון, ושאתם משתמשים באפליקציית מדיה שתואמת לארכיטקטורת אפליקציות המדיה של Android. ספריית האפליקציות לרכב מאפשרת להחליף את חוויית השימוש באפליקציה בתבניות, במקום להשתמש בתבניות שנוצרו באמצעות מבנה הנתונים של יצירת אפליקציות מדיה לרכב
MediaBrowser. עדיין צריך לספק MediaSession
לרכיבי ה-UI להפעלת סרטונים, וגם MediaBrowserService או MediaLibraryService,
שמשמשים להמלצות ולחוויות חכמות אחרות.
הגדרת המניפסט של האפליקציה
בנוסף לשלבים שמתוארים במאמר שימוש בספריית האפליקציות של Android למכוניות, אפליקציות מדיה שמבוססות על תבניות צריכות לעמוד בדרישות הבאות:
הצהרה על תמיכה בקטגוריה במניפסט
באפליקציה שלך צריך להצהיר על androidx.car.app.category.MEDIA
קטגוריית אפליקציית הרכב במסנן ה-Intent של CarAppService.
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.MEDIA"/>
</intent-filter>
</service>
...
<application>
כדי לקבל גישה אל MediaPlaybackTemplate, האפליקציה צריכה גם להצהיר על ההרשאה androidx.car.app.MEDIA_TEMPLATES בקובץ המניפסט שלה:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.MEDIA_TEMPLATES"/>
...
</manifest>
הגדרת רמת ה-API המינימלית של אפליקציית הרכב
אפליקציות מדיה שמשתמשות ב-MediaPlaybackTemplate נתמכות רק ב-CAL API 8 ומעלה. חשוב לוודא שרמת ה-Car App API level המינימלית מוגדרת ל-8.
<application ...>
...
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="8"/>
...
</application>
הוספת סמל שיוך
חשוב להוסיף סמל שיוך לאפליקציות מדיה שנוצרו באמצעות ספריית האפליקציות לרכב.
הצהרה על תמיכה ב-Android Auto
חשוב לוודא שהרכיבים הבאים כלולים במניפסט של האפליקציה:
<application>
...
<meta-data android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
לאחר מכן, מוסיפים את הצהרת התבנית אל automotive_app_desc.xml במשאבי ה-XML. הוא אמור להיראות כך:
<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
<uses name="media"/>
<uses name="template"/>
</automotiveApp>
הצהרה על תמיכה ב-Android Automotive OS
יש שתי דרכים שונות להפצת אפליקציית מדיה שמופעלת באמצעות Car App Library ב-Android Automotive OS: כקובץ APK יחיד או כשני קובצי APK נפרדים. אם אתם מפיצים קובץ APK יחיד, הוא יתמוך בכלי רכב שמופעל בהם Android Automotive OS עם מארח ספריית האפליקציות לרכב, ויחזור לאפליקציית MediaBrowserService או MediaLibraryService אם לא, גם בגרסאות Android ישנות יותר (Android 10 עד Android 13). אם בחרתם להפיץ שני קובצי APK נפרדים, תוכלו לעדכן את התוספות החדשות לגרסה של Car App Library בלי לחשוש מהשפעה על גרסה MediaBrowserService או MediaLibraryService של האפליקציה.
הפצה של חבילת APK אחת
כשמפיצים קובץ APK יחיד עבור Car App Library וגרסאות MediaBrowserService או MediaLibraryService של האפליקציה, חשוב להגדיר את android.software.car.templates_host.media לערך android:required="false".
<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>
לאחר מכן, פועלים לפי ההנחיות של ספריית אפליקציות לרכב ל-AAOS ומוסיפים CarAppActivity (או פעילות מסוג trampoline) שאפשר להפעיל. צריך להגדיר את הפעילות ל-android:enabled="false" במניפסט. לאחר מכן, מוסיפים תג מטא-נתונים להצהרה MediaBrowserService שמציין את רכיב CarAppActivity כתחליף. לדוגמה, קובץ המניפסט הבא:
<service android:name=".media.MyMediaService"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
</intent-filter>
<!-- Link to Car App Library Activity -->
<meta-data
android:name="androidx.car.app.media.CalMediaActivityComponent"
android:value="com.example.mediaapp.LaunchableTrampoline"/>
</service>
<activity
android:name=".LaunchableTrampoline"
android:exported="true"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:launchMode="singleTask"
android:label="@string/app_name_cal"
android:enabled="false"> <!-- Set to false -->
<meta-data android:name="distractionOptimized" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
הפצה ב-Play
קובץ ה-APK עם ספריית האפליקציות לרכב ו-MediaBrowserService
או MediaLibraryService צריכים להיות מופעלים עם קוד גרסה גבוה יותר ו-minSdk שמטרגט ל-Android 14 (34).
הפצה עם שני קובצי APK
כדי להפיץ שני קובצי APK נפרדים, אחד באמצעות ספריית האפליקציות לרכב ואחד באמצעות MediaBrowserService או MediaLibraryService, צריך לפעול לפי השלבים הבאים כדי לוודא שהיכולות הנכונות של הרכב מוגדרות בצורה נכונה.
כשיוצרים קובץ APK נפרד לגרסה של האפליקציה שמתבססת על ספריית האפליקציות לרכב, צריך להגדיר את הערך של android.software.car.templates_host.media ל-android:required=true. כך מוודאים שהאפליקציה מופצת רק בגרסאות של Android Automotive OS שאושרו עם תמיכה במארח של ספריית האפליקציות לרכב.
<uses-feature android:name="android.software.car.templates_host.media" android:required="true"/>
בנוסף לשימוש ב-android.software.car.templates_host.media ולהגדרתו ל-android:required=true, צריך לבצע את השלבים הבאים כדי להפעיל את Android Automotive OS לפעילות של ספריית האפליקציות לרכב שאפשר להפעיל.
Play Distribution
קובץ ה-APK שמשתמש בספריית האפליקציות לרכב צריך להיות מופץ במסלול הייעודי ל-Automotive OS.
תמיכה בפעולות קוליות
אפשר להוסיף לאפליקציה תכונות קוליות כדי לאפשר למשתמשים לבצע פעולות נפוצות בלי ידיים.
הוראות מפורטות יותר להטמעה זמינות במאמר בנושא תמיכה בפעולות קוליות למדיה. אם מקבלים פקודה קולית באפליקציית מדיה שמבוססת על תבנית, לא צריך לעדכן את MediaBrowserService או את MediaLibraryService בתוצאות חיפוש. במקום זאת, כדאי להוסיף פעולה בתבנית של הפעלת המדיה כדי לאפשר למשתמש למצוא תוכן נוסף על סמך ההפעלה או שאילתת החיפוש. כדי לעמוד בהנחיית האיכות VC-1, צריך לתמוך בפקודות קוליות.
יצירת תבנית הפעלה
התבנית MediaPlaybackTemplate מציגה מידע על הפעלת מדיה באפליקציית המדיה בספריית האפליקציות לרכב. התבנית הזו מאפשרת להגדיר כותרת עם שם ופעולות שאפשר להתאים אישית, בזמן שהמידע על המדיה ואמצעי הבקרה של ההפעלה מאוכלסים על ידי האפליקציה המארחת על סמך המצב של MediaSession באפליקציה.
איור 1:
MediaPlaybackTemplate עם פעולת כותרת לפתיחת התור
בחלק העליון.
בדוגמת הקוד הזו מוצג אופן הבנייה של תבנית הפעלה לדוגמה שמגדירה פעולת כותרת שמאפשרת למשתמש לעבור למסך עם תור השירים.
val playbackTemplate = MediaPlaybackTemplate.Builder()
.setHeader(
Header.Builder()
.setStartHeaderAction(Action.BACK)
.addEndHeaderAction(
Action.Builder()
.setTitle(model.context.getString(R.string.queue_button_title))
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
model.context,
R.drawable.gs_queue_music_vd_theme_24,
))
.build())
.setOnClickListener(showQueueScreen())
.build())
.setTitle(model.context.getString(R.string.media_playback_view_title))
.build())
.build()
כשמשתמשים ב-MediaPlaybackTemplate, צריך לרשום טוקן MediaSession באמצעות MediaPlaybackManager ב-CarAppService. אם לא עושים את זה, מוצגת שגיאה כששולחים MediaPlaybackTemplate למארח.
import androidx.car.app.media.MediaPlaybackManager
…
override fun onCreateSession(sessionInfo: SessionInfo): Session {
return object : Session() {
…
init {
lifecycle.addObserver(
LifecycleEventObserver { _, event ->
if (event == ON_CREATE) {
val token = ... // MediaSessionCompat.Token
(carContext.getCarService(CarContext.MEDIA_PLAYBACK_SERVICE) as MediaPlaybackManager)
.registerMediaPlaybackToken(token)
}
...
}
)
}
}
}
ההרשאה .registerMediaPlaybackToken נדרשת כדי לחשוף את פרטי ההפעלה של המדיה ואת אמצעי הבקרה ב-Android Auto. זה חשוב גם למארח כדי ליצור התראות ספציפיות למדיה.
באפליקציות שמשתמשות בספריית Media3, שבה נעשה שימוש ב-PlatformToken במקום ב-MediaSessionCompat.Token רגיל, צריך להטמיע SessionCommand מותאם אישית ב-MediaLibrarySession.Callback שמחזיר את טוקן הפלטפורמה הבסיסי של הסשן: session.platformToken. ב-CarAppService, שולחים את הפקודה המותאמת אישית הזו לסשן. אחרי שמקבלים את אסימון הפלטפורמה, ממירים אותו באמצעות MediaSessionCompat.Token.fromToken(platformToken) ומעבירים את אסימון התאימות הזה אל Car App Library ב-.registerMediaPlaybackToken().
ארגון מדיה באמצעות תבניות
כדי לארגן מדיה לעיון, כמו שירים או אלבומים, מומלץ להשתמש ב-SectionedItemTemplate, שמאפשר להשתמש ב-GridSection וב-RowSection יחד כדי ליצור פריסות שמשלבות רשימות של תמונות ופריטי טקסט.
איור 2: SectionedItemTemplate שמכיל RowSection ואחריו GridSection
שימוש ב-SectionedItemTemplate בתוך TabTemplate
דרך נוחה לסווג מדיה באפליקציה היא באמצעות התג SectionedItemTemplate בתוך התג TabTemplate.
val template =
SectionedItemTemplate.Builder()...build();
val tabTemplate =
TabTemplate.Builder(tabCallback)
.setTabContents(TabContents.Builder(template).build)
.setHeaderAction(Action.APP_ICON)
…
.build();
רכיבים ותכונות של ספריית האפליקציות לרכב 1.9
Car App Library API Version 1.9 כולל רכיבים מותאמים אישית ליכולות גלישה ייחודיות, כמו Chips, Progress Bars, Condensed Items, Interactive and Expanded Header, Spotlight Sections ו-Banners.
איור 3: תיבת טקסט A
SectionedItemTemplate שמכילה את Chips,
Condensed Items, את Interactive Header,
Grid Items ואת Minimized Control Panel
איור 4: שני מסכים של דפדוף במדיה עם הסמלים Expanded Header, Spotlight Sections ו-Progress Bars
לפרטים נוספים על עיצוב ממשק המשתמש של אפליקציית המדיה באמצעות התבניות האלה, אפשר לעיין במאמר בנושא אפליקציות מדיה.
ניווט אל רכיבי ה-UI להפעלה
כשמשתמשים מעיינים במדיה, חשוב שהם יוכלו לעבור במהירות אל MediaPlaybackTemplate עם מינימום הסחות דעת.כדי לעמוד בדרישת האיכות MFT-1, באפליקציה שלכם צריכה להיות דרך לגשת אל MediaPlaybackTemplate מכל מסכי העיון במדיה.
אם אתם משתמשים ב-SectionedItemTemplate, תוכלו להוסיף כפתור פעולה שמעביר אתכם למסך הפעלת המדיה. משתמשים בפעולה הרגילה של ספריית האפליקציות לרכב Action.MEDIA_PLAYBACK. אפליקציית מדיה תציג את הפעולה הזו כלוח בקרה ממוזער, שנדרש כדי לעמוד בדרישת האיכות MFT-1 אם משתמשים ב-Car App Library API מגרסה 1.9 ואילך. בתבניות אחרות, אפשר להשתמש בפעולה בכותרת כדי להשיג את אותה תוצאה.
טיפול ב-Intents של הפעלת מדיה במערכת
כשמפעילים אפליקציה מממשק מערכת להפעלת מדיה, כמו כרטיס מדיה, צריך להפנות את המשתמש אל MediaPlaybackTemplate. אנחנו דורשים מאפליקציות מדיה לטפל ב-Intent Action כדי לספק למשתמשים חוויה חלקה.
מוסיפים את הפעולה androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK ל-intent-filter של רכיב Car App Library (או CarAppActivity או Activity).
מוודאים שהפעילות משתמשת ב-launchMode של singleTask או singleTop כדי להפעיל את onNewIntent().
<activity
android:name=".LaunchableTrampoline"
android:exported="true"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:launchMode="singleTask"
android:label="@string/app_name_cal"
android:enabled="false">
<meta-data android:name="distractionOptimized" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
בכיתה Session, מחליפים את onNewIntent() כדי לנתח את הכוונה הנכנסת.
אם פעולת הכוונה הנכנסת תואמת ל-SHOW_MEDIA_PLAYBACK, צריך להעביר את המשתמש למסך 'מה שומעים עכשיו?'.
@Override
public void onNewIntent(@NonNull Intent intent) {
super.onNewIntent(intent);
if (SHOW_MEDIA_PLAYBACK.equals(intent.getAction())) {
ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
// Avoid redundant navigation if already on the playing screen
if (screenManager.getTop() instanceof MyMediaPlayScreen) {
return;
}
screenManager.push(MyMediaPlayScreen.createScreenFromPlaying(
getCarContext(), mMediaSessionController));
}
}
אם אתם משתמשים בפעילות טרמפולינה, בודקים את פעולת Intent בתוך onCreate(). מעבירים את הפעולה הזו אל CarAppActivity כוונת היצירה לפני הקריאה ל-finish().
public class LaunchableTrampoline extends AppCompatActivity {
private static final String SHOW_MEDIA_PLAYBACK = "androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent receivedIntent = getIntent();
String action;
if (SHOW_MEDIA_PLAYBACK.equals(receivedIntent.getAction())) {
action = SHOW_MEDIA_PLAYBACK;
} else {
action = Intent.ACTION_MAIN;
}
Intent intent = new Intent(action);
intent.setClassName(getPackageName(), "androidx.car.app.activity.CarAppActivity");
startActivity(intent);
finish();
}
}