Votre entrée TV doit fournir les données du guide des programmes électronique (EPG) pendant au moins un canal dans son activité de configuration. Vous devez également mettre régulièrement à jour données, en tenant compte de la taille de la mise à jour et du thread de traitement qui le gère. Vous pouvez également fournir des liens vers l'application pour les chaînes. qui guident l'utilisateur vers du contenu et des activités connexes. Cette leçon explique comment créer et mettre à jour les données d'une chaîne et d'un programme la base de données système en tenant compte de ces considérations.
Essayez le Exemple d'application TV Input Service.
Obtenir l'autorisation
Pour que votre entrée TV fonctionne avec les données EPG, elle doit déclarer l'élément l'autorisation d'écriture dans son fichier manifeste Android, comme suit:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Enregistrer des canaux dans la base de données
La base de données du système Android TV conserve des enregistrements des données de chaîne pour les entrées TV. Dans votre configuration
d'activité, pour chacun de vos canaux, vous devez mapper les données de votre chaîne avec les champs suivants de la
Classe TvContract.Channels
:
COLUMN_DISPLAY_NAME
: le nom à afficher canalCOLUMN_DISPLAY_NUMBER
: chaîne affichée numéroCOLUMN_INPUT_ID
: ID du service d'entrée TVCOLUMN_SERVICE_TYPE
: type de service du canalCOLUMN_TYPE
: norme de diffusion de la chaîne TypeCOLUMN_VIDEO_FORMAT
(format vidéo par défaut) pour la chaîne
Bien que le cadre d'entrée TV soit suffisamment générique pour gérer à la fois la diffusion traditionnelle et de service de distribution par contournement (OTT, over-the-top) sans distinction, vous pouvez définir les colonnes suivantes dans en plus de celles mentionnées ci-dessus afin de mieux identifier les chaînes de diffusion traditionnelles:
COLUMN_ORIGINAL_NETWORK_ID
: la télévision ID de réseauCOLUMN_SERVICE_ID
: ID du serviceCOLUMN_TRANSPORT_STREAM_ID
: flux de transport ID
Si vous souhaitez fournir des liens vers une application pour vos chaînes, vous devez : mettre à jour quelques champs supplémentaires. Pour en savoir plus sur les champs de lien d'application, consultez Ajoutez des informations sur les liens vers une application.
Pour les entrées TV basées sur le streaming sur Internet, attribuez vos propres valeurs aux valeurs ci-dessus en conséquence. chaque canal peut être identifié de manière unique.
Extrayez les métadonnées de votre chaîne (au format XML, JSON ou autre) depuis votre serveur backend et dans votre configuration. l'activité mappe les valeurs à la base de données système comme suit:
Kotlin
val values = ContentValues().apply { put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, channel.number) put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.name) put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId) put(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId) put(TvContract.Channels.COLUMN_SERVICE_ID, channel.serviceId) put(TvContract.Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat) } val uri = context.contentResolver.insert(TvContract.Channels.CONTENT_URI, values)
Java
ContentValues values = new ContentValues(); values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.number); values.put(Channels.COLUMN_DISPLAY_NAME, channel.name); values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId); values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId); values.put(Channels.COLUMN_SERVICE_ID, channel.serviceId); values.put(Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat); Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
Dans l'exemple ci-dessus, channel
est un objet qui contient les métadonnées de la chaîne provenant du
à un serveur backend.
Présenter des informations sur la chaîne et le programme
L'appli System TV présente des informations sur les chaînes et les programmes aux utilisateurs lorsqu'ils parcourent les chaînes. comme illustré dans la figure 1. Pour s'assurer que les informations de la chaîne et du programme fonctionnent avec le système les informations sur la chaîne et le programme, suivez les consignes ci-dessous.
- Numéro de la chaîne (
COLUMN_DISPLAY_NUMBER
) - Icône
(
android:icon
dans le fichier manifeste de l'entrée TV) - Program description (Description du programme) (
COLUMN_SHORT_DESCRIPTION
) - Titre du programme (
COLUMN_TITLE
) - Logo de la chaîne (
TvContract.Channels.Logo
) <ph type="x-smartling-placeholder">- </ph>
- Utilisez la couleur #EEEEEE pour faire correspondre le texte environnant.
- Ne pas inclure de marge intérieure
- Poster art (
COLUMN_POSTER_ART_URI
) <ph type="x-smartling-placeholder">- </ph>
- Format entre 16:9 et 4:3
L'appli System TV fournit les mêmes informations via le guide des programmes, y compris l'affiche, comme illustré dans la figure 2.
Mettre à jour les données de la chaîne
Lorsque vous mettez à jour les données d'un canal existant, utilisez le
update()
au lieu de supprimer et d'ajouter à nouveau les données. Vous pouvez identifier la version actuelle des données
en utilisant Channels.COLUMN_VERSION_NUMBER
et Programs.COLUMN_VERSION_NUMBER
lorsque vous choisissez les enregistrements à mettre à jour.
Remarque:Ajouter les données de la chaîne au ContentProvider
peut prendre du temps. Ajouter les programmes en cours (ceux qui se trouvent à moins de deux heures de l'heure actuelle)
uniquement lorsque vous configurez votre EpgSyncJobService
pour mettre à jour le reste
des données de la chaîne en arrière-plan. Voir
le <ph type="x-smartling-placeholder"></ph>
Exemple d'application Android TV Live TV.
Chargement par lot des données de canaux
Lorsque vous mettez à jour la base de données système avec une grande quantité de données de canaux, utilisez ContentResolver
applyBatch()
ou
bulkInsert()
. Voici un exemple avec applyBatch()
:
Kotlin
val ops = ArrayList<ContentProviderOperation>() val programsCount = channelInfo.mPrograms.size channelInfo.mPrograms.forEachIndexed { index, program -> ops += ContentProviderOperation.newInsert( TvContract.Programs.CONTENT_URI).run { withValues(programs[index]) withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000) withValue( TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, (programStartSec + program.durationSec) * 1000 ) build() } programStartSec += program.durationSec if (index % 100 == 99 || index == programsCount - 1) { try { contentResolver.applyBatch(TvContract.AUTHORITY, ops) } catch (e: RemoteException) { Log.e(TAG, "Failed to insert programs.", e) return } catch (e: OperationApplicationException) { Log.e(TAG, "Failed to insert programs.", e) return } ops.clear() } }
Java
ArrayList<ContentProviderOperation> ops = new ArrayList<>(); int programsCount = channelInfo.mPrograms.size(); for (int j = 0; j < programsCount; ++j) { ProgramInfo program = channelInfo.mPrograms.get(j); ops.add(ContentProviderOperation.newInsert( TvContract.Programs.CONTENT_URI) .withValues(programs.get(j)) .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000) .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, (programStartSec + program.durationSec) * 1000) .build()); programStartSec = programStartSec + program.durationSec; if (j % 100 == 99 || j == programsCount - 1) { try { getContentResolver().applyBatch(TvContract.AUTHORITY, ops); } catch (RemoteException | OperationApplicationException e) { Log.e(TAG, "Failed to insert programs.", e); return; } ops.clear(); } }
Traiter les données des canaux de manière asynchrone
La manipulation des données, telle que l’extraction d’un flux du serveur ou l’accès à la base de données, doit
et non à bloquer le thread UI. L'utilisation d'un AsyncTask
permet
d'effectuer des mises à jour de manière asynchrone. Par exemple, lorsque vous chargez des informations
de canal à partir d'un serveur backend,
vous pouvez utiliser AsyncTask
comme suit:
Kotlin
private class LoadTvInputTask(val context: Context) : AsyncTask<Uri, Unit, Unit>() { override fun doInBackground(vararg uris: Uri) { try { fetchUri(uris[0]) } catch (e: IOException) { Log.d("LoadTvInputTask", "fetchUri error") } } @Throws(IOException::class) private fun fetchUri(videoUri: Uri) { context.contentResolver.openInputStream(videoUri).use { inputStream -> Xml.newPullParser().also { parser -> try { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) parser.setInput(inputStream, null) sTvInput = ChannelXMLParser.parseTvInput(parser) sSampleChannels = ChannelXMLParser.parseChannelXML(parser) } catch (e: XmlPullParserException) { e.printStackTrace() } } } } }
Java
private static class LoadTvInputTask extends AsyncTask<Uri, Void, Void> { private Context mContext; public LoadTvInputTask(Context context) { mContext = context; } @Override protected Void doInBackground(Uri... uris) { try { fetchUri(uris[0]); } catch (IOException e) { Log.d("LoadTvInputTask", "fetchUri error"); } return null; } private void fetchUri(Uri videoUri) throws IOException { InputStream inputStream = null; try { inputStream = mContext.getContentResolver().openInputStream(videoUri); XmlPullParser parser = Xml.newPullParser(); try { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(inputStream, null); sTvInput = ChannelXMLParser.parseTvInput(parser); sSampleChannels = ChannelXMLParser.parseChannelXML(parser); } catch (XmlPullParserException e) { e.printStackTrace(); } } finally { if (inputStream != null) { inputStream.close(); } } } }
Si vous devez mettre à jour les données EPG régulièrement, envisagez d'utiliser
WorkManager
pour exécuter le processus de mise à jour en cas d'inactivité, par exemple tous les jours à 3h du matin.
D'autres techniques permettant de séparer les tâches de mise à jour de données du thread UI incluent l'utilisation de la méthode
HandlerThread
, ou vous pouvez implémenter la vôtre à l'aide de Looper
et Handler
. Voir <ph type="x-smartling-placeholder"></ph>
Processus et threads.
Ajouter des informations sur le lien vers l'application
Les chaînes peuvent utiliser des liens vers l'application pour permettre aux utilisateurs de lancer facilement une vidéo associée pendant qu'ils regardent le contenu de la chaîne. Version de la chaîne utilisée par les applis des liens vers l'application pour accroître l'engagement utilisateur en lançant des activités qui montrent les informations associées ou tout autre contenu. Par exemple, vous pouvez utiliser des liens d'application pour effectuer les opérations suivantes:
- Guidez l'utilisateur pour qu'il découvre et achète du contenu associé.
- Fournissez des informations supplémentaires sur le contenu en cours de lecture.
- Lorsque vous regardez des épisodes, commencez à regarder l'épisode suivant dans de la série.
- Permettre à l'utilisateur d'interagir avec le contenu (par exemple, donner une note ou un avis) sans interrompre la lecture.
Les liens vers l'application s'affichent lorsque l'utilisateur appuie sur Sélectionner pour afficher Menu TV lorsque vous regardez le contenu de la chaîne.
Lorsque l'utilisateur sélectionne le lien vers l'application, le système lance une activité en utilisant un URI d'intent spécifié par l'application de canal. La lecture du contenu de la chaîne continue lorsque l'activité des liens vers une application est active. L'utilisateur peut revenir à la chaîne. le contenu en appuyant sur Retour.
Fournir les données de canal de lien d'application
Android TV crée automatiquement un lien d'application pour chaque chaîne.
à l'aide des informations
des données de la chaîne. Pour fournir des informations sur les liens vers une application,
spécifiez les informations suivantes dans votre
Champs TvContract.Channels
:
COLUMN_APP_LINK_COLOR
: le couleur d'accentuation du lien vers l'application pour cette chaîne. Pour un exemple de couleur d’accentuation, voir figure 2, légende 3.COLUMN_APP_LINK_ICON_URI
– URI de l'icône du badge d'application du lien d'application pour cette chaîne. Pour une exemple de l'icône de badge d'application (voir figure 2, légende 2).COLUMN_APP_LINK_INTENT_URI
– URI d'intent du lien vers l'application pour cette chaîne. Vous pouvez créer l'URI en utilisanttoUri(int)
avecURI_INTENT_SCHEME
et reconvertissez l'URI dans l'intent d'origine avecparseUri()
COLUMN_APP_LINK_POSTER_ART_URI
- URI de l'affiche utilisée comme arrière-plan du lien vers l'application pour cette chaîne. Pour obtenir un exemple d'image poster, consultez la figure 2, légende 1.COLUMN_APP_LINK_TEXT
– Texte descriptif du lien vers l'application pour cette chaîne. Exemple : description du lien vers l'application (voir le texte de la figure 2, légende 3).
Si les données de la chaîne n'indiquent pas d'informations sur les liens vers une application, le système crée un lien d'application par défaut. Le système choisit les détails par défaut comme suit:
- Pour l'URI de l'intent
(
COLUMN_APP_LINK_INTENT_URI
), le système utiliseACTION_MAIN
activité pour la catégorieCATEGORY_LEANBACK_LAUNCHER
, généralement définie dans le fichier manifeste de l'application. Si cette activité n'est pas définie, un lien d'application non fonctionnel s'affiche. l'utilisateur clique dessus, rien ne se passe. - Pour le texte descriptif
(
COLUMN_APP_LINK_TEXT
) : le système utilise "Ouvrir app-name". Si aucun URI d'intent de lien d'application viable n'est défini, le système utilise "Aucun lien disponible". - Pour la couleur d'accentuation
(
COLUMN_APP_LINK_COLOR
), le système utilise la couleur par défaut de l'application. - Pour l'image poster
(
COLUMN_APP_LINK_POSTER_ART_URI
), le système utilise la bannière de l'écran d'accueil de l'application. Si l'application ne fournit pas le système utilise une image par défaut de l'application TV. - Pour l'icône du badge
(
COLUMN_APP_LINK_ICON_URI
), le utilise un badge indiquant le nom de l'application. Si le système utilise également de la bannière de l'application ou de l'image poster par défaut, aucun badge d'application n'est affiché.
Vous pouvez spécifier les détails des liens d'application pour vos chaînes dans la section
activité de configuration. Vous pouvez modifier ces informations
à tout moment.
Si un lien d'application doit correspondre aux modifications apportées à la version, mettez à jour l'application
détails du lien et appel
ContentResolver.update()
si nécessaire. Pour en savoir plus sur la mise à jour
données de canal, consultez Mettre à jour les données de la chaîne.