แอปสื่อที่ใช้เทมเพลต Car App Library สามารถปรับแต่งประสบการณ์การเรียกดูและการเล่นสื่อได้ พร้อมทั้งมั่นใจได้ว่าประสบการณ์การใช้งานจะได้รับการเพิ่มประสิทธิภาพสำหรับหน้าจอรถยนต์และลดสิ่งรบกวนขณะขับรถ
คู่มือนี้ถือว่าคุณมีแอปสื่อที่เล่นเสียงในโทรศัพท์อยู่แล้ว
และแอปสื่อของคุณเป็นไปตามสถาปัตยกรรมแอปสื่อของ Android ไลบรารีแอปในรถยนต์ช่วยให้คุณแทนที่ประสบการณ์การใช้งานแอปด้วยเทมเพลตแทนที่จะใช้เทมเพลตที่สร้างขึ้นโดยใช้โครงสร้างข้อมูลสร้างแอปสื่อสำหรับรถยนต์
MediaBrowser คุณยังคงต้องระบุMediaSession
สำหรับตัวควบคุมการเล่น และMediaBrowserServiceหรือMediaLibraryService
ซึ่งใช้สำหรับคำแนะนำและประสบการณ์การใช้งานอัจฉริยะอื่นๆ
กำหนดค่าไฟล์ Manifest ของแอป
นอกเหนือจากขั้นตอนที่อธิบายไว้ใน การใช้ไลบรารีแอป Android สำหรับรถยนต์แล้ว แอปสื่อที่ใช้เทมเพลตต้องมีคุณสมบัติต่อไปนี้
ประกาศการรองรับหมวดหมู่ในไฟล์ Manifest
แอปของคุณต้องประกาศ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 ด้วย
<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>
ระบุไอคอนการระบุแหล่งที่มา
อย่าลืมเพิ่มไอคอนการระบุแหล่งที่มาสำหรับแอปสื่อที่สร้างโดยใช้ Car App Library
ประกาศการรองรับ Android Auto
ตรวจสอบว่าไฟล์ Manifest ของแอปมีข้อมูลต่อไปนี้
<application>
...
<meta-data android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
จากนั้นเพิ่มการประกาศเทมเพลตไปยัง automotive_app_desc.xml ใน xml
resources โดยควรมีลักษณะดังนี้
<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 ได้ 2 วิธี ได้แก่ เป็น APK เดียวหรือเป็น APK 2 รายการแยกกัน หากคุณ
จัดจำหน่าย APK เดียว APK นั้นจะรองรับยานพาหนะที่เปิดใช้ Android
Automotive OS ด้วยโฮสต์ไลบรารีแอปในรถยนต์ และจะกลับไปใช้แอปพลิเคชัน MediaBrowserService หรือ MediaLibraryService หากไม่รองรับ แม้แต่สำหรับ Android เวอร์ชันเก่ากว่า (Android 10 - Android 13) หากเลือกที่จะจัดจำหน่าย APK แยกกัน 2 รายการ คุณจะอัปเดตฟีเจอร์ใหม่ๆ ใน Car App
Library เวอร์ชันได้ง่ายขึ้นโดยไม่ต้องกังวลว่าจะส่งผลต่อแอปเวอร์ชัน MediaBrowserService หรือ
MediaLibraryService
การจัดจำหน่าย APK เดียว
เมื่อเผยแพร่ APK เดียวสำหรับไลบรารีแอปในรถยนต์และแอปเวอร์ชัน MediaBrowserService
หรือ MediaLibraryService คุณต้องตั้งค่า
"android:required="false"
<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>
จากนั้นทําตามหลักเกณฑ์ของไลบรารีแอปในรถยนต์สําหรับ AAOS และ
แนะนํา CarAppActivity ที่เปิดใช้ได้ (หรือกิจกรรมแทรมโพลีน) คุณต้องตั้งค่า
กิจกรรมเป็น android:enabled="false" ในไฟล์ Manifest จากนั้นเพิ่มแท็กข้อมูลเมตา
ลงในประกาศMediaBrowserServiceที่ระบุCarAppActivity
คอมโพเนนต์เป็นการแทนที่ ดูตัวอย่างไฟล์ Manifest ด้านล่าง
<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 ที่กำหนดเป้าหมายเป็น Android 14 (34)
การเผยแพร่ด้วย APK 2 รายการ
หากต้องการเผยแพร่ APK 2 รายการแยกกัน โดยรายการหนึ่งใช้ 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 OS
สำหรับกิจกรรมไลบรารีแอปในรถยนต์ที่เปิดใช้ได้
การเผยแพร่ใน Play
ควรเผยแพร่ 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: A
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 เวอร์ชัน 1.9 มีการเปิดตัวคอมโพเนนต์ที่ปรับแต่งแล้ว เพื่อความสามารถในการเรียกดูที่ไม่เหมือนใคร เช่น ชิป แถบความคืบหน้า รายการแบบย่อ ส่วนหัวแบบอินเทอร์แอกทีฟและแบบขยาย ส่วนสปอตไลท์ และแบนเนอร์
รูปที่ 3: A
SectionedItemTemplate ที่มี Chips,
Condensed Items, Interactive Header,
Grid Items และ Minimized Control Panel
รูปที่ 4: หน้าจอการเรียกดูสื่อ 2 หน้าจอที่มีExpanded Header
Spotlight Sections และ Progress Bars
ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีออกแบบอินเทอร์เฟซผู้ใช้ของแอปสื่อโดยใช้เทมเพลตเหล่านี้ได้ที่แอปสื่อ
การไปยังตัวควบคุมการเล่น
เมื่อเรียกดูสื่อ ผู้ใช้ควรจะไปยังMediaPlaybackTemplateได้อย่างรวดเร็ว
โดยไม่มีสิ่งรบกวนมากนัก เพื่อให้เป็นไปตามข้อกำหนดด้านคุณภาพของ MFT-1 แอปของคุณต้องมีวิธีเข้าถึงMediaPlaybackTemplateจากหน้าจอการเรียกดูสื่อทั้งหมด
หากใช้ SectionedItemTemplate คุณสามารถทำได้โดยเพิ่มปุ่มการดำเนินการที่นำทางคุณไปยังหน้าจอการเล่นสื่อ ใช้การดำเนินการ
ไลบรารีแอปในรถยนต์มาตรฐาน Action.MEDIA_PLAYBACK แอปสื่อจะแสดงการดำเนินการนี้เป็นแผงควบคุมที่ย่อเล็กสุด
ซึ่งจำเป็นต่อการปฏิบัติตามข้อกำหนดด้านคุณภาพของ MFT-1 หากคุณใช้
Car App Library API 1.9 ขึ้นไป สำหรับเทมเพลตอื่นๆ การดำเนินการส่วนหัวเป็นอีกวิธีหนึ่ง
ในการดำเนินการนี้
จัดการ Intent การเล่นสื่อของระบบ
คุณต้องนำผู้ใช้ไปยัง 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() เพื่อแยกวิเคราะห์ Intent ที่เข้ามา
หากการดำเนินการผ่าน 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));
}
}
หากคุณใช้กิจกรรมแทรมโพลีน ให้ตรวจสอบการดำเนินการผ่าน 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();
}
}