Las apps de música y podcasts que usan las plantillas de la biblioteca de Car App pueden personalizar su experiencia de exploración y reproducción de contenido multimedia, a la vez que garantizan que la experiencia esté optimizada para las pantallas de los automóviles y minimice las distracciones mientras se conduce.
En esta guía, se da por sentado que ya tienes una app de música que reproduce audio en un teléfono y que cumple con la arquitectura de apps de música de Android. La biblioteca de Car App te permite reemplazar la experiencia en la app con plantillas en lugar de las que se compilan con la estructura de datos de Cómo compilar apps de música para automóviles.MediaBrowser Aun así, debes proporcionar un MediaSession para los controles de reproducción y un MediaBrowserService o MediaLibraryService, que se usan para las recomendaciones y otras experiencias inteligentes.
Configura el manifiesto de tu app
Además de los pasos que se describen en Cómo usar la biblioteca de apps de Android para vehículos, las apps de contenido multimedia basadas en plantillas deben cumplir con los siguientes requisitos:
Declara la compatibilidad de categoría en tu manifiesto
Tu app debe declarar la categoría de app para vehículos androidx.car.app.category.MEDIA en el filtro de intents de su 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>
Para obtener acceso a MediaPlaybackTemplate, tu app también debe declarar el permiso androidx.car.app.MEDIA_TEMPLATES en su archivo de manifiesto:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.MEDIA_TEMPLATES"/>
...
</manifest>
Cómo establecer el nivel mínimo de API de la app para vehículos
Las apps de contenido multimedia que usan MediaPlaybackTemplate solo se admiten en la API de CAL 8 y versiones posteriores. Asegúrate de que tu Car App API level mínimo esté establecido en 8.
<application ...>
...
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="8"/>
...
</application>
Proporciona un ícono de atribución
Asegúrate de agregar un ícono de atribución para las apps de medios creadas con la Biblioteca de apps para vehículos.
Declara la compatibilidad con Android Auto
Asegúrate de que se incluya lo siguiente en el manifiesto de tu app:
<application>
...
<meta-data android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
Luego, agrega la declaración template a automotive_app_desc.xml en tus recursos XML. Debería tener el siguiente aspecto:
<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
<uses name="media"/>
<uses name="template"/>
</automotiveApp>
Cómo declarar la compatibilidad con el SO Android Automotive
Existen dos formas diferentes de distribuir una app de música habilitada para la biblioteca de Car App en el SO Android Automotive: como un solo APK o como dos APKs separados. Si distribuyes un solo APK, este admitirá vehículos habilitados para el SO Android Automotive con el host de la biblioteca de Car App y recurrirá a una aplicación de MediaBrowserService o MediaLibraryService si no es así, incluso para versiones anteriores de Android (Android 10 a Android 13). Si decides distribuir dos APKs separados, podrás actualizar más fácilmente las nuevas incorporaciones a la versión de la biblioteca de Car App sin temor a afectar la versión MediaBrowserService o MediaLibraryService de tu app.
Distribuye un solo APK
Cuando distribuyas un solo APK para la Biblioteca de apps para vehículos y las versiones MediaBrowserService o MediaLibraryService de tu app, es fundamental que configures "android:required="false".
<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>
A continuación, sigue los lineamientos de la Car App Library para AAOS y presenta una CarAppActivity que se pueda iniciar (o actividad de trampolín). Debes establecer la actividad en android:enabled="false" en el manifiesto. A continuación, agrega una etiqueta de metadatos a la declaración MediaBrowserService que indique el componente CarAppActivity como reemplazo. Consulta el siguiente manifiesto de ejemplo:
<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>
Distribución en Play
Tu APK con la biblioteca de Car App y MediaBrowserService o MediaLibraryService debe habilitarse con un código de versión más alto y minSdk orientado a Android 14 (34).
Distribución con dos APKs
Para distribuir dos APKs separados, uno con la Biblioteca de apps para vehículos y otro con MediaBrowserService o MediaLibraryService, sigue estos pasos para asegurarte de que las capacidades correctas del vehículo se segmenten de forma adecuada.
Cuando crees un APK independiente para la versión de la biblioteca de Car App de tu app, debes establecer android.software.car.templates_host.media en android:required=true. Esto garantiza que la app solo se distribuya en compilaciones del SO Android Automotive certificadas con compatibilidad para el host de la biblioteca de Car App.
<uses-feature android:name="android.software.car.templates_host.media" android:required="true"/>
Además de usar android.software.car.templates_host.media y configurarlo como android:required=true, sigue estos pasos para habilitar el SO Android Automotive para tu actividad iniciable de la Biblioteca de Car App.
Distribución en Play
El APK que usa la biblioteca de Car App debe distribuirse en el segmento exclusivo de Automotive OS.
Cómo admitir acciones de voz
Habilita tu app para que se pueda usar con la voz y permite que los usuarios completen acciones comunes sin usar las manos.
Consulta cómo admitir acciones de voz para contenido multimedia para obtener instrucciones de implementación más detalladas. Con una app de medios basada en plantillas, si recibes un comando por voz, no es necesario que actualices tu MediaBrowserService o MediaLibraryService con los resultados de la búsqueda. En su lugar, considera agregar una acción en tu plantilla de reproducción de medios para permitir que el usuario encuentre más contenido en función de esa reproducción o búsqueda. Se requiere admitir comandos por voz para cumplir con el lineamiento de calidad VC-1.
Crea tu plantilla de reproducción
El MediaPlaybackTemplate muestra información sobre la reproducción de contenido multimedia en la app de música de la Biblioteca de apps para vehículos. Esta plantilla permite establecer un encabezado con un título y acciones personalizables, mientras que el host completa la información del contenido multimedia y los controles de reproducción según el estado del objeto MediaSession de tu app.
Figura 1:
MediaPlaybackTemplate con una acción de encabezado para abrir la fila
en la parte superior.
En este ejemplo de código, se muestra cómo compilar una plantilla de reproducción de ejemplo que establece una acción de encabezado que permite al usuario navegar a una pantalla con la fila de canciones.
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()
Cuando uses MediaPlaybackTemplate, registra un token de MediaSession con MediaPlaybackManager en tu CarAppService. De lo contrario, se mostrará un error cuando se envíe un MediaPlaybackTemplate al host.
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 es necesario para exponer la información y los controles de reproducción de contenido multimedia a Android Auto. Esto también es importante para que el host cree notificaciones específicas de contenido multimedia.
En el caso de las apps que usan la biblioteca de Media3, que utilizan un PlatformToken en lugar de un MediaSessionCompat.Token estándar, deberás implementar un SessionCommand personalizado en tu MediaLibrarySession.Callback que devuelva el token de la plataforma subyacente de la sesión: session.platformToken. En tu CarAppService, envía este comando personalizado a la sesión. Una vez que recibas el token de la plataforma, conviértelo con MediaSessionCompat.Token.fromToken(platformToken) y pasa este token de compatibilidad a la biblioteca de Car App en .registerMediaPlaybackToken().
Organiza contenido multimedia con plantillas
Para organizar contenido multimedia para la navegación, como canciones o álbumes, te recomendamos que uses SectionedItemTemplate, que te permite usar GridSection y RowSection juntos para crear diseños que combinen listas de imágenes y elementos de texto.
Figura 2: Un SectionedItemTemplate que contiene un RowSection seguido de un GridSection
Uso de SectionedItemTemplate dentro de un TabTemplate
Una forma conveniente de categorizar los medios en tu app es usar SectionedItemTemplate dentro de un TabTemplate.
val template =
SectionedItemTemplate.Builder()...build();
val tabTemplate =
TabTemplate.Builder(tabCallback)
.setTabContents(TabContents.Builder(template).build)
.setHeaderAction(Action.APP_ICON)
…
.build();
Componentes y funciones de la biblioteca de apps para automóviles 1.9
La versión 1.9 de la API de Car App Library introduce componentes personalizados para capacidades de navegación únicas, como chips, barras de progreso, elementos condensados, encabezados interactivos y expandidos, secciones de Spotlight y banners.
Figura 3: Un SectionedItemTemplate que contiene Chips, Condensed Items, un Interactive Header, Grid Items y un Minimized Control Panel
Figura 4: Dos pantallas de exploración de contenido multimedia con los botones Expanded Header, Spotlight Sections y Progress Bars
Si quieres obtener más información para diseñar la interfaz de usuario de tu app de medios con estas plantillas, consulta Apps de medios.
Cómo navegar a los controles de reproducción
Cuando navega por el contenido multimedia, es importante que el usuario pueda navegar rápidamente hasta el MediaPlaybackTemplate con la menor distracción posible.Para cumplir con el requisito de calidad MFT-1, tu app debe tener una forma de acceder al MediaPlaybackTemplate desde todas las pantallas de navegación de contenido multimedia.
Si usas SectionedItemTemplate, puedes lograr esto agregando un botón de acción que te navegue a la pantalla de reproducción de contenido multimedia. Usa la acción Action.MEDIA_PLAYBACK estándar de la biblioteca de Car App. Una app de medios mostrará esta acción como un panel de control minimizado, que es necesario para cumplir con el requisito de calidad MFT-1 si usas la API de Car App Library 1.9 o una versión posterior. En otras plantillas, una acción de encabezado es otra forma de lograrlo.
Cómo controlar intents de reproducción de contenido multimedia del sistema
Es necesario dirigir al usuario a MediaPlaybackTemplate cuando se inicia una aplicación desde una superficie del sistema que reproduce contenido multimedia, como una tarjeta multimedia. Exigimos que las aplicaciones de medios controlen este Intent Action en orden para proporcionar una experiencia fluida a los usuarios.
Agrega la acción androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK al intent-filter de tu componente de la biblioteca de Car App (CarAppActivity o tu Activity de trampolín).
Asegúrate de que tu actividad use un launchMode de singleTask o singleTop para que se invoque 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>
En tu clase Session, anula onNewIntent() para analizar el intent entrante.
Si la acción del intent entrante coincide con SHOW_MEDIA_PLAYBACK, navega al usuario a la pantalla En reproducción.
@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));
}
}
Si usas una actividad de trampolín, verifica la acción del intent dentro de onCreate(). Pasa esta acción al intent de creación de CarAppActivity antes de llamar a 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();
}
}