يمكن لتطبيقات الوسائط التي تستخدم نماذج "مكتبة تطبيقات السيارات" تخصيص تجربة تصفّح الوسائط وتشغيلها مع ضمان تحسين التجربة لشاشات السيارات والحدّ من عوامل التشتيت أثناء القيادة.
يفترض هذا الدليل أنّ لديك تطبيق وسائط يشغّل الصوت على الهاتف
وأنّ تطبيق الوسائط يتوافق مع بنية تطبيقات الوسائط على Android. تتيح لك "مكتبة تطبيقات السيارات" إمكانية استبدال التجربة داخل التطبيق بقوالب بدلاً من تلك التي تم إنشاؤها باستخدام بنية البيانات إنشاء تطبيقات وسائط للسيارات
MediaBrowser. سيظل عليك تقديم MediaSession
لعناصر التحكّم في التشغيل، وMediaBrowserService أو MediaLibraryService،
اللذين يُستخدمان في الاقتراحات والتجارب الذكية الأخرى.
ضبط ملف البيان الخاص بتطبيقك
بالإضافة إلى الخطوات الموضّحة في مقالة استخدام مكتبة تطبيقات Android للسيارات، يجب أن تستوفي تطبيقات الوسائط المستندة إلى نماذج المتطلبات التالية:
تحديد الفئات المتوافقة في البيان
يجب أن يحدّد تطبيقك androidx.car.app.category.MEDIA
فئة تطبيق السيارة في فلتر الأهداف الخاص بـ 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>
ضبط الحد الأدنى لمستوى واجهة برمجة تطبيقات السيارات
لا تتوافق تطبيقات الوسائط التي تستخدم MediaPlaybackTemplate إلا مع الإصدار 8 من واجهة برمجة تطبيقات CAL والإصدارات الأحدث، لذا تأكَّد من ضبط الحد الأدنى Car App API level على 8.
<application ...>
...
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="8"/>
...
</application>
توفير رمز تحديد المصدر
احرص على إضافة رمز تحديد المصدر لتطبيقات الوسائط التي تم إنشاؤها باستخدام Car App Library.
تحديد إمكانية استخدام التطبيق مع 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
هناك طريقتان مختلفتان يمكنك من خلالهما توزيع تطبيق وسائط متوافق مع Car App Library على نظام التشغيل Android Automotive: كحِزمة APK واحدة أو كحِزمتَي APK منفصلتَين. في حال توزيع حزمة APK واحدة، ستكون متوافقة مع السيارات التي تم تفعيل نظام التشغيل Android Automotive عليها باستخدام مضيف "مكتبة تطبيقات السيارات"، وسيتم الرجوع إلى تطبيق MediaBrowserService أو MediaLibraryService في حال عدم توفّره، حتى مع إصدارات Android القديمة (من Android 10 إلى Android 13). في حال اختيار توزيع حزمتَي APK منفصلتَين، يمكنك تعديل الإضافات الجديدة في إصدار "مكتبة تطبيقات السيارة" بدون التأثير في إصدار MediaBrowserService أو MediaLibraryService من تطبيقك.
توزيع حزمة APK واحدة
عند توزيع حزمة APK واحدة لكل من "مكتبة تطبيقات السيارات" وإصدارات 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 قابلاً للتشغيل (أو نشاطًا سريعًا). يجب ضبط النشاط على 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 التي تتضمّن Car App Library وMediaBrowserService
أو MediaLibraryService باستخدام رمز إصدار أعلى وminSdk يستهدف الإصدار 14 من نظام التشغيل Android (المستوى 34).
التوزيع باستخدام حزمتَي APK
لتوزيع حزمتَي APK منفصلتَين، إحداهما تستخدم مكتبة Car App Library والأخرى تستخدم MediaBrowserService أو MediaLibraryService، اتّبِع الخطوات التالية لضمان استهداف إمكانات السيارة الصحيحة بشكل صحيح.
عند إنشاء حزمة APK منفصلة لإصدار تطبيقك المتوافق مع Car App Library، يجب ضبط 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 لنشاط "مكتبة تطبيقات السيارات" القابل للتشغيل.
التوزيع على Play
يجب توزيع حزمة APK التي تستخدم Car App Library في قناة الإصدار المحدود المخصّصة لنظام التشغيل 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) وتمرير رمز التوافق هذا إلى "مكتبة تطبيقات السيارات" في .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 من "مكتبة تطبيقات السيارات"
تتضمّن الإصدار 1.9 من Car App Library API مكوّنات مخصّصة تتيح إمكانات تصفّح فريدة، مثل الشرائح وأشرطة التقدم والعناصر المختصرة والعناوين التفاعلية والموسّعة وأقسام "المنتجات المميّزة" والبانرات.
الشكل 3: SectionedItemTemplate يحتوي على Chips وCondensed Items وInteractive Header وGrid Items وMinimized Control Panel
الشكل 4: شاشتا تصفّح وسائط تعرضان الرموز Expanded Header وSpotlight Sections وProgress Bars
لمزيد من التفاصيل حول كيفية تصميم واجهة مستخدم تطبيق الوسائط باستخدام هذه النماذج، يُرجى الاطّلاع على تطبيقات الوسائط.
الانتقال إلى عناصر التحكّم في التشغيل
عند تصفّح الوسائط، من المهم أن يتمكّن المستخدم من الانتقال بسرعة إلى MediaPlaybackTemplate بأقل قدر من التشتيت.ولتلبية متطلبات الجودة MFT-1، يجب أن يوفّر تطبيقك طريقة للوصول إلى MediaPlaybackTemplate من جميع شاشات تصفّح الوسائط.
إذا كنت تستخدم SectionedItemTemplate، يمكنك تحقيق ذلك من خلال إضافة زر إجراء ينقلك إلى شاشة تشغيل الوسائط. استخدِم إجراء Action.MEDIA_PLAYBACK "مكتبة تطبيقات السيارات" العادي. سيعرض تطبيق موسيقى هذا الإجراء على شكل لوحة تحكّم مصغّرة، وهو أمر ضروري لاستيفاء متطلبات الجودة MFT-1 إذا كنت تستخدم الإصدار 1.9 أو إصدارًا أحدث من Car App Library API. بالنسبة إلى النماذج الأخرى، يشكّل إجراء العنوان طريقة أخرى لتحقيق ذلك.
التعامل مع طلبات تشغيل الوسائط في النظام
يجب توجيه المستخدم إلى MediaPlaybackTemplate عند تشغيل تطبيق من مساحة عرض وسائط في النظام، مثل بطاقة وسائط. ونشترط أن تتعامل تطبيقات الوسائط مع هذا Intent Action من أجل توفير تجربة سلسة للمستخدمين.
أضِف الإجراء androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK إلى
intent-filter الخاص بمكوّن "مكتبة تطبيقات السيارة" (إما 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() لتحليل الغرض الوارد.
إذا كان إجراء Intent الوارد يتطابق مع 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));
}
}
إذا كنت تستخدم نشاط ترامبولين، ابحث عن إجراء الهدف ضمن
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();
}
}