Ihr TV-Eingang muss in seiner Einrichtung mindestens für einen Kanal Daten der elektronischen Programmübersicht (EPG) bereitstellen. Sie sollten diese Daten auch regelmäßig aktualisieren und dabei die Größe des Updates und den Verarbeitungsthread berücksichtigen, der es verarbeitet. Außerdem können Sie App-Links für Kanäle bereitstellen, die den Nutzer zu ähnlichen Inhalten und Aktivitäten führen. In dieser Lektion wird beschrieben, wie Sie Kanal- und Programmdaten in der Systemdatenbank erstellen und aktualisieren.
Probieren Sie die Beispiel-App für den TV-Eingabedienst aus.
Berechtigung einholen
Damit Ihr TV-Eingang mit EPG-Daten funktioniert, muss er die Schreibberechtigung in seiner Android-Manifestdatei wie folgt deklarieren:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Kanäle in der Datenbank registrieren
In der Android TV-Systemdatenbank werden Datensätze mit Kanaldaten für TV-Eingänge verwaltet. In Ihrer Einrichtung müssen Sie für jeden Ihrer Kanäle Ihre Kanaldaten den folgenden Feldern der Klasse TvContract.Channels zuordnen:
COLUMN_DISPLAY_NAME: der angezeigte Name des KanalsCOLUMN_DISPLAY_NUMBER: die angezeigte Kanal nummerCOLUMN_INPUT_ID: die ID des TV-EingabedienstesCOLUMN_SERVICE_TYPE: der Diensttyp des KanalsCOLUMN_TYPE: der Übertragungsstandard typ des KanalsCOLUMN_VIDEO_FORMAT: das Standardvideoformat für den Kanal
Das TV-Eingabe-Framework ist zwar allgemein genug, um sowohl herkömmliche Übertragungen als auch Over-the-Top-Inhalte (OTT) ohne Unterschied zu verarbeiten, aber Sie können zusätzlich die folgenden Spalten definieren, um herkömmliche Übertragungskanäle besser zu identifizieren:
COLUMN_ORIGINAL_NETWORK_ID: die ID des FernsehsendersCOLUMN_SERVICE_ID: die Dienst-IDCOLUMN_TRANSPORT_STREAM_ID: die Transportstream ID
Wenn Sie Details zu App-Links für Ihre Kanäle angeben möchten, müssen Sie einige zusätzliche Felder aktualisieren. Weitere Informationen zu App-Link-Feldern finden Sie unter Informationen zu App-Links hinzufügen.
Weisen Sie TV-Eingängen, die auf Internetstreaming basieren, eigene Werte zu, damit jeder Kanal eindeutig identifiziert werden kann.
Rufen Sie Ihre Kanalmetadaten (in XML, JSON oder einem anderen Format) von Ihrem Back-End-Server ab und ordnen Sie die Werte in Ihrer Einrichtung wie folgt der Systemdatenbank zu:
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);
In diesem Beispiel ist channel ein Objekt, das Kanalmetadaten vom Back-End-Server enthält.
Kanal- und Programminformationen präsentieren
In der System-TV-App werden Nutzern Kanal- und Programminformationen präsentiert, wenn sie durch die Kanäle blättern (siehe Abbildung 1). Damit die Kanal- und Programminformationen mit der Präsentation von Kanal- und Programminformationen der System-TV-App funktionieren, müssen Sie die folgenden Richtlinien beachten:
- Kanalnummer (
COLUMN_DISPLAY_NUMBER) - Symbol
(
android:iconim Manifest des TV-Eingangs) - Programmbeschreibung (
COLUMN_SHORT_DESCRIPTION) - Programmtitel (
COLUMN_TITLE) - Kanallogo (
TvContract.Channels.Logo)- Verwenden Sie die Farbe #EEEEEE, damit sie mit dem umgebenden Text übereinstimmt.
- Fügen Sie keinen Abstand ein.
- Posterbild (
COLUMN_POSTER_ART_URI) - Seitenverhältnis zwischen 16:9 und 4:3
In der System-TV-App werden dieselben Informationen in der Programmübersicht angezeigt, einschließlich Posterbild (siehe Abbildung 2).
Kanaldaten aktualisieren
Wenn Sie vorhandene Kanaldaten aktualisieren, verwenden Sie die Methode update, anstatt die Daten zu löschen und neu hinzuzufügen. Sie können die aktuelle Version der Daten mit Channels.COLUMN_VERSION_NUMBER und Programs.COLUMN_VERSION_NUMBER identifizieren, wenn Sie die zu aktualisierenden Datensätze auswählen.
Hinweis:Das Hinzufügen von Kanaldaten zum ContentProvider kann einige Zeit dauern. Fügen Sie aktuelle Programme (innerhalb von zwei Stunden nach der aktuellen Zeit) nur hinzu, wenn Sie Ihren EpgSyncJobService so konfigurieren, dass die restlichen Kanaldaten im Hintergrund aktualisiert werden. Ein Beispiel finden Sie in der
Beispiel-App für Android TV Live-TV.
Kanaldaten im Batch laden
Wenn Sie die Systemdatenbank mit einer großen Menge an Kanaldaten aktualisieren, verwenden Sie die Methode applyBatch oder bulkInsert von ContentResolver. Hier ist ein Beispiel mit 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(); } }
Kanaldaten asynchron verarbeiten
Datenmanipulationen wie das Abrufen eines Streams vom Server oder der Zugriff auf die Datenbank sollten den UI-Thread nicht blockieren. Eine Möglichkeit, Aktualisierungen asynchron auszuführen, ist die Verwendung von AsyncTask. Wenn Sie beispielsweise Kanalinformationen von einem Back-End-Server laden, können Sie AsyncTask so verwenden:
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(); } } } }
Wenn Sie EPG-Daten regelmäßig aktualisieren müssen, sollten Sie
WorkManager
verwenden, um den Aktualisierungsprozess in der Leerlaufzeit auszuführen, z. B. täglich um 3:00 Uhr.
Andere Methoden, um die Aufgaben zur Datenaktualisierung vom UI-Thread zu trennen, sind die Verwendung der
HandlerThread Klasse oder die Implementierung einer eigenen Methode mit den Looper
und Handler Klassen. Weitere Informationen finden Sie unter
Prozesse und Threads.
Informationen zu App-Links hinzufügen
Kanäle können App-Links verwenden, damit Nutzer eine zugehörige Aktivität starten können, während sie sich Kanalinhalte ansehen. Kanal-Apps verwenden App-Links, um die Nutzerinteraktion zu erhöhen, indem sie Aktivitäten starten, die zugehörige Informationen oder zusätzliche Inhalte anzeigen. Sie können App-Links beispielsweise für Folgendes verwenden:
- Nutzer zu ähnlichen Inhalten führen, die sie entdecken und kaufen können
- Zusätzliche Informationen zu aktuell wiedergegebenen Inhalten bereitstellen
- Beim Ansehen von Episodeninhalten die nächste Folge einer Serie starten
- Nutzer mit Inhalten interagieren lassen, z. B. Inhalte bewerten oder Rezensionen schreiben, ohne die Wiedergabe zu unterbrechen
App-Links werden angezeigt, wenn der Nutzer Auswählen drückt, um das TV-Menü aufzurufen, während er sich Kanalinhalte ansieht.
Abbildung 1 : Ein Beispiel für einen App-Link, der in der Zeile Kanäle angezeigt wird, während Kanalinhalte wiedergegeben werden.
Wenn der Nutzer den App-Link auswählt, startet das System eine Aktivität mit einem Intent-URI, der von der Kanal-App angegeben wird. Die Wiedergabe der Kanalinhalte wird fortgesetzt, während die App-Link-Aktivität aktiv ist. Der Nutzer kann zu den Kanalinhalten zurückkehren, indem er Zurück drückt.
Kanaldaten für App-Links bereitstellen
Android TV erstellt automatisch einen App-Link für jeden Kanal, wobei Informationen aus den Kanaldaten verwendet werden. Geben Sie die folgenden Details in den Feldern TvContract.Channels an, um Informationen zu App-Links bereitzustellen:
COLUMN_APP_LINK_COLOR: die Akzentfarbe des App-Links für diesen Kanal Ein Beispiel für eine Akzentfarbe finden Sie in Abbildung 2, Zusatzinformation 3.COLUMN_APP_LINK_ICON_URI- Der URI für das App-Badge-Symbol des App-Links für diesen Kanal Ein Beispiel für ein App-Badge-Symbol finden Sie in Abbildung 2, Zusatzinformation 2.COLUMN_APP_LINK_INTENT_URI- Der Intent-URI des App-Links für diesen Kanal Sie können den URI mittoUri(int)undURI_INTENT_SCHEMEerstellen und ihn mitparseUriwieder in den ursprünglichen Intent umwandeln.COLUMN_APP_LINK_POSTER_ART_URI: der URI für das Posterbild, das als Hintergrund des App-Links für diesen Kanal verwendet wird Ein Beispiel für ein Posterbild finden Sie in Abbildung 2, Zusatzinformation 1.COLUMN_APP_LINK_TEXT- Der beschreibende Linktext des App-Links für diesen Kanal. Ein Beispiel für eine App-Link-Beschreibung finden Sie in Abbildung 2, Zusatzinformation 3.
Wenn in den Kanaldaten keine Informationen zu App-Links angegeben sind, erstellt das System einen Standard-App-Link. Das System wählt die Standarddetails wie folgt aus:
- Für den Intent-URI (
COLUMN_APP_LINK_INTENT_URI) verwendet das System die AktivitätACTION_MAINfür die KategorieCATEGORY_LEANBACK_LAUNCHER, die normalerweise im App-Manifest definiert ist. Wenn diese Aktivität nicht definiert ist, wird ein nicht funktionierender App-Link angezeigt. Wenn der Nutzer darauf klickt, passiert nichts. - Für den beschreibenden Text
(
COLUMN_APP_LINK_TEXT) verwendet das System „app-name öffnen“. Wenn kein geeigneter Intent-URI für den App-Link definiert ist, verwendet das System „Kein Link verfügbar“. - Für die Akzentfarbe (
COLUMN_APP_LINK_COLOR) verwendet das System die Standardfarbe der App. - Für das Posterbild (
COLUMN_APP_LINK_POSTER_ART_URI) verwendet das System das Banner auf dem Startbildschirm der App. Wenn die App kein Banner bereitstellt, verwendet das System ein Standardbild der TV-App. - Für das Badge-Symbol (
COLUMN_APP_LINK_ICON_URI) verwendet das System ein Badge, auf dem der App-Name angezeigt wird. Wenn das System auch das App-Banner oder das Standardbild der App für das Posterbild verwendet, wird kein App-Badge angezeigt.
Sie geben die Details zu App-Links für Ihre Kanäle in der Einrichtung Ihrer App an. Sie können diese Details zu App-Links jederzeit aktualisieren. Wenn ein App-Link also an Kanaländerungen angepasst werden muss, aktualisieren Sie die Details zu App-Links und rufen Sie bei Bedarf ContentResolver.update auf. Weitere Informationen zum Aktualisieren von
Kanaldaten finden Sie unter Kanaldaten aktualisieren.