자동차 앱 라이브러리 템플릿을 사용하는 미디어 앱은 자동차 화면에 최적화되고 운전 중 주의 산만을 최소화하는 환경을 보장하면서 미디어 탐색 및 재생 환경을 맞춤설정할 수 있습니다.
이 가이드에서는 개발자에게 이미 휴대전화에서 오디오를 재생하는 미디어 앱이 있고 미디어 앱이 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>
최소 자동차 앱 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>
그런 다음 xml 리소스의 automotive_app_desc.xml에 템플릿 선언을 추가합니다. 다음과 같이 표시됩니다.
<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
<uses name="media"/>
<uses name="template"/>
</automotiveApp>
Android Automotive OS 지원 선언
Android Automotive OS에서 자동차 앱 라이브러리가 사용 설정된 미디어 앱을 배포하는 방법에는 단일 APK 또는 두 개의 별도 APK가 있습니다. 단일 APK를 배포하면 자동차 앱 라이브러리 호스트로 Android Automotive OS가 사용 설정된 차량을 지원하고 이전 Android 버전 (Android 10~Android 13)의 경우에도 지원되지 않으면 MediaBrowserService 또는 MediaLibraryService 애플리케이션으로 대체됩니다. 두 개의 별도 APK를 배포하도록 선택하면 앱의 MediaBrowserService 또는 MediaLibraryService 버전에 영향을 미칠까 봐 걱정하지 않고 자동차 앱 라이브러리 버전에 새로 추가된 항목을 더 쉽게 업데이트할 수 있습니다.
단일 APK 배포
자동차 앱 라이브러리 및 앱의 MediaBrowserService
또는 MediaLibraryService 버전에 단일 APK를 배포할 때는
"android:required="false"로 설정하는 것이 중요합니다.
<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>
다음으로 AAOS용 자동차 앱 라이브러리 가이드라인을 따르고
실행 가능한 CarAppActivity (또는 트램펄린 활동)를 도입합니다. 매니페스트에서 활동을 android:enabled="false"로 설정해야 합니다. 다음으로 CarAppActivity 구성요소를 대체 항목으로 나타내는 메타데이터 태그를 MediaBrowserService 선언에 추가합니다. 아래 매니페스트 예를 참고하세요.
<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 배포
자동차 앱 라이브러리 및 MediaBrowserService 또는 MediaLibraryService가 포함된 APK는 버전 코드가 더 높고 Android 14 (34)를 타겟팅하는 minSdk로 사용 설정해야 합니다.
두 개의 APK로 배포
자동차 앱 라이브러리를 사용하는 APK와 MediaBrowserService 또는 MediaLibraryService를 사용하는 APK 등 두 개의 별도 APK를 배포하려면 다음 단계에 따라 올바른 차량 기능을 올바르게 타겟팅하세요.
앱의 자동차 앱 라이브러리 버전에 별도 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 배포
자동차 앱 라이브러리를 사용하는 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을 사용하는 경우
CarAppService에서 MediaPlaybackManager를 사용하여 a
MediaSession 토큰을 등록합니다. 이렇게 하지 않으면 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에 노출하는 데 필요합니다. 이는 호스트가 미디어 관련 알림을 만드는 데도 중요합니다.
표준 MediaSessionCompat.Token이 아닌 PlatformToken을 사용하는 Media3 라이브러리를 사용하는 앱의 경우 세션의 기본 플랫폼 토큰인 session.platformToken을 반환하는 MediaLibrarySession.Callback에서 맞춤 SessionCommand를 구현해야 합니다. CarAppService에서 이 맞춤 명령어를 세션으로 전송합니다. 플랫폼 토큰을 수신하면 MediaSessionCompat.Token.fromToken(platformToken)을 사용하여 변환하고 이 호환 토큰을 .registerMediaPlaybackToken()의 자동차 앱 라이브러리에 전달합니다.
템플릿을 사용하여 미디어 정리
노래 또는 앨범과 같은 탐색을 위해 미디어를 정리하려면
SectionedItemTemplate을(를)
사용하는 것이 좋습니다. 이를 통해 GridSection 및
RowSection을(를) 함께 사용하여 이미지
및 텍스트 항목 목록을 혼합하는 레이아웃을 만들 수 있습니다.
그림 2: RowSection 다음에 GridSection이 포함된 SectionedItemTemplate
TabTemplate 내에서 SectionedItemTemplate 사용
앱 내에서 미디어를 분류하는 편리한 방법 중 하나는
SectionedItemTemplate 내에서
TabTemplate을 사용하는 것입니다.
val template =
SectionedItemTemplate.Builder()...build();
val tabTemplate =
TabTemplate.Builder(tabCallback)
.setTabContents(TabContents.Builder(template).build)
.setHeaderAction(Action.APP_ICON)
…
.build();
자동차 앱 라이브러리 1.9 구성요소 및 기능
자동차 앱 라이브러리 API 버전 1.9에서는 칩, 진행률 표시줄, 축소된 항목, 대화형 및 확장된 헤더, 스포트라이트 섹션, 배너와 같은 고유한 탐색 기능을 위한 맞춤 구성요소를 도입합니다.
그림 3:
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 작업을 사용합니다. 미디어 앱은 이 작업을 최소화된 제어판으로 표시하며, 자동차 앱 라이브러리 API 1.9 이상을 사용하는 경우 MFT-1 품질 요구사항을 충족하는 데 필요합니다. 다른 템플릿의 경우 헤더 작업이 이를 실행하는 또 다른 방법입니다.
시스템 미디어 재생 인텐트 처리
미디어 카드와 같은 미디어를 재생하는 시스템 화면에서 애플리케이션이 실행될 때 사용자를 MediaPlaybackTemplate으로 안내해야 합니다. 사용자에게 원활한 환경을 제공하려면 미디어 애플리케이션이 이 Intent Action을(를) 처리해야 합니다.
자동차 앱 라이브러리 구성요소 (CarAppActivity 또는
트램펄린 Activity)의
intent-filter에 androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK 작업을 추가합니다.
onNewIntent()가 호출되도록 활동에서 launchMode singleTask 또는 singleTop을 사용하는지 확인합니다.
<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));
}
}
트램펄린 활동을 사용하는 경우 onCreate() 내에서 인텐트 작업을 확인합니다. finish()를 호출하기 전에 이 작업을 CarAppActivity 생성 인텐트에 전달합니다.
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();
}
}