as

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

Vegaヘッドレスタスクとヘッドレスサービス

Vegaヘッドレスタスクとヘッドレスサービス

ヘッドレスJavaScriptタスクとヘッドレスJavaScriptサービスは、ユーザーインターフェイス(UI)とは独立して、バックグラウンドでのJavaScriptコードの実行を可能にするものです。UIを必要とせずにコードを実行できるため、「ヘッドレス」という名前が付いています。 ヘッドレスJavaScriptタスクとヘッドレスJavaScriptサービスはどちらも、長時間実行されるタスクに適しています。両社の違いは、想定されている用途にあります。 ヘッドレスJavaScriptタスクは、いったん起動したら自動的に進行するタスク向けに設計されています。これに対してヘッドレスJavaScriptサービスは、実行中に対話操作が行われることを想定しています。たとえば、ヘッドレスJavaScriptタスクを利用すると、アプリのUIを起動せずに、チャンネルとそのスケジュール情報をバックエンドから取得してFire TVの電子番組表(EPG)に公開できます。このような場合、ヘッドレスJavaScriptタスクとの対話操作は求められません。一方、ヘッドレスJavaScriptサービスはメディア再生に使用できます。メインのJavaScriptランタイムをUIに解放し、セカンダリJavaScriptランタイムをHLSマニフェストのダウンロードと解析に利用して、W3C Media APIを使用してVegaのメディアパイプラインに入力できます。このシナリオでは、UIからヘッドレスJavaScriptサービスを操作してメディアの制御(再生、一時停止など)を行います。

ヘッドレスJSタスクおよびサービスのJSランタイム

ヘッドレスJSタスクとヘッドレスJSサービスは、バックグラウンドでVegaアプリコンポーネントを利用します。その上にセカンダリJavaScriptランタイム(Hermesで動作)を追加することで、JavaScriptコードの実行が可能になり、アプリのJavaScriptコードからライフサイクルイベントをリッスンできます。ヘッドレスJSタスク/サービスの各インスタンスには、それぞれ独自のJavaScriptランタイムインスタンスが保持されます。

ヘッドレスJSコンテキストでサポートされるモジュール

このJavaScriptランタイムは、ユーザーインターフェイスで利用できるものの簡易版で、次の表に示すモジュールのみをサポートしています。この最適化により、JavaScriptランタイムのメモリフットプリントを小さく保つことができます。これはメモリの少ないデバイスにとって非常に重要です。

モジュール 注記
ログ console.log
ネットワーク fetch
タイマー  
Promise  
プラットフォーム インポートには'@amazon-devices/react-native-kepler/Libraries/Utilities/Platform'を使用してください。

import Platform from '@amazon-devices/react-native-kepler/Libraries/Utilities/Platform';
パフォーマンス global.performance.now
ComponentInstanceManager インポートには'@amazon-devices/react-native-kepler/Libraries/ComponentInstance/ComponentInstanceManager'を使用してください。

import { ComponentType, type IComponentInstance } from '@amazon-devices/react-native-kepler/Libraries/ComponentInstance/ComponentInstanceManager';
FileReader インポートには'@amazon-devices/react-native-kepler/Libraries/Blob/FileReader'を使用してください。

import FileReader from '@amazon-devices/react-native-kepler/Libraries/Blob/FileReader';
URLSearchParams インポートには'@amazon-devices/react-native-kepler/Libraries/Blob/URL'を使用してください。

import {URLSearchParams} from '@amazon-devices/react-native-kepler/Libraries/Blob/URL';
I18nManager インポートには'@amazon-devices/react-native-kepler/Libraries/ReactNative/I18nManager'を使用してください。

import {I18nManager} from '@amazon-devices/react-native-kepler/Libraries/ReactNative/I18nManager';

ヘッドレスJSコンテキストでサポートされるReact Nativeライブラリ

ヘッドレスJSランタイムでサポートされるモジュールは限られており、次の表に示す特定のReact Nativeライブラリのセットのみがサポートされます。

ライブラリ 注記
@amazon-devices/react-native-kepler ヘッドレスJSコンテキストでは限られたモジュールのみを利用できます。上記の一覧を参照してください。ルートの@amazon-devices/react-native-keplerからはインポートしないでください。
@amazon-devices/headless-task-manager  
@amazon-devices/react-native-w3cmedia "@amazon-devices/react-native-w3cmedia/dist/headless"を使用して、対象のモジュールのみをインポートしてください。この「headless」エクスポートは、バージョン2.1.66以降でのみ提供されます。
@amazon-devices/react-native-mmkv  
@amazon-devices/react-native-async-storage/async-storage react-native-async-storageのドキュメントを参照してください。
@amazon-devices/kepler-subscription-entitlement  
@amazon-devices/kepler-media-account-login  
@amazon-devices/kepler-content-personalization  
@amazon-devices/kepler-epg-provider  
@amazon-devices/kepler-epg-sync-scheduler  

サポートされていないモジュールを使用した場合

上記以外のモジュールやライブラリを使用すると、次の例のようなランタイムエラーが発生します。この例では、ヘッドレスJSコンテキストでは使用できないDeviceInfoモジュールに関するエラーを示していますが、ほかにもサポートされていない任意のモジュールで発生する可能性があります。

E Volta:[KeplerScript-JavaScript] Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'DeviceInfo' could not be found.Verify that a module by this name is registered in the native binary., js engine: hermes.

問題となるモジュールを直接インポートしていなくても、このエラーが表示されることがあります。これは、インポートしたほかのモジュールまたはライブラリから、問題となるモジュールが推移的にインポートされる場合に発生する可能性があります。このような状況は、まだサポートされていないライブラリを使用しようとした場合や、上記の指定とは異なる方法でモジュールをインポートした場合に発生します。

たとえば、ヘッドレスJSコンテキストでの実行を想定したJSコードで@amazon-devices/react-native-w3cmediaからインポートすると、headlessエクスポートを介さずに直接インポートすることになります。

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

import { VideoPlayer } from '@amazon-devices/react-native-w3cmedia/dist/headless'; // 正しい
import { VideoPlayer } from '@amazon-devices/react-native-w3cmedia'; // 間違い

@amazon-devices/react-native-w3cmediaは、headlessエクスポートを通じて、ヘッドレスJSコンテキストで安全に実行できるモジュールのみをエクスポートします。インポート時にheadlessを使用しないと、ヘッドレスJSタスク/サービスバンドルにUI関連のモジュールがインポートされ、初期化されることになります。これらのモジュールが、処理の過程で@amazon-devices/react-native-keplerDeviceInfoなどのサポートされていないモジュールを初期化しようとして、上記のエラーが発生します。

将来のリリースでは、サポートされていないモジュールやライブラリの使用をビルドプロセス中に検出するツールを導入する予定です。それまでは、ヘッドレスJavaScriptタスク/サービスで安全に実行できるとVegaで判断されているモジュールのみを使用してください。

ヘッドレスJSタスクおよびサービスのビルド

ヘッドレスJSタスクおよびヘッドレスJSサービスを登録するには、以下の手順を実行する必要があります。

手順1: アプリのマニフェスト(manifest.toml)でコンポーネントをアドバタイズする

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

// manifest.toml

# Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All rights reserved.
#
# 専有/機密情報。 使用にあたってはライセンス条項が適用されます。
#
schema-version = 1

[package]
title = "ヘッドレスJSタスクおよびサービスのデモ"
version = "1.0.0"
id = "com.yourcompany.headlessjsdemo"

[components]

[[components.interactive]]
id = "com.yourcompany.headlessjsdemo.main"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
categories = ["com.amazon.category.main"]

# アプリにヘッドレスJSタスクがあることを示します。
[[components.task]]
id = "com.yourcompany.headlessjsdemo.task"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"

# アプリにヘッドレスJSサービスがあることを示します。
[[components.service]]
id = "com.yourcompany.headlessjsdemo.service"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"

マニフェストファイルの違い

manifest.tomlでのヘッドレスJSタスクまたはサービスの宣言は、それぞれに固有の目的によって異なります。たとえば、EPG同期タスクを宣言するドキュメントでは「runtime-module = /com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0」を使用するように指示されていますが、ヘッドレスJS再生のドキュメントでは「runtime-module = /com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0」が指定されています。

同様に、ヘッドレスJSタスク/サービスが実行されるプロセス(UIコンポーネントと同じプロセスか別のプロセスか)も、ユースケースによって異なります。たとえば、ヘッドレスJS再生はアプリのUIコンポーネントと同じプロセスで実行されますが、EPG同期タスクは、アプリのUIコンポーネントとは別のプロセスで実行するように宣言されます。

このため、さまざまなヘッドレスJSユースケース間で構成をコピーするのではなく、個々の機能のドキュメントを参照して、manifest.tomlファイルの正確なコンテンツを決定することが重要です。わずかな違いでも重大な影響が生じる可能性があるためです。

手順2: エントリポイントを登録する

タスクとサービスのエントリポイント(タスクではdoTask関数、サービスではonStartServiceおよびonStopService関数を使用)を登録するには、task.jsservice.jsという2つのファイルを個別に作成することをお勧めします。これらのファイルは、index.jsAppRegistry.registerComponentを使用してUIのエントリポイントを登録するファイル)と共に配置する必要があります。task.jsservice.jsを使用して、複数のヘッドレスJSタスク/サービスのエントリポイントを登録できます。

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

// task.js - ヘッドレスJSタスクのエントリポイントを登録します。

import { HeadlessEntryPointRegistry } from "@amazon-devices/headless-task-manager";

// SampleHeadlessTask.tsにdoTaskが実装されています。
import { doTaskSampleTask } from "./src/SampleHeadlessTask";

HeadlessEntryPointRegistry.registerHeadlessEntryPoint2("com.yourcompany.headlessjsdemo.task::doTask",
    () => doTaskSampleTask);

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

// service.js - ヘッドレスJSサービスのエントリポイントを登録します。

import {HeadlessEntryPointRegistry} from '@amazon-devices/headless-task-manager';

// SampleHeadlessService.tsにonStartSampleServiceとonStopSampleServieが実装されています。
import {onStartSampleService, onStopSampleService} from './src/SampleHeadlessService';

HeadlessEntryPointRegistry.registerHeadlessEntryPoint(
  'com.yourcompany.headlessjsdemo.service::onStartService',
  () => onStartSampleService,
);
HeadlessEntryPointRegistry.registerHeadlessEntryPoint(
  'com.yourcompany.headlessjsdemo.service::onStopService',
  () => onStopSampleService,
);

react-native build-keplerを使用してアプリをビルドする場合(package.jsonから引用した以下のスニペットを参照)、ヘッドレスJSタスク/サービスのHermesバンドル(task.hermes.bundleservice.hermes.bundle)をビルドするために必要な手順は、package.jsonと共に、task.jsservice.jsのいずれかまたは両方を用意することだけです。build-keplerは、これらのファイルを自動的に探し、タスクとサービスのHermesバイトコードバンドル(task.hermes.bundleservice.hermes.bundle)を生成して、アプリパッケージ(VPKG)に組み込みます。

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

// package.json

  "scripts": {
     .
    .
    "build:release": "react-native build-kepler --build-type Release",
    "build:debug": "react-native build-kepler --build-type Debug",
    "build:app": "npm-run-all build:release build:debug",
    .
  },

ただし、UIのHermesバイトコードバンドル(index.hermes.bundle)の生成とVPKGへのパッケージ化にreact-native build-keplerを使用しない場合は、ヘッドレスJSタスク/サービスについても同様に、それぞれのエントリポイントファイル(通常はtask.jsservice.js)を用意し、個別のバンドルファイルを生成して、VPKGに組み込む必要があります。

ヘッドレスJSタスクおよびサービスのデバッグ

ログ

ヘッドレスJSタスク/サービスのコードをデバッグするには、コンソールログ(console.log)を使用し、その出力をデバイスログで確認できます。

デバイス/シミュレーターシェルから次のコマンドを実行します。

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

loggingctl log -f | grep -i "<your package name>\|KeplerScript-Native\|KeplerScript-JavaScript"

ログが切り捨てられないようにするには、デバイス/シミュレーターシェルから次のコマンドを実行します。

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

loggingctl config --set-rate all 60000

<デバイスを再起動>

loggingctl config --set-rate all 60000 // 再実行

再ビルドなしでのJSバンドルのクイック更新

ヘッドレスJSタスクおよびサービスで、アプリを再ビルドして再インストールしなくても、更新されたJSバンドルを取得できるようになりました。

ヘッドレスJSタスク/サービスでは、再起動せずに変更を反映できるホットリロードや高速リフレッシュはサポートされません。代わりに、ヘッドレスJSタスク/サービスを再起動して、更新されたJSバンドルを取り込む必要があります。それでも、このプロセスはアプリを再ビルドして再インストールするよりもはるかに高速なため、開発ワークフローが大幅にスピードアップします。

この機能を使用するには、次の手順に従います。

  1. アプリ(UIとヘッドレスJSコンポーネント)をデバッグモードでビルドします。注: UIコンポーネントと同様に、行単位のデバッグはリリースビルドでは機能しません。
  2. アプリをインストールします。
  3. プロジェクトルートからMetroサーバーを実行します(npm start)。
  4. アプリとMetroで使用するように構成されているポート(通常は8081)に、デバイス(ターゲット)から開発コンピューター(ホスト)への逆方向のポートフォワーディングを設定します。この手順を実行しないと、アプリからMetroサーバーに接続することはできません。

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

  kepler device start-port-forwarding --device <デバイス名> -p 8081 --forward false
  1. アプリを起動します。これで、すべてのJSバンドル(UIとヘッドレスJSの両方)がMetroによって提供されるようになります。

行単位のデバッグ

ヘッドレスJSタスクおよびサービスでは、行単位のデバッグがサポートされます。現在の行単位のデバッグの実装には制限があり、Vega Studioに付属のDev Toolsでしか動作しません。また、複数のコンポーネント(UI、タスク、サービス)が同時に実行されている場合、Dev Toolsには最後に起動されたJSコンポーネントだけが表示されます。たとえば、Headless JS Media Playbackアプリでは、UIとヘッドレスJS再生サービスの両方が同時に実行されます。ヘッドレスJSサービスはUIの後に起動するため、これが最後に起動されたJSコンポーネントになります。したがって、Dev Toolsではservice.bundleが自動的にソースとして表示されます。Headless JS Media PlaybackアプリのUIコンポーネントを行単位でデバッグするには、まずkepler device launch-app -a <ヘッドレスJSコンポーネント名>を使用して手動でヘッドレスJSサービスを起動し、その後でUIコンポーネントを起動します。この順番で実行すれば、Dev Toolsにはindex.bundleがソースとして表示されます。

行単位のデバッグを使用するには、次の手順に従います。

  1. アプリ(UIとヘッドレスJSコンポーネント)をデバッグモードでビルドします。注: UIコンポーネントと同様に、行単位のデバッグはリリースビルドでは機能しません。
  2. アプリをインストールします。
  3. プロジェクトルートからMetroサーバーを実行します(npm start)。
  4. ポート8081(またはアプリとMetroに構成したポート)に、デバイス(ターゲット)から開発コンピューター(ホスト)への逆方向のポートフォワーディングを設定します。この手順を実行しないと、アプリからMetroサーバーに接続してDev Toolsとやり取りすることはできません。

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

  kepler device start-port-forwarding --device <デバイス名> -p 8081 --forward false
  1. デバッグするヘッドレスJSタスクまたはサービスを起動します。
    • 手動で起動するために、kepler device launch-app -a <ヘッドレスJSコンポーネント名>というコマンドを実行します。
    • UIコンポーネントを起動します。
  2. Vega Studioでコマンドパレットを開き、「Vega: Launch Dev Tools」を選択します。[Sources] タブに移動し、[React Native] を選択します。
  3. デバッグしようとしている目的のバンドル(index.bundle/service.bundle/task.bundle)が表示され、そのソースが読み込まれていることを確認します。注: Dev Toolsでは、ソースマップの読み込みの失敗に関するエラーが表示されますが、これは無視して構いません。
  4. ブレークポイントを設定するには、ターゲットのコードを検索し、ブレークポイントを追加する行番号をクリックします。ブレークポイントがヒットするのは、そのブレークポイントの設定後に実行されるコードに対してだけです。つまり、起動直後に実行されるコード(ヘッドレスJSタスクのdoTaskや、ヘッドレスJSサービスのonStartServiceなど)にブレークポイントを設定してもトリガーされません。このような場合のデバッグには、引き続きログを使用してください。
  5. Dev Toolsは自動的には更新されないため、アプリを起動し直す合間に、忘れずにDev Toolsインスタンスを閉じて再起動してください。

クラッシュレポート

ヘッドレスJSタスクまたはサービスから未処理のJSエラーが発生すると、アプリがクラッシュし、集約クラッシュレポート(ACR)が生成されます。この動作は現在、ヘッドレスJSタスク/サービスのリリースビルドにのみ適用されます。ヘッドレスJSタスク/サービスのデバッグビルドで未処理のJS例外を検出するには、引き続きデバイスログを使用してください。

ヘッドレスJSタスクおよびサービスに関する問題のトラブルシューティング

デバッグモードではヘッドレスJSタスク/サービスが動作するが、リリースモードでは起動しないかエラーが発生する

ログに次のようなエラーが表示される場合は、タスク/サービスバンドルが、ヘッドレスJSコンテキストでサポートされていないモジュールを初期化または使用しようとしています。

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

E Volta:[KeplerScript-JavaScript] Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'DeviceInfo' could not be found.Verify that a module by this name is registered in the native binary., js engine: hermes.

この状況に実際に当てはまるかどうかを特定するには、以下の手順を実行します。

手順1: react-native-bundle-visualizerを使用して、ヘッドレスJSタスク/サービスバンドルの構成を確認する

たとえば、サポートされていないモジュールをタスクバンドルが@amazon-devices/react-native-keplerから誤って取り込んでいる場合は、task.bundleの構成を比較します。

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

npx react-native-bundle-visualizer --entry-file task.js

シナリオ1: 正しいインポート

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

// task.js

// 正しいインポート
import { ComponentType  } from '@amazon-devices/react-native-kepler/Libraries/ComponentInstance/ComponentInstanceManager';

const componentInstance = {
    name: "TestComponent",
    type: ComponentType.TASK,
    id: "test-123"
};

// 列挙値を文字列に変換してログに記録します。
console.log(`ヘッドレスタスクのテスト: コンポーネントタイプ:${ComponentType[componentInstance.type]}`);

シナリオ2: 間違ったインポート

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

// task.js

// 間違ったインポート
import { ComponentType  } from '@amazon-devices/react-native-kepler';

const componentInstance = {
    name: "TestComponent",
    type: ComponentType.TASK,
    id: "test-123"
};

// 列挙値を文字列に変換してログに記録します。
console.log(`ヘッドレスタスクのテスト: コンポーネントタイプ:${ComponentType[componentInstance.type]}`);

シナリオ2のtask.bundleの構成を見ると明らかなように、このバンドルには@amazon-devices/react-native-keplerから多数のモジュールが取り込まれ、ヘッドレスJSコンテキストでサポートされていないモジュールも含まれています。サポートされていないモジュールが実際にタスク/サービスバンドルに含まれていることを確認したら、手順2に進んで、それらのモジュールが取り込まれた原因を特定します。

手順2: デバッグビルドのtask.bundle/service.bundleを手動で検査する

サービス/タスク(エラーが発生しているもの)のJSバンドル(Hermesバイトコードバンドルではありません)を開きます。これは通常、build/lib/rn-bundles/Debugにあります。ここでは、例としてtask.bundleを取り上げます。これは任意のエディターを使用して開くことができます。

たとえば、前の手順で示した間違ったインポートを含むtask.bundleがあり、次のエラーが発生しているとします。

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

E Volta:[KeplerScript-JavaScript] Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'DeviceInfo' could not be found.Verify that a module by this name is registered in the native binary., js engine: hermes.

この場合、DeviceInfoを入力として受け取るTurboModuleRegistry.getEnforcing呼び出しを検索します。

呼び出しが見つかったら、そのコードが含まれているモジュールを特定できます。

たとえば、上記のtask.bundleでは次のようになります。

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

  var NativeModule = TurboModuleRegistry.getEnforcing('DeviceInfo');
  var constants = null;
  var NativeDeviceInfo = {
    getConstants: function getConstants() {
      if (constants == null) {
        constants = NativeModule.getConstants();
      }
      return constants;
    },
    // amznmod_react:RCTDeviceEventEmitterの代わりにNativeDeviceInfoを使用してリスナーイベントを追加します。
    addListener: function addListener(eventName, handler) {
      NativeModule.addListener(eventName, handler);
    },
    getDimensionsV2: function getDimensionsV2(rootTag) {
      return NativeModule.getDimensionsV2(rootTag);
    },
    // amznmod_react:RCTDeviceEventEmitterの代わりにNativeDeviceInfoを使用してリスナーイベントを追加します。
    addListenerV2: function addListenerV2(rootTag, eventName, callback) {
      return NativeModule.addListenerV2(rootTag, eventName, callback);
    }
  };
  var _default = exports.default = NativeDeviceInfo;
},247,[19,3,5],"node_modules/@amazon-devices/react-native-kepler/Libraries/Utilities/NativeDeviceInfo.js");

このコードは@amazon-devices/react-native-kepler/Libraries/Utilities/NativeDeviceInfo.jsにあります。

次のステップは、何がこのモジュールに依存しているかを特定することです。そのためには、task.bundleでモジュールID247を検索します。

上記のtask.bundleには、モジュールID 247に依存するモジュールが2つあります。

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

},246,[3,12,13,4,5,247,20],"node_modules/@amazon-devices/react-native-kepler/Libraries/Utilities/Dimensions.js");

および

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

},564,[3,22,49,247,441],"node_modules/@amazon-devices/react-native-kepler/Libraries/Utilities/useVegaWindowDimensionsV2.js");

これらのいずれかに着目し、どこで使用されているかを検索します。これを数回繰り返すと、node_modules/@amazon-devices/react-native-kepler/index.jsというモジュールが表示されます。

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

},1,[2,471,481,484,485,378,20,487,395,490,491,493,494,498,500,28,478,472,404,271,324,408,457,503,288,505,507,418,482,483,421,511,512,513,232,514,515,516,521,171,523,526,375,528,222,199,531,534,444,535,537,455,188,246,337,45,267,334,538,540,364,365,436,82,174,152,151,542,544,245,546,548,550,551,553,259,31,555,556,19,35,446,558,559,563,564,565,568,569,98,570,572,573,4,575,182,21,17,207,204,274,441,296],"node_modules/@amazon-devices/react-native-kepler/index.js");

これはtask.jsからインポートされています。

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

},0,[1],"task.js");

将来のリリースでは、問題となるモジュールの検出をツールによって自動化する予定です。このツールをビルドステップ自体に統合して、サポートされていないモジュールとその取り込み元について警告したり、場合によってはビルドエラーにしたりすることが検討されています。

手順3: Amazonの担当者に連絡する

サポートされていないモジュールを検出する適切なツールがないために行き詰まった場合は、Amazonが問題の診断をお手伝いします。Amazonの担当者にお問い合わせください。

ヘッドレスJSタスクおよびサービスの現在の利用状況

ヘッドレスJSタスクは、次のFire TV統合で利用されています。

ヘッドレスJSサービスは、次のユースケースで利用されています。


Last updated: 2025年9月30日