Vegaコンテンツパーソナライゼーションについて
ここでは、Fire TV対応アプリにVegaコンテンツパーソナライゼーションを統合する場合に知っておくべきことを説明します。この統合に使用されるデータの種類について確認するには、データの種類のリファレンスを参照してください。
データにアクセスできない場合やデータを変換する必要がある場合は、この統合にかかる時間が長くなる可能性があります。このドキュメントを使用して、アプリのデータが要件に合った形式で格納されていることを確認してください。
前提条件
- Fire TV対応アプリのソースコードへのアクセス。
- この統合がサポートされているFire TVデバイス。現在サポートされているデバイスタイプのリストについては、Amazonの担当者に確認してください。
- アプリがカタログ統合プロセスに参加していること。これにより、Fire TVでコンテンツIDが認識されます。
- アプリがユーザーごとのエンタイトルメントを共有していること。これにより、コンテンツの検出機能の一部として、視聴権限のあるプロバイダーがFire TVで表示されます。詳細については、Amazonの担当者にお問い合わせください。
- アプリでコンテンツランチャー統合が完了していること。
統合の手順
手順1:パッケージの依存関係をアプリに追加する
package.jsonファイルに、kepler-content-personalizationとheadless-task-manager、さらにamzn/kepler-epg-providerの依存関係を追加します。
"dependencies": {
"@amazon-devices/react-native-kepler": "~2.0.0",
"react": "18.2.0",
"react-native": "0.72.0",
"@amazon-devices/kepler-content-personalization": "^1.2.0",
"@amazon-devices/kepler-epg-provider": "^1.0.0",
"@amazon-devices/headless-task-manager": "^1.0.0"
}
kepler-content-personalizationパッケージは、コンテンツパーソナライゼーションデータをシステムに送信するためのAPIを提供します。amzn/kepler-epg-providerパッケージは、PlaybackEventデータモデルのchannelDescriptorに使用される依存関係を提供します。headless-task-managerパッケージは、データプルバックグラウンドサービスをシステムに登録するためのAPIを提供します。詳細は以下のとおりです。
手順2:マニフェストファイルを更新する
manifest.tomlファイルを更新して、コンテンツパーソナライゼーションのサポートを追加します。以下はサンプルアプリの例です。
schema-version = 1
## パッケージを定義します
[package]
title = "Vega Video app"
version = "2.17.0"
id = "com.amazondeveloper.keplervideoapp"
[components]
## アプリの対話型コンポーネントを定義します(まだ存在しない場合)
[[components.interactive]]
id = "com.amazondeveloper.keplervideoapp.main"
library-name = "com.amazondeveloper.keplervideoapp"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
categories = ["com.amazon.category.kva"]
launch-type = "singleton"
## データリクエストを処理できるアプリのサービスコンポーネントを定義します。
[[components.service]]
id = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"
categories = ["com.amazon.category.kepler.media"]
## 各コンポーネントのプロセスグループを定義します
[processes]
[[processes.group]]
component-ids = ["com.amazondeveloper.keplervideoapp.main"]
[[processes.group]]
component-ids = ["com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"]
[wants]
## アプリがコンテンツパーソナライゼーションデータサービスに依存していることを定義します
[[wants.service]]
id = "com.amazon.tv.developer.dataservice"
[needs]
## コンテンツパーソナライゼーションインターフェイスを使用してデータを提供するためにアプリが必要とする権限を定義します
[[needs.privilege]]
id = "com.amazon.tv.content-personalization.privilege.provide-data"
[offers]
## アプリのデータ更新サービスコンポーネントを定義します。
[[offers.service]]
id = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
## アプリの対話型コンポーネントを定義します
[[offers.interaction]]
id = "com.amazondeveloper.keplervideoapp.main"
## コンテンツパーソナライゼーションのサポートを宣言するためのエクストラを追加します
[[extras]]
key = "interface.provider"
## アカウントログインまたはコンテンツランチャーインターフェイスを利用している場合は、
## component-idを適切なサービスコンポーネントに置き換えます。アカウントログイン統合ガイドに従ってください。
component-id = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
## コンテンツパーソナライゼーションのインターフェイスと属性のサポートを定義します
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]
[extras.value.application.interface.static_values]
SupportedCustomerLists = ["Watchlist"]
DataRefreshComponentId = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
以下の例は、複数のインターフェイスを定義する正しい方法を示しています。
[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]
[extras.value.application.interface.static_values]
SupportedCustomerLists = ["Watchlist"]
DataRefreshComponentId = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
override_command_component = { LaunchContent = "com.amazondeveloper.keplervideoapp.main" }
attribute_options = ["partner-id"]
[extras.value.application.interface.static_values]
partner-id = "<パートナーID>"
以下は誤った方法の例です。このような指定はしないでください。
[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentPersonalizationServer"
attribute_options = ["SupportedCustomerLists", "DataRefreshComponentId"]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
override_command_component = { LaunchContent = "com.amazondeveloper.keplervideoapp.main" }
attribute_options = ["partner-id"]
[extras.value.application.interface.static_values]
partner-id = "<パートナーID>"
SupportedCustomerLists = ["Watchlist"]
DataRefreshComponentId = "com.amazondeveloper.keplervideoapp.content.dataRefresh.provider"
手順3:サンプルAPI呼び出しを行う
アプリ起動時に生成されるサンプルやモックイベントから始めましょう。イベントを作成して送信するには、以下のコードを使用します。
// ユーザーがコンテンツの視聴を開始したときに生成される再生イベントの例
const playbackEvent: IPlaybackEvent = new PlaybackEventBuilder()
.playbackPositionMs(0)
.playbackState(PlaybackState.PLAYING)
.durationMs(2000)
.eventTimestamp(new Date())
.contentId(
new ContentIdBuilder()
.id('content_CDF_ID')
.idNamespace(ContentIdNamespaces.NAMESPACE_CDF_ID)
.build(),
)
.profileId(
new ProfileIdBuilder()
.id('myProfileId')
.idNamespace(ProfileIdNamespaces.NAMESPACE_APP_INTERNAL)
.build(),
)
.buildActiveEvent();
// イベントを送信します
ContentPersonalizationServer.reportNewPlaybackEvent(playbackEvent);
手順4:統合を検証する
作成したサンプルイベントコードをトリガーして、アプリ内で実行します。コードが正常に実行されたらログを表示し、SDKがアプリにリンクされており、メッセージを処理していることを確認します。
アプリログを検索することによって手順を検証できます。
journalctl --follow |grep -Ei 'kepler.tv.personalization'
ステップ3で示したイベントについて受信するログメッセージには、次のログの少なくとも1つが含まれている必要があります。
Dec 15 00:53:15.705114 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization.ancp.turbomodule:reportNewPlaybackEvent called
Dec 15 00:53:15.711945 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization:PlaybackEventBuilder buildActiveEvent() called
Dec 15 00:53:15.711990 carat-3fc19fb5ae526e4d local0.info keplerscript-ru[22814]: 1483317178 INFO kepler.tv.personalization:reportNewPlaybackEvent call received
手順5:アプリ内機能の一部としてAPI呼び出しを実行する方法
それぞれのデータの種類について、そのデータの種類の「送信するタイミング」セクションを確認して、コードのどこでVegaコンテンツパーソナライゼーションを呼び出すかを理解してください。ユーザーが各アクションを実行したときに実行されるコード部分を特定し、API呼び出しを追加します。データの種類によってトリガーは異なります。
- 視聴アクティビティの場合は、視聴アクティビティ: 送信するタイミングを参照してください。
- 個別のコンテンツエンタイトルメントの場合は、個別のコンテンツエンタイトルメント: 送信するタイミングを参照してください。
- ウォッチリストの場合は、ウォッチリスト: 送信するタイミングを参照してください。
たとえば、ユーザーがウォッチリストにアイテムを追加したら、関連情報と共にreportNewCustomerListEntry APIを呼び出すことが想定されています。まず、ウォッチリストにアイテムを追加するコードをアプリ内で探し、ロジックの一部としてAPI呼び出しを行います。
手順6:バックグラウンドまたはデバイス外のデータ用にデータプルサービスを実装する
Amazonがアプリからデータをプルできるようにするには、以下の説明に従ってサービスを実装します。このサービスには、セットアップと接続に必要な処理がすべて含まれています。開発者に求められる作業は、レシーバーオブジェクトにデータを送信する関数を実装することだけです。このオブジェクトを使用すると、必要に応じてデータをチャンクに分けて共有できます。これにより、大きなリストがメモリに読み込まれることを防ぎます。
-
package.jsonが保存されているのと同じパスに、次の内容を含むservice.jsファイルを作成します。これにより、
content.dataRefresh.providerサービスのエントリポイントがシステムに通知されます。import { HeadlessEntryPointRegistry } from '@amazon-devices/headless-task-manager'; import { onStartService, onStopService, } from './src/headless/HeadlessService'; HeadlessEntryPointRegistry.registerHeadlessEntryPoint2( 'com.amazondeveloper.keplervideoapp.content.dataRefresh.provider::onStartService', () => onStartService, ); HeadlessEntryPointRegistry.registerHeadlessEntryPoint2( 'com.amazondeveloper.keplervideoapp.content.dataRefresh.provider::onStopService', () => onStopService, ); -
src/headless/HeadlessServiceInterface.tsとして、以下の内容のヘッドレスサービスインターフェイスファイルを作成します。
import { IComponentInstance, } from "@amazon-devices/react-native-kepler"; export interface HeadlessServiceInterface { /** * この関数は、ネイティブサービスのonStartが呼び出されたときに呼び出されます。 * @param {IComponentInstance} componentInstance - ヘッドレスコンポーネントのインスタンス。 */ onStart(componentInstance: IComponentInstance): Promise<void>; /** * この関数は、ネイティブサービスのonStopが呼び出されたときに呼び出されます。 * @param {IComponentInstance} componentInstance - ヘッドレスコンポーネントのインスタンス。 */ onStop(componentInstance: IComponentInstance): Promise<void>; } -
src/headless/HeadlessService.tsとして、以下の内容のデータプルサービスを作成します。
import { ContentPersonalizationServer, CustomerListType, IContentEntitlementsHandler, IContentEntitlementsProvider, ICustomerListEntriesHandler, ICustomerListEntriesProvider, IPlaybackEventsHandler, IPlaybackEventsProvider } from "@amazon-devices/kepler-content-personalization"; import { HeadlessServiceInterface } from "./HeadlessInterface"; import { IComponentInstance } from "@amazon-devices/react-native-kepler"; /*********** コンテンツパーソナライゼーションハンドラー *************/ const contentEntitlementsHandler: IContentEntitlementsHandler = { getAllContentEntitlements: ( contentEntitlementsProvider: IContentEntitlementsProvider, ) => { contentEntitlementsProvider.addContentEntitlementChunk(<エンタイトルメントを追加>); contentEntitlementsProvider.commit(); }, }; const customerListEntriesHandler: ICustomerListEntriesHandler = { getAllCustomerListEntries: ( listType: CustomerListType, customerListEntriesProvider: ICustomerListEntriesProvider, ) => { customerListEntriesProvider.addCustomerListChunk(listType, <リストエントリを追加>); customerListEntriesProvider.commit(); }, }; const playbackEventsHandler: IPlaybackEventsHandler = { getPlaybackEventsSince: ( sinceTimestamp: Date, playbackEventsProvider: IPlaybackEventsProvider, ) => { playbackEventsProvider.addPlaybackEventChunk(<再生イベントを追加>); playbackEventsProvider.commit(); }, }; /*********** コンテンツパーソナライゼーションハンドラーの割り当て *************/ class HeadlessService implements HeadlessServiceInterface { onStart(componentInstance: IComponentInstance): Promise<void> { ContentPersonalizationServer.setContentEntitlementsHandlerForComponent( contentEntitlementsHandler, componentInstance ); ContentPersonalizationServer.setCustomerListEntriesHandlerForComponent( customerListEntriesHandler, componentInstance ); ContentPersonalizationServer.setPlaybackEventsHandlerForComponent( playbackEventsHandler, componentInstance ); return Promise.resolve(); } onStop(componentInstance: IComponentInstance): Promise<void> { return Promise.resolve(); } } const HeadlessServiceInstance = new HeadlessService() as HeadlessServiceInterface; export const onStartService = (componentInstance: IComponentInstance): Promise<void> => { return HeadlessServiceInstance.onStart(componentInstance); }; export const onStopService = (componentInstance: IComponentInstance): Promise<void> => { return HeadlessServiceInstance.onStop(componentInstance); };
実装の詳細
カタログ統合の変更(Amazon担当者から指示されたとき)
エンタイトルメントとアクティビティのデータを利用するために、Fire TVには、既存のFire TVカタログ統合から以下のデータが必要です。これらの要素については、今後、Fire TVのカタログ統合に関する公開ドキュメントを更新して含める予定ですが、ここでは、Vegaコンテンツパーソナライゼーションの統合に必要となる内容のプレビューを示します。これらのカタログの変更を開始する時期は、Amazonの担当者がお知らせします。
- TVOD(購入およびレンタル)- 該当するタイトルに新規購入とレンタルのオファーを追加します。定期購入オファーと同じように見えますが、定期購入IDは使用されません。
- 国際化 - 他国への展開に向けて、Fire TVは国別のカタログからFire TVのグローバルカタログ形式に移行する予定です。上記のカタログの変更は、グローバルカタログの一部に含めて実装すると移行が容易になります。ただし、Fire TVは引き続き国ごとのカタログもサポートします。
AmazonコンテンツID
Vegaコンテンツパーソナライゼーションは、さまざまな名前空間でのコンテンツ識別をサポートします。Amazonがコンテンツアイテムを識別できるようにするために、コンテンツIDを渡すときは常に、関連付けられている名前空間を一緒に指定する必要があります。Amazonでは、次の名前空間がサポートされています。
| 名前空間 | 説明 |
|---|---|
cdf_id |
このID空間では、データがAmazonカタログ統合で共有されています。これらのIDは、開発者がそれぞれのコンテンツに指定したものです。カタログデータ形式(CDF)のCommonWorkType/IDフィールドに対応します。 |
AmazonプロフィールID
どのデータの種類も、関連付けられているプロフィールIDを共有できるようになっています。プロフィールにはさまざまな種類があるため、名前空間を指定します。Amazonでは現在、以下のプロフィールID名前空間がサポートされています。
| 名前空間 | 説明 |
|---|---|
app_internal |
この名前空間は、アクティブなプロフィールの内部プロフィールIDの文字列表現を共有していることを示します。このIDはアプリ内の特定のプロフィールを識別するものとして機能し、それを通じてAmazonでは、アクティビティを適切なFire TVプロフィールに関連付けることができます。内部で使用している実際のIDは提供しないでください。提供された値では、ユーザーを特定できないようにする必要があります。すべてのデバイス間で同一となる、内部プロフィールIDのハッシュ値を使用することをお勧めします。さらに、ユーザーから提供されたプロフィール名も送信しないでください。アプリでプロフィールを使用しない場合でも、一貫した値を提供してください。 |
レポートの更新
SDKには、次の3種類の操作を使用して情報を共有する機能が含まれています。
New(例:reportNewCustomerListEntry)- データセットに新しいエントリを追加するインクリメンタル更新を表します。Removed(例:reportRemovedCustomerListEntry)- データセットからエントリを削除するデクリメンタル更新を表します。Refreshed(例:reportRefreshedCustomerList)- デバイス外のアクションによりデータセットに変更があったため、データプルサービスを使用して更新された新しいバージョンのリストを取得する必要があることを示します。
NewとRemovedは、ユーザーがアプリ内のコンテンツを操作し、アプリが追加や削除を実行する場合に役立ちます。Refreshedによる更新は、ユーザーのログインやデバイス外でのアクティビティによってリストが大幅に変更された場合や、別の理由でリストが同期されていないと思われる場合に役立ちます。
大量のデータの提供
データプルサービスを通じて大量のデータを提供する場合は、クラウドバックエンドから適度に小さいページに分けてデータを取得し、データがプルダウンされるときにプロバイダーAPIを呼び出します。これにより、サービスのメモリ使用量が制限され、アプリがシステムによって終了されるのを防ぐことができます。
フローの例は次のようになります。
const contentEntitlementsHandler: IContentEntitlementsHandler = {
getAllContentEntitlements: (
provider: IContentEntitlementsProvider,
) => {
let myCloudHasMoreData = true;
while(myCloudHasMoreData){
let myCloudResponse = getNextPageFromMyBackend();
let myCloudData = myCloudResponse.getData();
let entitlements: IContentEntitlements[] = [];
for(let element in myCloudData){
let entitlement = <ContentEntitlementBuilderを使用してデータを作成>
entitlements.push(entitlement)
}
provider.addContentEntitlementChunk(entitlements);
myCloudHasMoreData = myCloudResponse.hasMoreData();
}
provider.commit();
},
};
Last updated: 2025年9月30日

