Un servicio de entrada de TV representa una fuente de transmisión multimedia y te permite presentar tu contenido multimedia en una la moda lineal y de transmisión de TV, como canales y programas. Con el servicio de entrada de TV, puedes controles parentales, información de la guía de programas y clasificaciones de contenido. Si el servicio de entrada de TV funciona con la app del sistema Android para TV. En última instancia, esta app controla y presenta el contenido del canal en la TV. La app de TV del sistema se desarrolló específicamente para el dispositivo e inmutable por aplicaciones de terceros. Para obtener más información sobre el marco de trabajo de entrada de TV (TIF) arquitectura y sus componentes, consulta Framework de entrada de TV.
Cómo crear un servicio de entrada de TV usando la Biblioteca complementaria del TIF
La Biblioteca complementaria del TIF es un framework implementaciones de funciones comunes del servicio de entrada de TV. Está diseñado para que lo usen los OEMs para crear solo para Android 5.0 (nivel de API 21) hasta Android 7.1 (nivel de API 25).
Cómo actualizar tu proyecto
La Biblioteca complementaria del TIF está disponible para que los OEM la usen de forma heredada en la androidtv-sample-inputs en un repositorio de confianza. Consulta ese repositorio para ver un ejemplo de cómo incluir la biblioteca en una app.
Cómo declarar tu servicio de entrada de TV en el manifiesto
Tu app debe proporcionar un permiso compatible con TvInputService
que el sistema usa para acceder a tu app. El TIF
La Biblioteca complementaria proporciona la clase BaseTvInputService
, que
proporciona una implementación predeterminada de TvInputService
que puedes personalizar. Crea una subclase de BaseTvInputService
.
y declarar la subclase en tu manifiesto como servicio.
Dentro de la declaración del manifiesto, especifica el
BIND_TV_INPUT
para permitir
para conectar la entrada de TV al sistema. Un servicio del sistema
realiza la vinculación y tiene la
BIND_TV_INPUT
.
La app de TV del sistema envía solicitudes a los servicios de entrada de TV.
a través de la interfaz TvInputManager
En tu declaración de servicio, incluye un filtro de intents que especifique
TvInputService
como la acción que se debe realizar con el
. También declara los metadatos del servicio como recurso XML independiente. El
Se muestran la declaración del servicio, el filtro de intents y la declaración de metadatos del servicio.
en el siguiente ejemplo:
<service android:name=".rich.RichTvInputService" android:label="@string/rich_input_label" android:permission="android.permission.BIND_TV_INPUT"> <!-- Required filter used by the system to launch our account service. --> <intent-filter> <action android:name="android.media.tv.TvInputService" /> </intent-filter> <!-- An XML file which describes this input. This provides pointers to the RichTvInputSetupActivity to the system/TV app. --> <meta-data android:name="android.media.tv.input" android:resource="@xml/richtvinputservice" /> </service>
Define los metadatos del servicio en un archivo XML independiente. El servicio El archivo en formato XML de metadatos debe incluir una interfaz de configuración que describa el funcionamiento de configuración inicial y análisis de canales. El archivo de metadatos también debe contener una marca que indica si los usuarios pueden grabar contenido o no. Para ver más información sobre cómo admitir la grabación de contenido en tu app, consulta Admite la grabación de contenido.
El archivo de metadatos del servicio se encuentra en el directorio de recursos XML.
para tu app y debe coincidir con el nombre del recurso que declaraste en el
. Con las entradas del manifiesto del ejemplo anterior, deberías
crea el archivo en formato XML en res/xml/richtvinputservice.xml
, con el
el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?> <tv-input xmlns:android="http://schemas.android.com/apk/res/android" android:canRecord="true" android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />
Cómo definir canales y crear tu actividad de configuración
El servicio de entrada de TV debe definir al menos un canal que los usuarios a través de la app del sistema para TV. Deberías registrar tus canales en la base de datos del sistema y proporcionan una actividad de configuración invoca cuando no puede encontrar un canal para tu app.
Primero, habilita tu app para leer y escribir en el sistema electrónico. Guía de programación (EPG), cuyos datos incluyen los canales y programas disponibles para el usuario. Para permitir que tu app realice estas acciones y realizar la sincronización con la EPG después de reiniciar el dispositivo, agrega los siguientes elementos al manifiesto de la app:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>
Agrega el siguiente elemento para asegurarte de que tu app aparezca en el Google Play Store como una app que proporciona canales de contenido en Android TV:
<uses-feature android:name="android.software.live_tv" android:required="true" />
A continuación, crea una clase que extienda EpgSyncJobService
. Esta clase abstracta facilita la creación de un servicio de trabajo que
crea y actualiza canales en la base de datos del sistema.
En la subclase, crea y muestra la lista completa de canales en
getChannels()
Si tus canales provienen de un archivo XMLTV,
usa la clase XmlTvParser
. De lo contrario, genera
canales de manera programática con la clase Channel.Builder
.
Para cada canal, el sistema llama a getProgramsForChannel()
.
cuando se necesita una lista de programas que se puedan ver en un período determinado
en el canal. Muestra una lista de objetos Program
para el
canal. Usa la clase XmlTvParser
para obtener programas de un
XMLTV o puedes generarlos de forma programática con el
Clase Program.Builder
.
Para cada objeto Program
, usa un
InternalProviderData
para configurar información del programa, como la
el tipo de video del programa. Si solo tienes una cantidad limitada de programas
si quieres que el canal se repita indefinidamente,
Método InternalProviderData.setRepeatable()
con un valor de
true
cuando configures la información del programa.
Después de implementar el servicio de trabajo, agrégalo al manifiesto de tu app:
<service android:name=".sync.SampleJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
Finalmente, crea una actividad de configuración. Tu actividad de configuración debe proporcionar una manera para sincronizar los datos del canal y del programa. Una forma de hacerlo es que el usuario a través de la IU en la actividad. También puedes hacer que la app lo haga automáticamente cuando comienza la actividad. Cuando la actividad de configuración necesita sincronizar los canales y la información del programa, la app debería iniciar el servicio de trabajo:
Kotlin
val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID) EpgSyncJobService.cancelAllSyncRequests(getActivity()) EpgSyncJobService.requestImmediateSync( getActivity(), inputId, ComponentName(getActivity(), SampleJobService::class.java) )
Java
String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID); EpgSyncJobService.cancelAllSyncRequests(getActivity()); EpgSyncJobService.requestImmediateSync(getActivity(), inputId, new ComponentName(getActivity(), SampleJobService.class));
Usa el método requestImmediateSync()
para sincronizar
el servicio de trabajo. El usuario debe esperar a que finalice la sincronización, por lo que
mantén tu período de solicitud relativamente corto.
Usa el método setUpPeriodicSync()
para que el servicio de trabajo
Sincroniza periódicamente los datos de los canales y los programas en segundo plano:
Kotlin
EpgSyncJobService.setUpPeriodicSync( context, inputId, ComponentName(context, SampleJobService::class.java) )
Java
EpgSyncJobService.setUpPeriodicSync(context, inputId, new ComponentName(context, SampleJobService.class));
La Biblioteca complementaria del TIF proporciona un método adicional sobrecargado de
requestImmediateSync()
, que te permite especificar la duración de
que los datos del canal se sincronicen en milisegundos. El método predeterminado sincroniza
de datos del canal.
La Biblioteca complementaria del TIF proporciona un método adicional de sobrecarga
setUpPeriodicSync()
, que te permite especificar la duración de
los datos de cada canal y la frecuencia
con la que se debe realizar la sincronización periódica. El
El método predeterminado sincroniza 48 horas de datos del canal cada 12 horas.
Para obtener más detalles sobre los datos del canal y la EPG, consulta Trabaja con datos del canal.
Cómo manejar solicitudes de sintonización y reproducción de contenido multimedia
Cuando un usuario selecciona un canal específico, la app de TV del sistema usa un
Session
, creado por tu app, para sintonizar el canal solicitado
y reproducir contenido. La Biblioteca complementaria del TIF ofrece
que puedes extender para manejar llamadas de canal y sesión desde el sistema.
La subclase BaseTvInputService
crea sesiones que controlan
ajustar las solicitudes. Anula el
onCreateSession()
, crea una sesión extendida de
la clase BaseTvInputService.Session
y llama a
super.sessionCreated()
con tu nueva sesión. En la siguiente
ejemplo, onCreateSession()
muestra un
Un objeto RichTvInputSessionImpl
que extiende
BaseTvInputService.Session
:
Kotlin
override fun onCreateSession(inputId: String): Session = RichTvInputSessionImpl(this, inputId).apply { setOverlayViewEnabled(true) }
Java
@Override public final Session onCreateSession(String inputId) { RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId); session.setOverlayViewEnabled(true); return session; }
Cuando el usuario utiliza la app de TV del sistema para comenzar a ver uno de tus canales,
el sistema llama al método onPlayChannel()
de tu sesión. Anular
este método si necesitas realizar una inicialización especial de canales antes de
comienza a reproducirse el programa.
Luego, el sistema obtiene el programa programado en ese momento y llama a tu
método onPlayProgram()
de la sesión, que especifica el programa
información y el tiempo de inicio en milisegundos. Usa el
TvPlayer
para comenzar a reproducir el programa.
El código de tu reproductor multimedia debería implementar TvPlayer
para controlar.
eventos de reproducción específicos. La clase TvPlayer
controla las funciones
como controles de pausa en directo sin agregar complejidad a tu
Implementación de BaseTvInputService
.
En el método getTvPlayer()
de tu sesión, muestra
el reproductor multimedia que implementa TvPlayer
. El
La app de ejemplo de servicio de entrada de TV implementa un reproductor multimedia que usa
ExoPlayer.
Cómo crear un servicio de entrada de TV con el marco de trabajo de entrada de TV
Si tu servicio de entrada de TV no puede usar la Biblioteca complementaria del TIF, debes hacer lo siguiente: para implementar los siguientes componentes:
TvInputService
proporciona disponibilidad de larga duración y en segundo plano para la entrada de TVTvInputService.Session
mantiene el estado de la entrada de TV y se comunica. con la app de hostingTvContract
, que describe los canales y programas disponibles para la TV. entradaTvContract.Channels
, que representa información acerca de un canal de TV.TvContract.Programs
describe un programa de TV con datos, como el programa. título y hora de inicioTvTrackInfo
, que representa una pista de audio, video o subtítulo.TvContentRating
describe una clasificación de contenido y permite contenido personalizado. esquemas de calificaciónTvInputManager
proporciona una API a la app de TV del sistema y administra. la interacción con entradas de TV y apps
También debes realizar lo siguiente:
- Declara tu servicio de entrada de TV en el manifiesto, como se muestra a continuación: que se describe en Cómo declarar tu servicio de entrada de TV en la .
- Crea el archivo de metadatos del servicio.
- Crea y registra la información del canal y el programa.
- Crea la actividad de configuración.
Cómo definir tu servicio de entrada de TV
Para tu servicio, extiende la clase TvInputService
. R
La implementación de TvInputService
es una
servicio vinculado donde el servicio del sistema
es el cliente que se vincula a él. Los métodos del ciclo de vida del servicio
que debes implementar, se ilustran en la figura 1.
El método onCreate()
inicializa e inicia la
HandlerThread
, que proporciona un subproceso independiente del subproceso de IU para
gestionar acciones impulsadas por el sistema. En el siguiente ejemplo, onCreate()
inicializa el objeto CaptioningManager
y se prepara para controlar
ACTION_BLOCKED_RATINGS_CHANGED
y ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED
. Estos
acciones describen los intents del sistema que se activan cuando el usuario cambia la configuración de los controles parentales
se realizó un cambio en la lista de clasificaciones bloqueadas.
Kotlin
override fun onCreate() { super.onCreate() handlerThread = HandlerThread(javaClass.simpleName).apply { start() } dbHandler = Handler(handlerThread.looper) handler = Handler() captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager setTheme(android.R.style.Theme_Holo_Light_NoActionBar) sessions = mutableListOf<BaseTvInputSessionImpl>() val intentFilter = IntentFilter().apply { addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED) addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED) } registerReceiver(broadcastReceiver, intentFilter) }
Java
@Override public void onCreate() { super.onCreate(); handlerThread = new HandlerThread(getClass() .getSimpleName()); handlerThread.start(); dbHandler = new Handler(handlerThread.getLooper()); handler = new Handler(); captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); setTheme(android.R.style.Theme_Holo_Light_NoActionBar); sessions = new ArrayList<BaseTvInputSessionImpl>(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(TvInputManager .ACTION_BLOCKED_RATINGS_CHANGED); intentFilter.addAction(TvInputManager .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED); registerReceiver(broadcastReceiver, intentFilter); }
![](https://developer.android.com/static/images/tv/tvinput-life.png?hl=es-419)
Figura 1: Ciclo de vida de TvInputService
Consulta
Controla el contenido para obtener más información sobre cómo trabajar con contenido bloqueado y proporcionar
con los controles parentales. Consulta TvInputManager
para ver más acciones impulsadas por el sistema que
que recomendamos en tu servicio de entrada de TV.
TvInputService
crea un
TvInputService.Session
que implementa Handler.Callback
para manejar los cambios de estado del reproductor. Con
onSetSurface()
,
TvInputService.Session
establece Surface
con el
contenido de video. Consulta Cómo integrar el jugador con la plataforma
y obtén más información para trabajar con Surface
en la renderización de videos.
TvInputService.Session
controla las
onTune()
cuando el usuario selecciona un canal, y notifica a la app de TV del sistema cuando hay cambios en el contenido y
metadatos de contenido. Estos métodos notify()
se describen en
Cómo controlar el contenido y Cómo controlar la selección de pistas
más adelante en esta capacitación.
Cómo definir la actividad de configuración
La app de TV del sistema funciona con la actividad de configuración que defines para tu entrada de TV. El la actividad de configuración es obligatoria y debe proporcionar al menos un registro de canal para la base de datos del sistema. El la app de TV del sistema invoca la actividad de configuración cuando no puede encontrar un canal para la entrada de TV.
La actividad de configuración describe a la app de TV del sistema los canales disponibles a través de la TV. entrada, como se demuestra en la siguiente lección, Crear y actualizar los datos de los canales.