Las apps de música que usan las plantillas de la Biblioteca de apps para vehículos pueden personalizar su experiencia de exploración y reproducción de contenido multimedia, al mismo tiempo que se aseguran de que la experiencia esté optimizada para las pantallas de los automóviles y minimice las distracciones mientras se conduce.
En esta guía, se supone 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 apps para vehículos te permite reemplazar la experiencia en la app con
plantillas en lugar de las que se compilan con la estructura de datos 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 usa para recomendaciones y otras experiencias inteligentes.
Cómo configurar 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, se requieren los siguientes elementos para las apps de música basadas en plantillas:
Declara la compatibilidad de categoría en tu manifiesto
Tu app debe declarar la androidx.car.app.category.MEDIA
categoría de app para vehículos 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 configurar el nivel de API mínimo de la app para vehículos
Las apps de música que usan MediaPlaybackTemplate solo son compatibles con la API de CAL 8 y
versiones posteriores. Asegúrate de que tu Car App API level mínimo esté configurado 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 música compiladas 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 de plantilla a automotive_app_desc.xml en tus recursos XML. Debería verse de la siguiente manera:
<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
<uses name="media"/>
<uses name="template"/>
</automotiveApp>
Declara la compatibilidad con el SO Android Automotive
Existen dos formas diferentes de distribuir una app de música habilitada para la Biblioteca de apps para vehículos en el SO Android Automotive: como un solo APK o como dos APK separados. Si distribuyes un solo APK, admitirá vehículos habilitados para el SO Android Automotive con el host de la Biblioteca de apps para vehículos y volverá a una aplicación MediaBrowserService o MediaLibraryService si no es así, incluso para versiones anteriores de Android (Android 10 a Android 13). Si eliges distribuir dos APK separados, puedes actualizar más fácilmente las nuevas incorporaciones a la versión de la Biblioteca de apps para vehículos sin temor a afectar la versión MediaBrowserService o MediaLibraryService de tu app.
Cómo distribuir un solo APK
Cuando distribuyes un solo APK para la Biblioteca de apps para vehículos y MediaBrowserService
o MediaLibraryService versiones de tu app, es fundamental configurar
"android:required="false".
<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>
A continuación, sigue los lineamientos de la Biblioteca de apps para vehículos para AAOS y
presenta una que se pueda iniciar CarAppActivity (o actividad de trampolín). Debes configurar la actividad en android:enabled="false" en el manifiesto. Luego, agrega una etiqueta de metadatos a la declaración MediaBrowserService que indique el componente CarAppActivity como el 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 de Play
Tu APK con la Biblioteca de apps para vehículos y MediaBrowserService o MediaLibraryService debe habilitarse con un código de versión más alto y minSdk orientado a Android 14 (34).
Cómo distribuir con dos APKs
Para distribuir dos APK separados, uno que use la Biblioteca de apps para vehículos y otro que use MediaBrowserService o MediaLibraryService, sigue estos pasos para asegurarte de que las capacidades correctas del vehículo se orienten correctamente.
Cuando crees un APK independiente para la versión de la Biblioteca de apps para vehículos de tu app, debes configurar android.software.car.templates_host.media en android:required=true. Esto garantiza que la app se distribuya solo en compilaciones del SO Android Automotive certificadas con compatibilidad para el host de la Biblioteca de apps para vehículos.
<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 en
android:required=true anteriormente, sigue estos pasos para habilitar el SO Android Automotive
para tu actividad de la Biblioteca de apps para vehículos que se puede iniciar.
Distribución de Play
El APK que usa la Biblioteca de apps para vehículos debe distribuirse en el segmento dedicado de Automotive OS.
Cómo admitir acciones de voz
Habilita la voz en tu app para permitir 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 música basada en plantillas, si recibes un comando de voz, no necesitas actualizar 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 contenido multimedia para permitir que el usuario encuentre más contenido en función de esa reproducción o consulta de búsqueda. Se requiere la compatibilidad con comandos de voz para cumplir con el VC-1 lineamiento de calidad.
Crea tu plantilla de reproducción
El MediaPlaybackTemplate muestra información de reproducción de contenido multimedia
en tu app de música de la Biblioteca de apps para vehículos. Esta plantilla permite configurar un
encabezado con un título y acciones personalizables, mientras que el host completa la información de contenido multimedia y los
controles de reproducción según el estado de MediaSession de tu app.
Figura 1:
MediaPlaybackTemplate con una acción de encabezado para abrir la cola 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 cola 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 usas MediaPlaybackTemplate, registra un
MediaSession token con MediaPlaybackManager en tu
CarAppService. Si no lo haces, 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 usan un PlatformToken en lugar de un MediaSessionCompat.Token estándar, deberás implementar un SessionCommand personalizado en tu MediaLibrarySession.Callback que muestre el token de 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 plataforma, conviértelo con MediaSessionCompat.Token.fromToken(platformToken) y pasa este token de compatibilidad a la Biblioteca de apps para vehículos en .registerMediaPlaybackToken().
Organiza el contenido multimedia con plantillas
Para organizar el contenido multimedia para la exploración, como canciones o álbumes, te recomendamos que uses la
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
Cómo usar SectionedItemTemplate dentro de TabTemplate
Una forma conveniente de categorizar el contenido multimedia dentro de tu app es usar el
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 vehículos 1.9
La versión 1.9 de la API de la Biblioteca de apps para vehículos presenta componentes personalizados para capacidades de exploración únicas, como chips, barras de progreso, elementos condensados, encabezado interactivo y expandido, secciones destacadas 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 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 música con esas plantillas, consulta el documento sobre apps de música.
Cómo navegar a los controles de reproducción
Cuando se explora el contenido multimedia, es importante que el usuario pueda navegar rápidamente a MediaPlaybackTemplate con una distracción mínima.Para cumplir con el requisito de calidad MFT-1, tu app debe tener una forma de acceder a MediaPlaybackTemplate desde todas las pantallas de exploración de contenido multimedia.
Si usas SectionedItemTemplate, puedes lograrlo agregando un
botón de acción que te dirija a la pantalla de reproducción de contenido multimedia. Usa la acción Action.MEDIA_PLAYBACK estándar de la Biblioteca de apps para vehículos. Una app de música 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 1.9 de la Biblioteca de apps para vehículos o versiones posteriores. Para 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 plataforma del sistema que reproduce contenido multimedia, como una tarjeta de contenido multimedia. Requerimos que las aplicaciones de contenido multimedia controlen esta Intent Action para
brindar una experiencia fluida a los usuarios.
Agrega la acción androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK al
filtro de intents de tu componente de la Biblioteca de apps para vehículos (ya sea 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 de intent entrante coincide con SHOW_MEDIA_PLAYBACK, dirige al usuario a la pantalla de 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, busca la acción de 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();
}
}