Wejście TV musi zawierać dane przewodnika po programach elektronicznym (EPG) przez co najmniej jeden kanał w konfiguracji. Należy też okresowo aktualizować z uwzględnieniem rozmiaru aktualizacji i wątku przetwarzania która radzi sobie z tym zadaniem. Możesz też dodać linki do aplikacji dla kanałów które kierują użytkownika do powiązanych treści i działań. Z tej lekcji dowiesz się, jak tworzyć i aktualizować dane kanału i programu z uwzględnieniem tych kwestii.
Wypróbuj Przykładowa aplikacja do obsługi wejścia TV.
Przyznaj dostęp
Aby wejście TV działało z danymi EPG, musi zadeklarować uprawnienia do zapisu w pliku manifestu Androida w ten sposób:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Zarejestruj kanały w bazie danych
Baza danych systemu Android TV przechowuje rejestry danych kanałów z wejściach telewizyjnych. W konfiguracji
dla każdego ze swoich kanałów musisz zmapować dane kanału do następujących pól
Zajęcia TvContract.Channels
:
COLUMN_DISPLAY_NAME
– wyświetlana nazwa kanałCOLUMN_DISPLAY_NUMBER
– wyświetlany kanał numerCOLUMN_INPUT_ID
– identyfikator usługi wejścia TV.COLUMN_SERVICE_TYPE
– rodzaj usługi kanału;COLUMN_TYPE
– standard transmisji kanału typCOLUMN_VIDEO_FORMAT
– domyślny format wideo. dla kanału
Chociaż struktura wejścia TV jest wystarczająco ogólna, by obsługiwać zarówno tradycyjne transmisje, treści Over-The-Top (OTT) bez rozróżniania, warto zdefiniować następujące kolumny w aby lepiej określić tradycyjne kanały telewizyjne:
COLUMN_ORIGINAL_NETWORK_ID
– telewizor identyfikator sieciCOLUMN_SERVICE_ID
– identyfikator usługi.COLUMN_TRANSPORT_STREAM_ID
– strumień transportu. Identyfikator
Jeśli chcesz podać szczegóły linków do aplikacji swoich kanałów, musisz zaktualizować niektóre dodatkowe pola. Więcej informacji o polach linku aplikacji: Dodaj informacje o linku aplikacji.
W przypadku strumieniowych źródeł sygnału telewizyjnego z internetu przypisz do powyższych wartości własne wartości, każdy kanał można jednoznacznie zidentyfikować.
Pobierz metadane kanału (w formacie XML, JSON lub innym) z serwera backendu i podczas konfiguracji aktywność mapuje wartości na systemową bazę danych w następujący sposób:
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);
W powyższym przykładzie channel
to obiekt, który przechowuje metadane kanału z
z serwera backendu.
Prezentowanie informacji o kanale i programie
Systemowa aplikacja TV wyświetla użytkownikom informacje o kanałach i programach, gdy przeglądają kanały, jak widać na ilustracji 1. Aby upewnić się, że informacje o kanale i programie są zgodne z prezentera informacji o kanale i programie, zastosuj się do poniższych wskazówek.
- Numer kanału (
COLUMN_DISPLAY_NUMBER
) - Ikona
(
android:icon
w pliku manifestu wejścia TV) - Opis programu (
COLUMN_SHORT_DESCRIPTION
) - Tytuł programu (
COLUMN_TITLE
) - Logo kanału (
TvContract.Channels.Logo
)- .
- Użyj koloru #EEEEEE, aby dopasować otaczający tekst.
- Nie używaj dopełnienia
- Platka (
COLUMN_POSTER_ART_URI
)- .
- Format obrazu: od 16:9 do 4:3
![](https://developer.android.google.cn/static/images/tv/channel-info.png?authuser=19&hl=pl)
Rysunek 1. Prezentujący informacje o kanale i programie w aplikacji systemowej.
Systemowa aplikacja TV udostępnia te same informacje w przewodniku po programach, w tym plakat, jak widać na rysunku 2.
![](https://developer.android.google.cn/static/images/tv/prog-guide.png?authuser=19&hl=pl)
Rysunek 2. Przewodnik po programach systemowych aplikacji TV.
Zaktualizuj dane kanału
Przy aktualizacji danych kanału skorzystaj z
update()
zamiast usuwać i ponownie dodawać dane. Możesz określić bieżącą wersję danych
za pomocą funkcji Channels.COLUMN_VERSION_NUMBER
i Programs.COLUMN_VERSION_NUMBER
podczas wybierania rekordów do zaktualizowania.
Uwaga: dodaję dane kanału do ContentProvider
może zająć trochę czasu. Dodaj bieżące programy (te znajdujące się w okresie 2 godzin od aktualnej godziny).
tylko wtedy, gdy skonfigurujesz EpgSyncJobService
, aby zaktualizować resztę
z danymi kanałów w tle. Zobacz
Przykładowa aplikacja Android TV Live TV.
Zbiorcze wczytywanie danych kanału
Gdy aktualizujesz systemową bazę danych za pomocą dużej ilości danych o kanałach, użyj funkcji ContentResolver
applyBatch()
lub
bulkInsert()
. Oto przykład użycia właściwości 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(); } }
Asynchroniczne przetwarzanie danych kanału
Manipulacja danymi, np. pobieranie strumienia z serwera lub uzyskiwanie dostępu do bazy danych, powinna
nie blokować wątku UI. Korzystanie z AsyncTask
asynchronicznie. Na przykład podczas wczytywania informacji o kanale z serwera backendu
Z usługi AsyncTask
możesz korzystać w następujący sposób:
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(); } } } }
Jeśli musisz regularnie aktualizować dane EPG,
WorkManager
, aby proces aktualizacji był uruchamiany w czasie bezczynności, np.codziennie o 3:00.
Inne techniki oddzielania zadań aktualizacji danych od wątku UI to użycie parametru
HandlerThread
. Możesz też wdrożyć własne za pomocą narzędzia Looper
.
i Handler
zajęć. Zobacz
procesy i wątki, aby dowiedzieć się więcej.
Dodaj informacje o linku aplikacji
Kanały mogą korzystać z linków do aplikacji, aby umożliwić użytkownikom łatwe uruchamianie co robią podczas oglądania treści na kanale. Używane przez aplikacje kanału linków do aplikacji, aby zwiększać zaangażowanie użytkowników przez uruchamianie działań, które pokazują powiązane informacje lub dodatkowe treści. Możesz na przykład użyć linków do aplikacji, wykonaj następujące czynności:
- Poinformuj użytkownika, jak odkrywać i kupować powiązane treści.
- Podaj dodatkowe informacje o aktualnie odtwarzanych treściach.
- Podczas oglądania treści w odcinkach zacznij oglądać następny odcinek serii.
- Pozwól użytkownikowi na interakcję z treścią, np. ocenę lub opinię. bez przerywania odtwarzania.
Linki do aplikacji pojawiają się, gdy użytkownik naciśnie Wybierz, aby wyświetlić Menu telewizora podczas oglądania treści kanału.
![](https://developer.android.google.cn/static/images/training/tv/tif/app-link.png?authuser=19&hl=pl)
Rysunek 1. Przykładowy link aplikacji w wierszu Kanały.
Gdy użytkownik kliknie link do aplikacji, system rozpocznie aktywność za pomocą parametru identyfikator URI intencji określony przez aplikację kanału. Treści na kanale są nadal odtwarzane gdy aktywność związana z linkiem do aplikacji jest aktywna. Użytkownik może wrócić na kanał. kliknij Wstecz.
Podawanie danych kanału linku aplikacji
Android TV automatycznie tworzy link do aplikacji dla każdego kanału,
na podstawie informacji
z danych kanału. Aby podać informacje o linku aplikacji:
podaj następujące szczegóły w
TvContract.Channels
pola:
COLUMN_APP_LINK_COLOR
kolor uzupełniający linku do aplikacji dla tego kanału Przykładem koloru uzupełniającego: patrz: rysunek 2, objaśnienie 3.COLUMN_APP_LINK_ICON_URI
– Identyfikator URI ikony plakietki aplikacji w linku do aplikacji na tym kanale. Dla przykładowa ikona plakietki aplikacji, patrz ilustracja 2, objaśnienie 2.COLUMN_APP_LINK_INTENT_URI
– Identyfikator URI intencji linku do aplikacji na tym kanale. Możesz utworzyć identyfikator URI używasztoUri(int)
zURI_INTENT_SCHEME
i skonwertuj identyfikator URI z powrotem na pierwotną intencję zparseUri()
COLUMN_APP_LINK_POSTER_ART_URI
– Identyfikator URI plakatu używanego jako tło linku do aplikacji. dla tego kanału. Przykładowy obraz plakatu znajdziesz na ilustracji 2, objaśnienie 1.COLUMN_APP_LINK_TEXT
– Opisowy tekst linku do aplikacji na tym kanale. Przykład: opis linku aplikacji, zobacz tekst na rysunku 2, objaśnienie 3.
![](https://developer.android.google.cn/static/images/training/tv/tif/app-link-diagram.png?authuser=19&hl=pl)
Rysunek 2. Szczegóły linku aplikacji.
Jeśli dane kanału nie zawierają informacji o linku aplikacji, system tworzy domyślny link aplikacji. System wybiera domyślne szczegóły w następujący sposób:
- W przypadku identyfikatora URI intencji
(
COLUMN_APP_LINK_INTENT_URI
), system używa funkcjiACTION_MAIN
aktywność w kategoriiCATEGORY_LEANBACK_LAUNCHER
, zwykle zdefiniowanej w manifeście aplikacji. Jeśli aktywność nie jest zdefiniowana, pojawi się link niedziałającej aplikacji – użytkownik kliknie reklamę, ale nic się nie stanie. - Dla tekstu opisu
(
COLUMN_APP_LINK_TEXT
), system korzysta z funkcji „Otwórz app-name”. Jeśli nie określono prawidłowego identyfikatora URI intencji linku aplikacji, system użyje stanu „Brak linku”. - Kolor uzupełniający:
(
COLUMN_APP_LINK_COLOR
), system używa domyślnego koloru aplikacji. - W przypadku obrazu plakatu
(
COLUMN_APP_LINK_POSTER_ART_URI
), system używa banera na ekranie głównym aplikacji. Jeśli aplikacja nie udostępnia system używa domyślnego obrazu aplikacji telewizyjnej. - W przypadku ikony plakietki
(
COLUMN_APP_LINK_ICON_URI
), wartość system używa plakietki z nazwą aplikacji. Jeśli system używa też atrybutu baner aplikacji lub domyślny obraz aplikacji w przypadku obrazu plakatu, plakietka aplikacji nie jest wyświetlana.
Szczegóły linku aplikacji dla kanałów określasz w sekcji
Konfiguracja. Szczegóły linku do aplikacji możesz zaktualizować w każdej chwili,
Jeśli link aplikacji musi pasować do zmian wprowadzonych w kanale, zaktualizuj aplikację
Szczegóły połączenia i połączenie
ContentResolver.update()
. Więcej informacji o aktualizacjach
Więcej informacji znajdziesz w artykule Aktualizowanie danych kanału.