as

Settings
Sign out
Notifications
Alexa
Amazonアプリストア
AWS
ドキュメント
Support
Contact Us
My Cases
開発
設計と開発
公開
リファレンス
サポート

コンテンツランチャー統合ガイド

コンテンツランチャー統合ガイド

このドキュメントでは、コンテンツランチャーをアプリに統合する方法について説明します。メディアアプリは通常、次の3つの主要なAPIと統合する必要があります。

  1. コンテンツランチャーAPI
  2. VegaメディアコントロールAPI
  3. アカウントログインAPI

コンテンツランチャーAPIとVegaメディアコントロールAPIは、Vegaメディアクエリを処理するメインコンポーネントである対話型コンポーネントに実装されます。アカウントログインAPIはサービスコンポーネントとして実装されます。

手順1: アプリのマニフェストファイルを更新します。

アプリのmanifest.tomlファイルに、コンテンツランチャーのサポートを含めます。この例では、パッケージIDをcom.amazondeveloper.keplervideoappと想定しています。このパッケージIDをアプリのパッケージIDに置き換えてください。

アプリは、VegaメディアコンテンツランチャーAPIとやり取りするように正しく構成されている必要があります。

クリップボードにコピーしました。

schema-version = 1

[package]
title = "<アプリタイトル>"
id = "com.amazondeveloper.media.sample"

[components]
[[components.interactive]]
id = "com.amazondeveloper.media.sample.main"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"
# カテゴリ "com.amazon.category.kepler.media" は主要コンポーネントのみに必要で、マニフェストの [[extras]]
# セクションの "component-id" 値を使用して識別されます。
categories = ["com.amazon.category.main", "com.amazon.category.kepler.media"]

[processes]
[[processes.group]]
component-ids = ["com.amazondeveloper.media.sample.main"]

[offers]
[[offers.interaction]]
id = "com.amazondeveloper.media.sample.main"

[[message]]
uri = "pkg://com.amazondeveloper.media.sample.main"
# [[offers.interaction]] で使用した権限と一致させます。権限が追加されていない場合は "*" を使用します。
sender-privileges = ["*"]
receiver-privileges = ["self"]

[[offers.module]]
id = "/com.amazondeveloper.media.sample.module@ISomeUri1" 
includes-messages = ["pkg://com.amazondeveloper.media.sample.main"]

[[extras]]
key = "interface.provider"

component-id = "com.amazondeveloper.media.sample.main"

[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"

# "override_command_component" フィールドは、[[extras]] セクションで指定されている "component-id" が
# ここで指定するcomponent-idと異なる場合のみ必要です。これにより、コマンドの実行時に
# extrasで最初に定義されていたコンポーネントとは別のコンポーネントを使用できるため、
# 柔軟な設定が可能になります。

# たとえば、コンテンツランチャーインターフェイスに加えてアカウントログインインターフェイスを
# 使用している場合は、アカウントログインのStatus属性をオーバーライドして、サービスにリダイレクトする
# 必要があります。これには次の行を使用します。
# override_command_component = { Status = "com.amazondeveloper.media.sample.interface.provider" }
attribute_options = ["partner-id"]
static-values = { partner-id = "<パートナーID>" }

[needs]

[[needs.module]]
id = "/com.amazon.kepler.media@IContentLauncher1"

手順2: アプリで必要なパッケージの依存関係を追加する

package.jsonファイルに、依存関係として@amazon-devices/kepler-media-content-launcherパッケージを追加します。

クリップボードにコピーしました。

"dependencies": {
    "@amazon-devices/kepler-media-content-launcher": "^2.0.0",
},

手順3: コンテンツランチャーAPIを実装する

  1. コンテンツランチャーハンドラーを定義します。

    新しいContentLauncherServerComponentをインスタンス化します。コールバック関数をカプセル化するハンドラーオブジェクトを作成します。

    クリップボードにコピーしました。

    import {
    ILauncherResponse,
    IContentLauncherHandler,
    ContentLauncherStatusType,
    ContentLauncherServerComponent,
    IContentSearch,
    ILaunchContentOptionalFields,
    } from '@amazon-devices/kepler-media-content-launcher';
    
    ...
    // ContentLauncherServerComponentのインスタンスを作成します。
    let factory = new ContentLauncherServerComponent();
    
    // コンテンツの起動がリクエストされたときに呼び出されるハンドラーを作成します。
    const contentLauncherHandler: IContentLauncherHandler = {
       async handleLaunchContent(
          contentSearch: IContentSearch,
          autoPlay: Boolean,
          _optionalFields: ILaunchContentOptionalFields,
       ): Promise<ILauncherResponse> {
          console.log('Content_Launcher_Sample: handleLaunchContent invoked');
    
          // ここでデータを取得するために繰り返し処理を行い、
          // 起動リクエストを処理するビジネスロジック
    
          let launcherResponse = factory
                .makeLauncherResponseBuilder()
                .contentLauncherStatus(ContentLauncherStatusType.SUCCESS)
                .build();
          return Promise.resolve(launcherResponse);
       },
    };
    

    ハンドラーはリクエストを処理し、ILauncherResponseに解決されるPromiseを返す必要があります。これは、ContentLauncherServerComponentのインスタンスを使用して作成します。アプリが正常にリクエストを処理した場合は、LauncherResponsecontentLauncherStatusのステータスをContentLauncherStatusType.SUCCESSに設定します。認可の問題が原因でアプリがリクエストを処理できなかった場合は、ステータスをContentLauncherStatusType.AUTH_FAILEDに設定します。それ以外の場合は、ステータスをContentLauncherStatusType.URL_NOT_AVAILABLEに設定します。

  2. 対話型アプリにVegaメディアコンテンツランチャーを実装します。

    対話型アプリにVegaメディアコンテンツランチャーを実装するには、まずIContentLauncherServerAsyncのシングルトンインスタンスを取得します。これは、ContentLauncherServerComponentインスタンスのgetOrMakeServerメソッドを使用して行うことができます。次に、IContentLauncherHandlerインターフェイスを実装するハンドラーオブジェクトを作成して、コンテンツ起動リクエストを処理します。IContentLauncherServerAsyncインスタンスのsetHandlerForComponentメソッドを呼び出して、このハンドラーを正しいコンポーネントに関連付けます。このとき、ハンドラーと適切なIComponentInstanceを渡します。対話型アプリでは、useComponentInstanceメソッドを使用してIComponentInstanceを取得できます。React Nativeアプリの場合は、useEffectフック内でハンドラーを設定します。コンポーネントがマウントされ、IComponentInstanceが利用可能になったらすぐに、コンテンツランチャーを初期化する必要があります。これにより、コンテンツランチャーの機能がコンポーネントのライフサイクルと緊密に統合されます。また、初期化された時点から、アプリでVegaコンテンツランチャーのコマンドを効率的に処理することが可能になります。このセットアップでは、各コンポーネントで確実にIComponentInstanceが使用され、コールバックルーティングの混乱を防ぐことができます。これは複数のコンポーネントを使用するアプリにとって重要です。

    クリップボードにコピーしました。

    import { useComponentInstance , IComponentInstance } from '@amazon-devices/react-native-kepler';
    
    export const App = () => {
    
    const componentInstance: IComponentInstance = useComponentInstance();
    
    useEffect(() => {
       const factory = new ContentLauncherServerComponent();
    
       const contentLauncherHandler: IContentLauncherHandler = {
    
          async handleLaunchContent(
          contentSearch: IContentSearch,
          autoPlay: boolean,
          _optionalFields: ILaunchContentOptionalFields,
          ): Promise<ILauncherResponse> {
          console.log('Content_Launcher_Sample: handleLaunchContent invoked.');
    
          // 繰り返し処理して..
          //..ここでデータを取得します
    
          const launcherResponse = factory
             .makeLauncherResponseBuilder()
             .contentLauncherStatus(ContentLauncherStatusType.SUCCESS)
             .build();
    
          return Promise.resolve(launcherResponse);
          },
       };
    
       const contentLauncherServer = factory.getOrMakeServer();
       contentLauncherServer.setHandlerForComponent(contentLauncherHandler,componentInstance);
    
       return () => {};
    }, []);
    
    // ここでプロバイダーアプリのユーザーインターフェイスを作成します。
    };
    

実装の詳細

IContentLauncherHandlerハンドラーは、再生するコンテンツ、または検索結果に表示するコンテンツを定義する3つのパラメーターを取ります。

  • IContentSearchインターフェイスを実装しているオブジェクトへのポインター。
  • autoPlayと呼ばれるブール値。
  • ILaunchContentOptionalFieldsインターフェイスを実装しているオブジェクトへのポインターを介して渡される任意の追加フィールド。

autoPlayを使用して実行するアクションを決定します。

autoPlayがtrueの場合はクイック再生のリクエストです。リクエストされたコンテンツは、ユーザーが追加の操作を行わなくても直接再生できる必要があります。autoPlayがfalseの場合は検索結果を表示します。これにより、ユーザーは使用可能なオプションを確認して選択できます。

contentSearch:IContentSearchの値を取得します。

このパラメーターには、ユーザーがコンテンツランチャーやAlexaを通じて送信したコンテンツが含まれています。以下は、contentSearch:IContentSearchに格納される値のスキーマです。

クリップボードにコピーしました。

1    "parameterList": [{
1.1     "type": "<エンティティタイプ>",
1.2     "value": "<エンティティの値>",
1.3     "externalIdList": [{
1.3.1          "name": "<外部ID名>",
1.3.2          "value": "<外部IDの値>"
        }]
      }]

1 parameterListには1つ以上のエントリがあります。リスト全体を取得するには、contentSearch.getParameterList().lengthを使用します。

1.1 <エンティティタイプ> は、パラメーターにリストされているエンティティのタイプを表します。サポートされているすべてのエンティティタイプの一覧については、Enumeration ContentSearchParamType(英語のみ)を参照してください。たとえば、映画またはTV番組の場合、“type”“ContentSearchParamType::VIDEO”になります。タイプを取得するにはgetParamType()を呼び出します。

1.2 <エンティティ値> は、タイプで指定されたエンティティの値を表します。このフィールドを取得するにはgetValue()を呼び出します。

1.3 parameterListには1つ以上の外部IDがあります。リストのサイズを取得するにはgetExternalIdList().lengthを使用します。getExternalIdList()を使用すると、externalIdListの完全なリストを取得できます。

1.3.1 getName()は通常、<外部ID名>を取得します。externalIdの名前がamzn_idの場合は、その値を特定します。

1.3.2 <外部IDの値> はexternalIdの値を表します。この値を取得するには、getValue()を使用します。getValue()は、カタログ統合で使用された<ID>または<起動ID>と同じ値を返します。これにより、ユーザーが視聴しようとしているコンテンツを特定できます。

例: リクエストされた検索パラメーターの抽出と検索

次のコードサンプルは、リクエストされた検索パラメーターを抽出して検索する方法を示しています。このアプローチでは、さまざまな情報が単一の文字列に統合され、handleLaunchContentメソッド内で変更を加えて使用できます。

以下の例では、「Streamzで『The SeaShow: The Real Story』のシーズン2、エピソード5を見せて」というAlexaへの発話を使用してエピソードを起動します。

クリップボードにコピーしました。

// データを取得するイテレータ。
let searchParameters = contentSearch.getParameterList();
if (searchParameters.length > 0) {
   for (var j = 0; j < searchParameters.length; j++) {
      let paramType = searchParameters[j].getParamType();
      let searchString = searchParameters[j].getValue();

      let additionalInfoList = searchParameters[j].getExternalIdList();
      for (var i = 0; i < additionalInfoList.length; i++) {
         let searchName = additionalInfoList[i].getName();
         let entityID = additionalInfoList[i].getValue();

         if (searchName == 'amzn_id') {
         // このエンティティIDを使用してカタログから正確なコンテンツを取得します。

         } else {
            // 例:
            // entityID= "エンティティID" :
            // searchName = "amzn1.p11cat.merged-video.087c9371-6bb7-5edb-bcef-f8717fde0a8a"
            //
         }
      }
   }
   if (autoPlay) {
      console.log(`Content_Launcher_Sample: Quickplay`);

      // 上記で取得したデータを使用して、ここで再生ロジックを処理します。
   } else {
      console.log(`Content_Launcher_Sample: In-App search`);

      // 上記で取得したデータを使用して、ここで検索ロジックを処理します。
   }
} else {
   console.log('Content_Launcher_Sample: 検索文字列を取得中にエラーが発生しました');
}
// データを取得するイテレータ。

コンテンツランチャーリクエストの例

以下の例では、コンテンツランチャーの主なユースケースにおけるcontentSearchパラメーターの値について説明します。ここには、サポートされるユースケースがすべて示されています。どのユースケースでも、コンテンツランチャーが呼び出され、アプリが起動されます。

以下はstreamz_usのサンプルカタログで、エントリの例として「Seabound」という映画と「The SeaShow: The Real Story」というTV番組が含まれています。

クリップボードにコピーしました。

...
<Movie>
  <ID>1700000725</ID>
  <Title locale="en-US">Seabound</Title>
  <Offers>
    <SubscriptionOffer>
      <LaunchDetails>
        <Quality>UHD</Quality>
        <Subtitle>en-US</Subtitle>
        <LaunchId>tv.streamz/movie/46720001</LaunchId>
      </LaunchDetails>
    </SubscriptionOffer>
    <FreeOffer>
      <Regions>
        <Territories>US</Territories>
      </Regions>
      <LaunchDetails>
        <Quality>SD</Quality>
        <Subtitle>en-US</Subtitle>
        <LaunchId>tv.streamz/movie/467200002</LaunchId>
      </LaunchDetails>
    </FreeOffer>
  </Offers>
</Movie>

<TvShow>
  <ID>1700000123</ID>
  <Title locale="en-US">The SeaShow: The Real Story</Title>
  <Offers>
    <FreeOffer>
      <Regions>
        <Territories>US</Territories>
      </Regions>
      <LaunchDetails>
        <Quality>HD</Quality>
        <Subtitle>en-US</Subtitle>
        <LaunchId>459800033</LaunchId>
      </LaunchDetails>
    </FreeOffer>
  </Offers>
</TvShow>

<TvSeason>
  <ID>1700000234</ID>
  <Title locale="en-US">Season 1</Title>
    <Offers>
     <FreeOffer>
       <Regions>
         <Territories>US</Territories>
       </Regions>
       <LaunchDetails>
         <Quality>HD</Quality>
         <Subtitle>en-US</Subtitle>
         <LaunchId>453200012</LaunchId>
        </LaunchDetails>
     </FreeOffer>
   </Offers>
   <ShowID>1700000123</ShowID>
   <SeasonInShow>2</SeasonInShow>
</TvSeason>

<TvEpisode>
  <ID>1700000825</ID>
  <Title locale="en-US">The Seashow.Story Starts</Title>
  <Offers>
    <FreeOffer>
      <Regions>
        <Territories>US</Territories>
      </Regions>
      <LaunchDetails>
        <Quality>HD</Quality>
        <Subtitle>en-US</Subtitle>
        <LaunchId>453100008</LaunchId>
      </LaunchDetails>
    </FreeOffer>
  </Offers>
  <ShowID>1700000123</ShowID>
  <SeasonID>1700000234</SeasonID>
  <EpisodeInSeason>5</EpisodeInSeason>
</TvEpisode>
...

リモコンによるコンテンツの起動

Vega TVのホーム画面から、リモコンを使用して映画「Seabound」を起動します。

クリップボードにコピーしました。

"parameterList": [
  {                                           // パラメーター0。
      "type": 13,                             // ContentSearchParamType::VIDEO,
      "value": ,                              // コンテンツタイトル含まれません。
      "externalIdList": [{
          "name": "catalogContentId",          // 廃止される予定です。 これは無視してください。
          "value": "tv.catalog/movie/46720000" // カタログからのIDまたはLaunchId。
      }, 
      {
          "name": "amzn_id",          
          "value": "tv.catalog/movie/46720000" // カタログからのIDまたはLaunchId。
      }
     ]
  }
]

アプリでは、tv.streamz/movie/46720000LaunchIdとして使用して映画を特定し、直接再生する必要があります。

音声によるクイック再生

音声を使用して映画「Seabound」を再生します。「アレクサ、『Seabound』を再生して」という発話を使用します。

ここではautoPlaytrueになります。contentSearch: IContentSearchには、以下のサンプルに示すような値が設定されます。アプリが起動し、ID 1700000725を使用してコンテンツが直接再生されます。

クリップボードにコピーしました。

[
    {                             // パラメーター0。
        "type": 13,               // ContentSearchParamType::VIDEO
        "value": "Seabound",      // 検索文字列。
        "externalIdList": [{
            "name": "streamz_us"  // カタログID。 廃止される予定です。 これは無視してください。
            "value": "1700000725" // カタログからのID。
        },
        { 
            "name": "amzn_id"  
            "value": "1700000725" // カタログからのID。
        }
      ]
    }
]

音声による特定のエピソードの再生

以下のサンプルカタログは、TV番組「SeaShow: The Real Story」と、そのシーズンおよびエピソードを表しています。Alexaに「アレクサ、『The SeaShow: The Real Story』のシーズン2、エピソード5を再生して」という発話を使用すると、アプリが呼び出され、指定されたエピソードが再生されます。

ここではautoPlaytrueになります。contentSearchには番組のIDのみが設定され、エピソードIDは含まれません。アプリでは、ID 1700000123ContentSearchParamType::SEASONContentSearchParamType::EPISODEの各値を使用してエピソードを正確に特定する必要があります。

クリップボードにコピーしました。

[
  {                // パラメーター0。
    "type": 13,    // ContentSearchParamType::VIDEO
    "value": "The SeaShow: The Real Story シーズン2 エピソード5", 

    "externalIdList": [{
       "name": "streamz_us", // 廃止される予定ですこれは無視してください。
       "value": "1700000123" // カタログから番組ID。
     },
     {
      "name": "amzn_id",
      "value": "1700000123" // カタログから番組ID。
    }]
  },
  {                // パラメーター1。
    "type": 14,    // ContentSearchParamType::SEASON
    "value": "2",  // カタログ内のシーズン番号。
    "externalIdList": []
  },
  {               // パラメーター2。
    "type": 15,   // ContentSearchParamType::EPISODE
    "value": "5", // カタログ内のエピソード番号。
    "externalIdList": []
  }
]

音声によるコンテンツタイトルのアプリ内検索

音声を使用して映画「Seabound」を検索します。これを行うには、「アレクサ、Streamzで『Seabound』を検索して」という発話を使用します。

アプリでは、「Seabound」の検索結果と、関連するコンテンツを表示する必要があります。検索ロジックはアプリに任されます。ここではautoPlayfalseになります。contentSearch: IContentSearchには、以下の値が設定されます。

クリップボードにコピーしました。

[
  {                      // パラメーター0。
    "type": 13,          // ContentSearchParamType::VIDEO
    "value": "Seabound", // 検索使用する検索キーワード。
    "externalIdList": [{
        "name": "streamz_us",  // 廃止される予定です。 これは無視してください。
        "value": "1700000725"  // カタログからのID。
    },
   {
        "name": "amzn_id",
        "value": "1700000725" // カタログからのID。
    }
   ]
  }
]

音声によるジャンルのアプリ内検索

音声を使用してジャンルを検索します。「アレクサ、Streamzでコメディ映画を検索して」という発話を使用します。

ここではautoPlayfalseになります。contentSearch: IContentSearchには、以下の値が設定されます。Alexaは複数のジャンルとタイプを返します。アプリでは、独自のロジックを使用して検索を実装できます。

クリップボードにコピーしました。

 [
  {                               // パラメーター0。
    "type": 6,                    // ContentSearchParamType::GENRE
    "value": "コメディ",          // 検索使用する検索キーワード。
    "externalIdList": []
  },
 {                                // パラメーター1。
    "type": 6,                    // ContentSearchParamType::GENRE
    "value": "ダークコメディ",    // 検索使用する検索キーワード。
    "externalIdList": []
  },
 {                                // パラメーター2。
    "type": 6,                    // ContentSearchParamType::GENRE
    "value": "ロマンチックコメディ",   // 検索使用する検索キーワード。
    "externalIdList": []
  },
 {                                // パラメーター3。
    "type": 13,                   // ContentSearchParamType::TYPE for VIDEO
    "value": "コメディ映画",      // 検索使用する検索キーワード。
    "externalIdList": []
  }
]

音声による俳優のアプリ内検索

音声を使用して俳優を検索します。「アレクサ、Streamzでショーン・コネリーの映画を検索して」という発話を使用します。

ここではautoPlayfalseになります。contentSearch: IContentSearchには、以下の値が設定されます。

クリップボードにコピーしました。

[
  {                                 // パラメーター0。
    "type": 0,                      // ContentSearchParamType::ACTOR
    "value": "ショーン・コネリー"   // 検索使用する検索キーワード。
    "externalIdList": []
  },
  {                                 // パラメーター1。
    "type": 13,                     // VIDEOを表すContentSearchParamType::TYPE。
    "value": "ショーン・コネリーの映画",   // 検索使用するキーワード。
    "externalIdList": []
  }
]

Last updated: 2025年9月30日