開発者コンソール

ライブTVの統合


ライブTVの統合

Fire TVでは、ユーザーが好きなコンテンツを見つけて楽しむことができるように、さまざまな閲覧機能、音声機能、検索機能を提供しています。ライブTVを統合する主な目的は、既存ユーザーがコンテンツの閲覧や検索によりライブTV(常時リニアフィードでスケジュールされている番組)を利用できるようにすることです。このサービスは、Androidドキュメントの TV入力サービスの開発がベースとなっています。

予備知識と用語

Fire TVのライブTV機能をよく理解するにあたり、予備知識や用語の把握が重要となります。統合を進める前に、以下のドキュメントを参照してください。

Fire TVのライブTV機能

ライブTVの統合が完了し、ユーザーがアプリをインストールして認証すると、どのFire TVデバイスでも以下の機能を利用できるようになります(ただし、一部のマーケットプレイスでは、[ライブ] タブを利用できません)。

[ホーム] タブにあるリニアコンテンツのタイルに、各リニアフィードの最新の番組情報が表示されます。

[ホーム] タブのリニアコンテンツのタイル

[ライブ] タブにあるリニアコンテンツのタイルに、最新の番組情報が表示されます。

マーチャンダイジングの機会

[ライブ] タブにあるリニアコンテンツのタイルに、最新の番組情報が表示されます。

[ライブ] タブのリニアコンテンツのタイル

統合チャンネルガイドに、各チャンネルの14日間の番組が表示されます。

14日間の番組を表示する統合チャンネルガイド

ユーザーは、今後14日間の放送局と番組に関する情報を検索できます。

放送局と番組に関する情報の検索

Alexaでチャンネルを変更できます。

チャンネルの変更

ユーザーは、閲覧画面でお気に入りのチャンネルを設定したり、チャンネルを管理したりすることができます。

お気に入りのチャンネルの設定とチャンネルの管理

これらすべての閲覧ポイント、検索ポイント、音声入力ポイントで、ネイティブのライブTVアプリで再生するか、ディープリンク経由で開始するかを選択できます。

統合要件

リニアなライブチャンネルを統合するには、ユーザーのチャンネル権限へのアクセスに加え、Fire TVでコンテンツが閲覧および検索されやすくするためのメタデータを提供する必要があります。

ライブチャンネル権限

TV入力フレームワーク(TIF)によって提供されているデバイスのローカルチャンネルデータベースに、視聴権限のあるチャンネルをプッシュするには、アプリを更新する必要があります。チャンネルは、アプリがバックグラウンドで実行されているときも含め、いつでも追加、更新、削除が可能です。アプリが最初にインストールされたときに視聴権限メタデータが確実に更新されるように、INITIALIZE_PROGRAMSアクションをリッスンするブロードキャストレシーバーを登録しておく必要があります。

チャンネルの編集については、チャンネルデータを利用するを参照してください。

このデータベースにチャンネルが存在すれば、ユーザーにそのチャンネルを視聴する権限があるということです。デバイスのライブTVアプリは、ライブコンテンツの操作時に表示されるすべてのチャンネルの情報源として、このデータベースを使用します。このデータベースからいつでもチャンネルの追加や削除を行うことができ、変更は即座にUIに反映されます。

TvContract.Channelsのチャンネル列は、可能な限り埋める必要があります。GracenoteチャンネルIDを把握している場合、または再生にディープリンクを提供する場合は、Channels#COLUMN_INTERNAL_PROVIDER_DATAでその情報を共有できます(下記のコードスニペットを参照してください)。

番組メタデータの取得

GracenoteチャンネルID(TVまたはGVD(グローバルビデオデータ))を提供すると、この情報はライブTVアプリによってクラウドに同期され、最大14日間の番組情報を含むFire TVカタログで、対応するチャンネルを検索するために使用されます。クラウドでGracenote IDが検出されると、それ以上の統合処理をしなくても、そのチャンネルに関連する番組情報が [ホーム] タブ、[ライブ] タブ、およびチャンネルガイドに表示されます。画面は自動的に更新され、常に最新情報が表示されます。検索機能とAlexaの機能も簡単に使用できます。

Gracenote IDがない場合

チャンネルのGracenoteチャンネルIDを提供できない場合は、ロゴを含むすべてのChannelメタデータを挿入し、該当するチャンネルすべての今後の番組情報を、TvContract.Programsに可能な限り詳しく、定期的に挿入する必要があります。AndroidサンプルTV入力アプリに、この実行例が示されています。

チャンネルディープリンク

ライブTVコンテンツの再生は、通常、TvInputService.Sessionに応答することで、デバイスのネイティブなライブTVアプリによって処理されます。独自のアプリで全画面再生できるようにするには、ディープリンクインテントをチャンネル情報の一部としてチャンネルデータベースに挿入する必要があります。後述のコードサンプルを参照してください。閲覧や検索でチャンネルが選択されると、このインテントが起動します。このインテントによって、アプリにジャンプし、リクエストされたチャンネルの全画面再生が開始されます。

ディープリンクインテントが提供されている場合でも、TvInputService.Sessionを実装する必要があります。ユーザーが閲覧の行にあるいずれかのタイルにフォーカスすると、onTuneが呼び出されます。このとき、リクエストされたチャンネルの再生を、指定の安全なサーフェスにレンダリングすることを強くお勧めします(これが重要なエンゲージメントドライバーであるためです)。onTuneリクエストに基づいて、指標を取得したり、ライブコンテンツの読み込みを開始したりすることで、パフォーマンスを高めることもできます。

ペアレンタルコントロール

TvInputServiceで指定されているサーフェスにコンテンツをレンダリングするアプリの場合は、ペアレンタルコントロールが適切に実装されていることが重要です。ペアレンタルコントロールが有効になっている場合、アプリはコンテンツを表示する前に、エンドユーザーにPINの入力を要求します。TvInputServiceを使用して、ブロックされるべきコンテンツが要求されるたびにフォアグラウンドのアプリに通知する必要があります。推奨されるフローについては、コードサンプルのセクションを参照してください。

ベストプラクティス

以下は、Fire TVで最高のライブTVエクスペリエンスを提供するための製品および実装のガイドラインです。

  • トライアルを提供する場合は、簡単に登録できるようにする。たとえば、アプリの登録フォームの項目を減らしたり、登録に電話番号を利用したりします。
  • エンゲージメントを促進するため、閲覧でのライブチャンネルのプレビューをサポートする。
  • チャンネルラインナップのTvContract.Channels.Logoには、モノクロで透明なロゴを使用する。
  • ディープリンクフローを最適化し、全画面再生を2.5秒未満で開始する。
  • 必要に応じてGracenoteチャンネルIDを活用し、統合を簡素化する。
  • 完全なスケジュールを提供することよりも、メタデータ読み込みのパフォーマンスに重点を置く。
  • JobSchedulerまたはWorkManagerを使用して、視聴権限が適切であることを定期的に確認する。これにより、アプリがフォアグラウンドで実行されていなくても、閲覧/検索されるチャンネルが視聴権限のあるチャンネルの実際の状態と常に同期されるようになります。
  • 視聴権限のあるチャンネルのリストが一部だけ変更された場合は、すべてのチャンネルを削除して再度追加するのではなく、必要な部分を更新するようにする。
  • COLUMN_DISPLAY_NAME列に表示可能なチャンネル名を指定する(UIでフォールバックとして使用されることがあるため)。Fire TVでは最大16文字まで表示可能です。

パッケージのホワイトリスト

パッケージのホワイトリストによって、Fire TVの閲覧/検索時にチャンネルを表示できるアプリが特定されます。デバイスシリアル番号(DSN)のリストをAmazonの担当者と共有し、公開前にデバイスで上記の機能を統合および検証できるようにする必要があります。

プロバイダーのアトリビューション

デフォルトでは、アプリのlabelは、チャンネルを含む閲覧時のヘッダーとして使用されます。別の名前を使用したくても何らかの理由でlabelを変更できない場合は、Amazon担当者と相談してオーバーライドされるようにしてください。また、番組アートの上にオーバーレイされるモノクロのロゴも指定する必要があります。このロゴの高さは34pxとします。幅は、適切な範囲内で任意の長さに設定することができます。

Gracenote IDがない場合

TvContract.ProgramsCOLUMN_POSTER_ART_URIを設定した場合、モノクロのロゴを画像に入れる必要があります。モノクロのロゴは、右上の座標から(-56, 44)に配置する必要があります。

認定チェックリスト

Amazonは、以下のチェックリストを使用して、ライブTVが統合されたアプリを認定します。アプリの実装が直接関係する動作ポイントは次のとおりです。認定の例外は、状況に応じて処理されます。

権限状態の変更

  • ユーザーが次のいずれかを実行すると、権限のあるチャンネルがFire TVのUIに表示されます(例:[放映中のチャンネル] 行、チャンネルガイド)。 (1)アプリを開いてサインインする、(2)[設定] -> [放送中のチャンネル] -> [チャンネル提供元] -> <アプリ名>からアプリの設定ページにアクセスする。
  • ユーザーのメンバーシップ期限が切れた場合(つまり、視聴権限がなくなった場合)、ユーザーがチャンネルにアクセスしてペイウォールに直面し、オファーをキャンセルまたは拒否するまで、チャンネルはFire TVのUIに表示され続けます。
  • チャンネルは、アプリがアンインストールされたとき、またはチャンネルの視聴権限が無効になったときに、Fire TVのUIから削除されます。

閲覧と再生

  • チャンネルにフォーカスすると、リッチなメタデータエクスペリエンスが提供されます。ガイドに表示されるチャンネルには、チャンネルのロゴ、チャンネル番号(オプション)、今後14日間のスケジュール情報が含まれます。番組のメタデータには、番組名、再生時間、エピソード名、エピソードの詳細な説明、シーズンとエピソードの情報、字幕、番組のレーティング画像(16:9)、背景画像(16:9)が含まれます。このメタデータ情報は、Gracenoteのマッチングから取得されるか、TVコントラクトの一部としてプッシュされる必要があります。
  • ユーザーが [放映中のチャンネル] 行のチャンネルにフォーカスすると、背景画像に代わってライブチャンネルのプレビューが表示されます。
  • ユーザーは、視聴権限のあるこのチャンネルの提供元を把握できる必要があります。このため、背景画像(モノクロ、高さ34px)の一部として、またはライブチャンネルプレビューの再生前のスプラッシュ画面として、プロバイダーアトリビューションを追加します。
  • ユーザーがチャンネルを選択すると、全画面再生が開始されます。[戻る] ボタンを押すと、Fire TVのUIに戻ります。
  • PCONが有効になっている場合、再生前にPINを求めるプロンプトが表示されます。PCONが有効になっている場合は、ライブチャンネルプレビューを無効にする必要があります。
  • Alexaにアクセスする場合は、再生するライブコンテンツの音声をミュートする必要があります。ビデオは続行されます。
  • (任意)ジャンルをチャンネルに割り当てることができます。この場合、Fire TV UIの追加入力ポイントでチャンネルが表示されます。

開発、ステージング環境、およびデプロイ

  • 本稼働環境に進む前に、Amazonが特定のアカウントをホワイトリストに登録して、統合されたエクスペリエンスを確認および認定できる必要があります。
  • 視聴権限のあるチャンネルのみが、両者がリリースに同意したマーケットプレイスのFire TV UIに追加されます。その後、別のマーケットプレイスでリリースする際には、新しい認定レビューとして扱われ、ホワイトリストの登録が必要となります。
  • リリース後に追加または削除されるチャンネルはすべて、Amazonが把握する必要があります。追加されるチャンネルの上限については、両者の合意が必要です。
  • (強く推奨)アプリのダウンロードページとリリースノートには、ユーザーがFire TVで利用可能な新機能を把握できるように、ライブTVの統合について記載してください。

コードサンプル

次のコードサンプルは、Gracenote IDとディープリンクをTVデータベースに挿入する方法を示しています。

/**
 * 外部IDのタイプを格納する変数。サービスメタデータのマッチングに使用されます。有効なタイプは
 * プレフィックス「EXTERNAL_ID_TYPE_」を持つ定数として以下で定義されます
 * Nullまたは無効なデータを使用すると、サービスメタデータの
 * マッチングに失敗します
 */
private final static String EXTERNAL_ID_TYPE = "externalIdType";

/**
 * 外部IDの値を格納する変数。サービスメタデータのマッチングに使用されます。
 * Nullまたは無効なデータを使用すると、サービスメタデータのマッチングに失敗します
 */
private final static String EXTERNAL_ID_VALUE = "externalIdValue";

/**
 * 外部プレーヤーへの再生のディープリンクURI。
 * Nullまたは無効なデータを入力すると、Gordonプレーヤーとの統合がデフォルトとなります
 */
private final static String PLAYBACK_DEEP_LINK_URI = "playbackDeepLinkUri";

// 既知の外部IDタイプ定数のリストのコントラクト
private final static String EXTERNAL_ID_TYPE_GRACENOTE_ONTV = "gracenote_ontv"; // gracenote ontv id

// 再生のディープリンクURIのコントラクト​
// Intent.URI_INTENT_SCHEMEを使用して、インテントからURIを作成し、元のインテントに戻します
Intent playbackDeepLinkIntent; // アプリによって作成されました
String playbackDeepLinkUri = playbackDeepLinkIntent.toUri(Intent.URI_INTENT_SCHEME);

// BLOBを作成します
ContentValues values = new ContentValues();  // store all the channel data
ContentResolver resolver = context.getContentResolver();
values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, "#Actual display name#");
values.put(TvContract.Channels.COLUMN_INPUT_ID, "#Actual input id#");
try {
    String jsonString = new JSONObject()
                  .put(EXTERNAL_ID_TYPE, "#Actual Id Type#")
                  .put(EXTERNAL_ID_VALUE, "#Actual Id Value#")
                  .put(PLAYBACK_DEEP_LINK_URI, playbackDeepLinkUri).toString();

    values.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, jsonString.getBytes());
} catch (JSONException e) {
    Log.e(TAG, "Error when adding data to blob " + e);
}

Uri uri = resolver.insert(TvContract.Channels.CONTENT_URI, values);

ペアレンタルコントロールの実装方法

次のコードサンプルは、ペアレンタルコントロールをリッスンしてライブプレビューまたはネイティブの全画面再生を開始する方法を示しています。

private TvContentRating mBlockedRating = null;

    @Override
    public boolean onTune(final Uri channelUri) {
        ...
        if (mTvInputManager.isParentalControlsEnabled()) {
            // サーフェスで音声や画像が再生されないようにします
            mBlockedRating = <content_rating>;
            //1.全画面再生のときに、ユーザーにPINの入力を求めるプロンプトを表示します
            //2.[放映中のチャンネル] 行を閲覧しているときに
            //    番組画像が再生サーフェスで表示されないようにします
            notifyContentBlocked(mBlockedRating);
        } else {
            // 再生が開始されます
            notifyContentAllowed();
        }
        ...
    }

    @Override
    public void onUnblockContent(final TvContentRating unblockedRating) {
        // ユーザーが、指定のレーティングに対する正しいPINを入力し
        // コンテンツのブロックが解除されました
        if (unblockedRating.unblockContent(mBlockedRating)) {
            // 再生が開始されます
            notifyContentAllowed();
        }
    }