as

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

アカウントログイン統合ガイド

アカウントログイン統合ガイド

VegaメディアアカウントログインAPIは、アプリの認証ステータスをシステムに報告する方法を提供します。

アプリでは、起動するたびにユーザーのログインステータスを更新する必要があります。これはアカウントログインAPIを通じて行われます。アカウントのログインステータスには、サインイン済みとサインアウトの2つがあります。アプリは、ログインステータスを最新の状態に保つことによって、ユーザーが適切なコンテンツや機能にアクセスできるようにします。このインターフェイスを使用すると、アプリの起動時とログイン状態の変更時に、ユーザーがログインしているかどうかを示すブール値をアプリから伝達できます。システムが必要に応じてこのステータスを照会することもできるため、パーソナライズされたユーザーエクスペリエンスが可能になります。

製品では、この情報を活用し、ユーザーが既に認証されているサービスのコンテンツを取り上げたりフィルタリングしたりして、コンテンツへのすばやいアクセスを実現できます。

アカウントログイン機能には、認証ステータスを管理するための主要な2つのコンポーネントとして、updateStatusメソッドとhandleReadStatusコールバック関数が含まれています。updateStatusメソッドは、認証状態が変更されたときに、アプリの現在のログインステータスを報告してリアルタイムで更新します。handleReadStatusコールバック関数は、アプリの現在のログインステータスに関するシステムからの照会に応答します。どちらのメソッドでも、アカウントステータスを表すにはStatusTypeが使用されます。これは、 SIGNED_INSIGNED_OUTの2つの値になる可能性があります。

VegaメディアアカウントログインAPIのリファレンス

このAPIのリファレンスドキュメントについては、コンテンツランチャーAPIとアカウントログインAPIの概要を参照してください。

Vegaメディアアカウントログインの一般的なユースケース

次のような場合は、アプリのログインステータスを反映するようにシステムをアップデートする必要があります。

  • アプリの初回起動時
  • ユーザーのサブスクリプションステータスに変更があった場合
  • 他のサービスから要求があった場合

Vegaメディアアカウントログインのインストールとセットアップ

手順1: アプリのマニフェストを更新する

アカウントログインの操作の一部は、サービスコンポーネントを使用して処理します。サービスコンポーネントについての理解を深めてください。これはヘッドレスコンポーネントとも呼ばれます。対話型コンポーネントと並行してサービスを動作させることで、この統合の実行とトラブルシューティングが容易になります。サービスコンポーネントのドキュメントを参照してください。

まず、アプリのマニフェストを更新して、VegaメディアアカウントログインAPIを使用するように設定します。マニフェストエントリを変更するときは、以下の例に含まれているcom.amazondeveloper.media.sampleを、アプリの実際のパッケージIDに置き換えてください。通常、アカウントログインAPIは、特に読み取り操作中にアカウントログインステータスを提供するサービスとして実装されます。ユーザーに対話型インターフェイスベースのアプリを開くことを要求しないでください。メディアプロバイダーアプリは、ほとんどの場合、ユーザーインターフェイスを処理する対話型アプリとして実装されます。対話型アプリとサービスアプリは、アカウントログイン情報を互いに交換する必要があります。これには、共有ファイルやその他のプロセス間通信メカニズムを使用できます。

以下の例は、コンテンツランチャーAPIとアカウントログイン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"]

[[components.service]]
id = "com.amazondeveloper.media.sample.interface.provider"
runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"

[processes]

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

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

[offers]

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

[[offers.service]]
id = "com.amazondeveloper.media.sample.interface.provider"
required-privileges = ["com.amazon.multimedia.privilege.session.manage"]

[[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"
attribute_options = ["partner-id"]
static-values = { "partner-id" = "<パートナーID>" }

[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IAccountLoginServer"
attribute_options = ["Status"]
# このマニフェストの例では、コンテンツランチャーとアカウントログインの両方のインターフェイスを定義しています。
# アカウントログインクラスターは、応答性の理由から対話型コンポーネントではなくサービスコンポーネントで
# 処理する必要があるため、"override_attribute_component" を使用して "Status" 属性の呼び出しを
# サービスコンポーネントにリダイレクトします。
override_attribute_component = { Status = "com.amazondeveloper.media.sample.interface.provider" }

[needs]

[[needs.module]]
# この形式では、「media」の後に意図的にドット(.)が追加されています。この表記は今後のリリースで
# 変更される予定です。
id = "/com.amazon.kepler.media.@IAccountLogin1"

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

メディアアプリは、多くの場合、次の3つの主要なAPIと統合する必要があります。

  • コンテンツランチャークラスターAPI。コンテンツを検索して起動するために使用します。
  • VegaメディアコントロールAPI。起動したメディアを制御するために使用します。
  • アカウントログインAPI。アカウントログインステータスをシステムに伝達するために使用します。

コンテンツランチャーAPIとVegaメディアコントロールAPIは、ほとんどの場合、Vegaメディアクエリを処理する対話型コンポーネントとして実装されます。このコンポーネントは、以下のTOMLスニペットや前の例に示されているように、アプリマニフェストのextrasセクションでinterface.providerキーを使用して指定します。

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

[[extras]]
key = "interface.provider"
component-id = "<主要対話型コンポーネントのID>"

アカウントログインAPIはサービスアプリとして実装され、アプリ全体が起動していなくても、システムからのアカウントログインステータスの照会に応答できます。アカウントログインAPIは、サービスコンポーネントによって処理される1つのStatus属性を使用します。ログインステータス属性の操作が適切にルーティングされるようにするには、以下のTOMLの例や前の例に示されているように、アプリのマニフェストで「override_attribute_component」設定を使用してサービスコンポーネントを指定する必要があります。

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

override_attribute_component = { Status = "<アカウントログインAPIを実装しているサービスコンポーネントのID>" }

このアプローチを使用すると、システムパフォーマンスが最適化され、メディアコントロールとアカウント管理の機能を明確に切り分けることができます。

手順2: パッケージの依存関係を追加する

VegaメディアアカウントログインAPIは、システムターボモジュールであるamzn/kepler-media-account-loginを使用してTypeScript開発者に提供されます。このターボモジュールはSDKパッケージの一部です。APIを使用するには、ターボモジュールを依存関係として取り込むようにpackage.jsonを更新し、amzn/headless-task-managerを使用してヘッドレスサービスアプリを作成します。

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

"dependencies": {
  "@amazon-devices/kepler-media-account-login": "^1.1.0",
  "@amazon-devices/headless-task-manager": "^1.1.0"
}

手順3: Vegaメディアアカウントログインのビジネスロジックを追加する

AccountLoginWrapper.tsという名前のファイルを作成して、VegaメディアアカウントログインAPIのコアビジネスロジックを含めます。このファイルで、AccountLoginWrapperという名前のクラスを作成してエクスポートします。このクラスには、アカウントログインサーバーとのやり取りに使用される、IAccountLoginServerAsyncインターフェイスのインスタンスを表すメンバー変数を1つ含めます。さらにこのファイルでは、AccountLoginServerComponentのインスタンスをグローバルに作成し、それをaccountLoginServerComponentという名前の変数に格納します。

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

import { IComponentInstance } from '@amazon-devices/react-native-kepler';
import {
  AccountLoginServerComponent,
  IAccountLoginHandlerAsync,
  StatusType,
  IAccountLoginServerAsync,
  IStatus,
} from '@amazon-devices/kepler-media-account-login';
import AsyncStorage from '@react-native-async-storage/async-storage';

const accountLoginServerComponent = new AccountLoginServerComponent();

export class AccountLoginWrapper {
  accountLoginServer?: IAccountLoginServerAsync;
}

手順4: アカウントログインステータスを非同期に返す

ここで、IAccountLoginHandlerAsyncを使用してhandleReadStatus()メソッドを実装します。このメソッドは引数を持たず、Promise<IStatus>を返します。メソッドをこのように設計することで、サービスアプリからアカウントログインステータスを非同期に返すことができ、呼び出し元がブロックされません。Promise<IStatus>戻り型は、このメソッドが最終的にIStatusオブジェクトで解決されることを示します。このオブジェクトには、現在のログイン状態に関する情報が含まれている可能性があります。

handleReadStatus()ハンドラーは、後の手順8で作成するヘッドレスサービスによって呼び出されます。対話型コンポーネント(UIアプリ)とヘッドレスサービスは別々のプロセスで実行されるため、メモリ内の状態は共有されません。したがって、メモリ内の変数に依存する処理では不十分です。2つのコンポーネント間で信頼性の高いやり取りを実現するには、共有のメカニズムを使用して、ログインステータスを永続化して転送します。ログインステータスは、この永続ストレージから非同期に読み取る必要があります。ヘッドレスサービスでは現在、ReactのAsyncStorageとVegaファイルシステムがサポートされています。MMKV(英語のみ)はサポートされません。この例ではAsyncStorageを使用しています。

以下は、AsyncStorageを利用するコンポーネントの実装例を示しています。

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

// 対話型コンポーネント
// 「com.amazondeveloper.media.sample.main」の内部
const onLoginChange = async (newStatus: boolean) => {
  await AsyncStorage.setItem('loginStatus', newStatus);
};

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

// サービスコンポーネント
// 「com.amazondeveloper.media.sample.interface.provider」の内部
const getLoginStatus = async (): boolean => {
  return await AsyncStorage.getItem('loginStatus');
};

handleReadStatus()ハンドラーを登録して、システムから呼び出されたときにログインステータスを返します。getLoginStatus()では、前述のように永続ストレージからステータスを読み取る必要があります。getLoginStatus()はアプリに固有です。

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

export class AccountLoginWrapper {
  async getAccountLoginStatus(): IStatus {
    return accountLoginServerComponent.makeStatusBuilder()
      .status(
        // 永続ストレージからステータスを取得します。
        (await getLoginStatus())
          ? StatusType.SIGNED_IN
          : StatusType.SIGNED_OUT)
      .build();
  }

  createAccountLoginHandler(): IAccountLoginHandlerAsync {
    return {
      handleReadStatus: async (): Promise<IStatus> => {
        console.log('handleReadStatus()が呼び出されました。')
        return await this.getAccountLoginStatus();
      }
    };
  }
}

次に、AccountLoginWrapperクラスにsetupAccountLoginServer()メソッドを導入します。このメソッドは、IComponentInstanceオブジェクトをパラメーターとして受け入れます。以下のように実装します。

  1. IAccountLoginServerAsyncのシングルトンインスタンスを作成し、メンバー変数のaccountLoginServerに格納します。
  2. 次にsetHandlerForComponent()を呼び出して、手順4で作成したhandleReadStatus()ハンドラーと、提供されたComponentInstanceを渡します。

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

export class AccountLoginWrapper {
  setupAccountLoginServer(componentInstance: IComponentInstance) {
    console.log('setupAccountLoginServer()が呼び出されました。');
    try {
      this.accountLoginServer = accountLoginServerComponent.getOrMakeServer();
    } catch (error) {
      this.accountLoginServer = undefined;
      console.error(
        'setupAccountLoginServer()でアカウントログインサーバーの作成に失敗しました:',
        error,
      );
      return;
    }

    try {
      this.accountLoginServer?.setHandlerForComponent(this.createAccountLoginHandler(), componentInstance);
    } catch (error) {
      console.error(
        'setupAccountLoginServer()でハンドラーの設定に失敗しました:',
        error,
      );
    }
    console.log('setupAccountLoginServer()が完了しました。');
  }
}

手順6: アカウントログインステータスを更新する

アカウントログインステータスを更新するには、updateStatus()メソッドを非同期的に使用します。この関数を呼び出す前に、必ずログインステータスを永続ストレージに保存してください。

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

export class AccountLoginWrapper {
  async updateStatus(loginStatus: boolean) {
    console.log('updateStatus()が呼び出されました。');
    const status = accountLoginServerComponent.makeStatusBuilder()
      .status(loginStatus ? StatusType.SIGNED_IN : StatusType.SIGNED_OUT,)
      .build();
    try {
      this.accountLoginServer?.updateStatus(status);
    } catch (error) {
      console.error(
        'updateStatus()でログインステータスの更新に失敗しました:',
        error,
      );
    }
  }
}

手順7: アカウントログインサーバーをサービスのライフサイクルと統合する

この統合を行うために、AccountLoginWrapperクラスでonStart()onStop()の2つのメソッドを公開します。

onStart()

onStart()メソッドは、提供されたIComponentInstanceと共にsetupAccountLoginServer()を呼び出して、アカウントログインサーバーを初期化します。

onStop()

onStop()メソッドは、サービスを停止するときに実行する必要のあるクリーンアップロジックを追加します。

これらを実装したら、AccountLoginWrapperInstanceというシングルトンインスタンスを作成し、それを使用して、同等のトップレベルメソッドとなるonStartService()onStopService()の2つを公開します。これらのメソッドは、サービスコンポーネントと対話型コンポーネントの両方で、アカウントログインサーバーを起動および停止するために使用します。

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

export class AccountLoginWrapper {
  onStart(componentInstance: IComponentInstance): Promise<void> {
    this.setupAccountLoginServer(componentInstance);
    return Promise.resolve();
  }

  onStop(): Promise<void> {
    // ここにクリーンアップコードを追加します。
    return Promise.resolve();
  }
}

export const AccountLoginWrapperInstance = new AccountLoginWrapper();

export const onStartService = (componentInstance: IComponentInstance): Promise<void> => {
  return AccountLoginWrapperInstance.onStart(componentInstance);
};

export const onStopService = (): Promise<void> => {
  return AccountLoginWrapperInstance.onStop();
};

手順8: ヘッドレスサービスを実装する

ヘッドレスサービスは、独自のReact Nativeランタイムを使用して、ユーザーインターフェイスなしで動作するバックグラウンドプロセスです。このサービスはログインステータスリクエストに応答するために重要なものであり、以下の手順で作成できます。

  1. アプリのルートディレクトリにservice.jsという名前の新しいファイルを作成します。
  2. 前の手順で作成したAccountLoginWrapperをインポートし、headless-task-managerもインポートします。

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

     import { HeadlessEntryPointRegistry } from '@amazon-devices/headless-task-manager';
     import { onStartService, onStopService } from './src/AccountLoginWrapper';
    
  3. 開始エントリポイントと終了エントリポイントを定義します。

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

     HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
       'com.amazondeveloper.media.sample.interface.provider::onStartService',
       () => onStartService
     );
    
     HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
       'com.amazondeveloper.media.sample.interface.provider::onStopService',
       () => onStopService
     );
    
    • com.amazondeveloper.media.sampleをアプリの実際のパッケージIDに置き換えてください。
    • エントリポイントの命名規則は、<アプリのパッケージID>.interface.provider::onStartServiceまたは::onStopServiceです。

Fire TVのシステムコンポーネントは、自動的にonStartService()を呼び出して、アカウントログインサーバーをヘッドレスサービスとして初期化します。このプロセスの間に、handleReadStatus()関数が特定のサービスコンポーネントのインスタンスに登録されます。

このハンドラーが後でシステムから呼び出されると、handleReadStatus()は、アプリから報告された現在のログイン状態(サインイン済みまたはサインアウト)を返します。

手順9: ログイン状態を報告できるようにアカウントログインサーバーを初期化する

対話型コンポーネント(UIアプリ)でも、updateStatus()メソッドを使用してユーザーのログイン状態を報告するために、アカウントログインサーバーを初期化する必要があります。

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

// 「com.amazondeveloper.media.sample.main」の内部
useEffect(() => {
  AccountLoginWrapperInstance.onStart(componentInstance);

  return () => {
    AccountLoginWrapperInstance.onStop();
  };
}, []);

手順10: ログインステータスの更新を送信する

対話型コンポーネント(UIアプリ)は、次のシナリオの発生時に、現在のログインステータスを指定してupdateStatus()メソッドを呼び出す必要があります。

  1. アプリの起動時
  2. ユーザーのログインステータスの変更時

毎回、updateStatus()を呼び出す前にステータスを永続ストレージに保存して、handleReadStatus()で正しい値が取得され、返されるようにする必要があります。これにより、ユーザーの認証状態がシステムに常に反映され、シームレスなユーザーエクスペリエンスが実現されます。

このセットアップにより、メインアプリがアクティブに実行されていない場合でも、アプリでログインステータスリクエストを管理できます。

これでIAccountLoginServerComponentAsyncの単一のインスタンスが作成されました。handleReadStatus()メソッドとIComponentInstanceの間にリンクが確立され、すべての読み取りリクエストはサービスコンポーネントに送られます。これを通じてアカウントログインステータスのクエリが処理されます。また、updateStatus()メソッドも2つの状況に対応して呼び出されます。この呼び出しは、ログインステータスを強制的に更新する場合と、ステータスが変更されたときに行われます。

Vegaメディアアカウントログインに関するトラブルシューティング

アカウントログインとの統合時に発生する可能性のある問題はいくつか考えられますが、ここでは、特によくある問題の一部について説明します。

サービスコンポーネントが起動することを確認する

updateStatus()の呼び出しが実行されているかどうかを確認してください。これにより、サービスコンポーネントがクラッシュせずに起動していることを確認できます。

そのためには、kepler device launch-app com.your.app.id.interface.providerを実行する前にログのキャプチャを開始します。これで、サービスコンポーネントの起動シーケンスの動作を監視できます。サービスコンポーネント名に対応するログが表示されるので、このフェーズでクラッシュが発生していないかどうかを確認します。ログはregisterHeadlessEntryPoint()onStartService)エントリポイントに到達した後に出力されます。

目的のログが見つからない場合、エラーまたはクラッシュを示すログが表示されることがあります。その場合は、Vegaのクラッシュのデバッグに関するドキュメントを参照すると役立ちます。

ハンドラーが呼び出されることを確認する

サービスが正常に起動していることがわかったら、サービスでsetHandlerForComponent()が使用され、ハンドラーが正しく登録されていることを確認します。この呼び出しの前後にログを追加すると、そのパスが実行されることを確認できます。確認として、サービスコンポーネントIDに対応するhandle_set_response_handlerからも同等のログが表示されます。

さらに、handleReadStatus()の前後にもログを追加して、想定どおりに機能していることを確認します。


Last updated: 2025年9月30日