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