TV 入力で、少なくとも次の期間の電子番組ガイド(EPG)データを提供する必要があります 設定アクティビティで 1 つのチャネルを 作成しますまた、Cloud Monitoring で 更新と処理スレッドのサイズを考慮して、 処理しますまた、チャンネルのアプリリンクを提供することもできます。 関連するコンテンツやアクティビティにユーザーを誘導します。 このレッスンでは、 システムのデータベースについてよく理解しておく必要があります。
<ph type="x-smartling-placeholder"></ph>をお試しください TV 入力サービス サンプルアプリ。
権限を付与する
テレビ入力で EPG データを扱うには、テレビ入力で Android マニフェスト ファイルで、次のように書き込み権限を設定します。
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
データベースにチャンネルを登録する
テレビ入力のためのチャンネル データのレコードは、Android TV システム データベースに保持されます。設定
作成するには、チャネルごとに、チャネル データを
TvContract.Channels
クラス:
COLUMN_DISPLAY_NAME
- リソースの表示名 チャンネルCOLUMN_DISPLAY_NUMBER
- 表示されるチャネル 数値COLUMN_INPUT_ID
- テレビ入力サービスの IDCOLUMN_SERVICE_TYPE
- チャンネルのサービスタイプCOLUMN_TYPE
- チャンネルのブロードキャスト標準 種類COLUMN_VIDEO_FORMAT
- デフォルトの動画形式 チャンネル
TV 入力フレームワークは汎用性が高いため、従来の放送と配信の両方に対応できます。 特に区別なくオーバー ザ トップ(OTT)コンテンツである場合は、 従来の放送チャンネルをより適切に識別できるようにしました。
COLUMN_ORIGINAL_NETWORK_ID
- テレビ ネットワーク IDCOLUMN_SERVICE_ID
- サービス IDCOLUMN_TRANSPORT_STREAM_ID
- トランスポート ストリーム ID
チャンネルのアプリリンクの詳細を提供する場合は、以下を行う必要があります。 いくつかのフィールドを更新します。アプリリンク フィールドの詳細については、以下をご覧ください。 アプリリンク情報を追加します。
インターネット ストリーミング ベースのテレビ入力の場合は、上記に応じて独自の値を割り当てて、 各チャネルは一意に識別できます
バックエンド サーバーからチャンネルのメタデータ(XML、JSON など)を取得し、設定で取得します。 アクティビティは、次のように値をシステム データベースにマッピングします。
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);
上の例では、channel
は
バックエンドサーバーと通信します
チャンネルと番組の情報を表示する
システム TV アプリは、ユーザーがチャンネルを次々と切り替えたときにチャンネルと番組の情報を表示します。 必要があります。チャンネルと番組の情報がシステムの TV アプリのものと一致することを確認する チャンネルとプログラムの情報のプレゼンターは、以下のガイドラインに従ってください。
- チャンネル番号(
COLUMN_DISPLAY_NUMBER
) - アイコン
(
android:icon
、 TV 入力のマニフェスト) - プログラムの説明(
COLUMN_SHORT_DESCRIPTION
) - 番組タイトル(
COLUMN_TITLE
) - チャンネルのロゴ(
TvContract.Channels.Logo
) <ph type="x-smartling-placeholder">- </ph>
- 周囲のテキストに合わせるには #EEEEEE の色を使用します。
- パディングを含めないでください
- ポスターアート(
COLUMN_POSTER_ART_URI
) <ph type="x-smartling-placeholder">- </ph>
- 16:9~4:3 のアスペクト比
システム TV アプリは、ポスターアート、 必要があります。
チャンネル データを更新する
既存のチャンネル データを更新する場合は、
update()
メソッドを使用します。データの現在のバージョンと
Channels.COLUMN_VERSION_NUMBER
を使用
および Programs.COLUMN_VERSION_NUMBER
選択します
注: チャンネル データを ContentProvider
に追加する
時間がかかります。現在の番組(現在の時刻から 2 時間以内の番組)を追加する
残りの要素を更新するように EpgSyncJobService
を構成した場合のみ
バックグラウンドで自動的に処理されます。詳しくは、
<ph type="x-smartling-placeholder"></ph>
Android TV Live TV サンプルアプリをご覧ください。
チャンネル データを一括で読み込む
大量のチャンネル データでシステム データベースを更新する場合は、ContentResolver
を使用します。
applyBatch()
または
bulkInsert()
メソッドを呼び出します。以下に 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(); } }
チャンネル データを非同期で処理する
サーバーからのストリームのフェッチやデータベースへのアクセスなどのデータ操作は、
UI スレッドをブロックしませんAsyncTask
を使用するのは、
更新を非同期で実行することもできますたとえば、バックエンド サーバーからチャンネル情報を読み込む場合、
次のように AsyncTask
を使用できます。
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(); } } } }
EPG データを定期的に更新する必要がある場合は、
WorkManager
たとえば、毎日午前 3 時など、アイドル時間にアップデート プロセスを実行します。
データ更新タスクを UI スレッドから分離するその他の手法として、
HandlerThread
クラスを使用するか、Looper
を使用して独自のものを実装できます。
および Handler
クラス。<ph type="x-smartling-placeholder"></ph>をご覧ください。
プロセスとスレッドをご覧ください。
アプリリンク情報を追加する
チャンネルでアプリリンクを使用すると、関連するアプリをユーザーが簡単に起動できるようになります。 行動を起こすことができます。チャネルアプリの使用状況 以下を表示するアクティビティを起動して、ユーザー エンゲージメントを拡大します。 関連する情報や追加のコンテンツですたとえばアプリリンクを使用して 次の操作を行います。
- ユーザーが関連コンテンツを見つけて購入できる場所を案内する
- 現在再生中のコンテンツに関する追加情報を提供する
- エピソード形式のコンテンツの視聴中に、 シリーズとして提供されます
- ユーザーがコンテンツを操作できるようにする(評価、レビューなど) ストリーミングできます。
アプリリンクは、ユーザーが [選択] を押して チャンネル コンテンツの視聴中にテレビのメニューを表示。
ユーザーがアプリリンクを選択すると、システムは チャネルアプリで指定されたインテント URI。チャンネルのコンテンツが引き続き再生される アプリリンク アクティビティがアクティブな間。ユーザーはチャンネルに戻ることができます [戻る] を押します。
アプリリンクにチャンネル データを提供する
Android TV はチャンネルごとに自動的にアプリリンクを作成します。
チャンネルデータの情報を使用しますアプリリンク情報を提供するには
その際、
TvContract.Channels
フィールド:
COLUMN_APP_LINK_COLOR
- このチャンネルのアプリリンクのアクセント カラー。たとえば アクセントカラーは 図 2 の吹き出し 3 を参照してください。COLUMN_APP_LINK_ICON_URI
~ このチャンネルのアプリリンクのアプリバッジ アイコンの URI。1 つの アプリバッジ アイコンの例(図 2 の吹き出し 2 を参照)COLUMN_APP_LINK_INTENT_URI
~ このチャンネルのアプリリンクのインテント URI。URI はtoUri(int)
とURI_INTENT_SCHEME
と 元のインテントに URI を戻します。parseUri()
。COLUMN_APP_LINK_POSTER_ART_URI
- アプリリンクの背景として使用されるポスターアートの URI このチャンネルのポスター画像の例は、図 2 の吹き出し 1 をご覧ください。COLUMN_APP_LINK_TEXT
~ このチャンネルのアプリリンクの説明リンクテキスト。例 アプリリンクの説明(図 2 の吹き出し 3 のテキストを参照)。
チャンネル データにアプリリンク情報が指定されていない場合は、 デフォルトのアプリリンクを作成します。詳細項目はデフォルトでは以下のように選択されます。
- インテント URI の場合
(
COLUMN_APP_LINK_INTENT_URI
), システムはACTION_MAIN
を使用するCATEGORY_LEANBACK_LAUNCHER
カテゴリのアクティビティ。通常はアプリ マニフェストで定義されます。 このアクティビティが定義されていない場合、 ユーザーがクリックしても何も起こりません - 説明文
(
COLUMN_APP_LINK_TEXT
)、システム 「Open app-name」を使用します。アプリリンクのインテント URI が定義されていない場合、 「No link available」と表示されます。 - アクセント カラー用
(
COLUMN_APP_LINK_COLOR
), デフォルトのアプリ色が使用されます。 - ポスター画像の場合
(
COLUMN_APP_LINK_POSTER_ART_URI
), システムはアプリのホーム画面のバナーを使用します。アプリが バナーに表示される場合、システムはデフォルトのテレビアプリの画像を使用します。 - バッジアイコンの場合
(
COLUMN_APP_LINK_ICON_URI
)、 アプリ名を示すバッジが使用されます。システムが ポスター画像にアプリバナーまたはデフォルトのアプリ画像が表示され、アプリバッジは表示されません。
チャンネルのアプリリンクの詳細は、
設定します。アプリリンクの詳細は随時更新できるため、
チャンネルの変更に合わせてアプリリンクを変更する場合は、アプリを更新する
リンクの詳細と呼び出し
必要に応じて ContentResolver.update()
。更新について詳しくは、
チャンネル データについて詳しくは、チャンネル データを更新するをご覧ください。