Vegaヘッドレスタスクとヘッドレスサービス
JavaScript(JS)は、ヘッドレスタスクとヘッドレスサービスという2つの方法により、ユーザーインターフェイス(UI)を表示せずにバックグラウンドで実行することができます。タスクは独立して動作する1回限りの操作であるのに対し、サービスは継続的な対話を可能にします。たとえば、タスクでは、アプリを開かずにTVチャンネルデータを取得して番組ガイドを更新できます。サービスはメディア再生などの機能を処理します。UIはサービスにコマンド(再生や一時停止など)を送信でき、サービスはメディアのストリーミングと処理を別のランタイムで管理します。このアプローチにより、負荷の高い処理をバックグラウンドに移動して、メインインターフェイスの応答性を維持することができます。
ヘッドレスJSタスクおよびサービスのJSランタイム
ヘッドレスJSタスクとヘッドレスJSサービスは、バックグラウンドでVegaアプリコンポーネントを利用します。アプリコンポーネントは、JSコードの実行を可能にするために最上位にセカンダリJSランタイム(Hermesで動作)を追加し、コードからライフサイクルイベントをリッスンできるようにします。ヘッドレスJSタスク/サービスの各インスタンスには、それぞれ独自のJavaScriptランタイムインスタンスが保持されます。
ヘッドレスJSコンテキストでサポートされるモジュール
ヘッドレスランタイムは、メモリフットプリントを小さく保つために、ユーザーインターフェイスで利用できる機能を簡易化したものです。次の表に示すモジュールのみがサポートされます。
| モジュール | 注記 |
|---|---|
| ログ | 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のコードを記述しているときに、ヘッドレスエクスポートではなく@amazon-devices/react-native-w3cmediaを直接インポートすると、このエラーが発生します。
import { VideoPlayer } from '@amazon-devices/react-native-w3cmedia/dist/headless'; // 正しい
import { VideoPlayer } from '@amazon-devices/react-native-w3cmedia'; // 間違い
@amazon-devices/react-native-w3cmediaのヘッドレスエクスポートには、ヘッドレスJSで安全に動作するモジュールのみが含まれています。このエクスポートをスキップすると、コードでは、@amazon-devices/react-native-keplerのDeviceInfoなど、サポートされていない機能に依存するUI関連のモジュールの読み込みが試みられ、エラーが発生することになります。
今後、サポートされていないモジュールをビルド時に検出するツールの追加を予定していますが、現時点では、VegaでヘッドレスJavaScript用に承認されているモジュールのみを使用するようにしてください。
ヘッドレス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"
マニフェストファイルの違い
さまざまなヘッドレスJSタスク/サービスに応じて、manifest.tomlファイルには異なる設定が必要になります。以下に例を示します。
- 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と同じプロセスで実行されます。
- EPG同期タスクは別のプロセスで実行されます。
実装する各機能の固有のドキュメントを必ず確認してください。わずかな違いが大きい問題につながることがあるため、異なるヘッドレスJS機能間で設定をコピーしないでください。
手順2: エントリポイントを登録する
タスクとサービスのエントリポイント(タスクではdoTask関数、サービスではonStartServiceおよびonStopService関数を使用)を登録するには、task.jsとservice.jsという2つのファイルを個別に作成することをお勧めします。これらのファイルは、index.js(AppRegistry.registerComponentを使用してUIのエントリポイントを登録するファイル)と一緒に配置します。task.jsファイルとservice.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-vegaを使用してアプリをビルドする場合は、このプロセスによってヘッドレスJSバンドルが自動的に処理されます。次のファイルをプロジェクトのルートに配置してください。
- ヘッドレスタスクのtask.js
- ヘッドレスサービスのservice.js
ビルドシステムは、これらのファイルを検出して以下を作成します。
- タスクのtask.hermes.bundle
- サービスのservice.hermes.bundle
これらのバンドルが自動的にアプリパッケージ(VPKG)に含められます。
.jsという拡張子にする必要があります。これらの名前をtask.tsやservice.tsにすると、react-native build-vegaコマンドでファイルが検出されず、アプリのVPKGにtask.hermes.bundleやservice.hermes.bundleが取り込まれなくなります。その結果、ANR(アプリ応答なし)クラッシュやその他のランタイムエラーが発生する可能性があります。
// package.json
"scripts": {
.
.
"build:release": "react-native build-vega --build-type Release",
"build:debug": "react-native build-vega --build-type Debug",
"build:app": "npm-run-all build:release build:debug",
.
},
react-native build-vegaを使用しない場合は、次の手順を手動で実行する必要があります。
- エントリポイントファイル(
task.jsとservice.js)からHermesバイトコードバンドルを生成します。 - これらのバンドルを手動でアプリパッケージ(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バンドルを取り込む必要があります。
この機能を使用するには、次の手順に従います。
- アプリ(UIとヘッドレスJSコンポーネント)をデバッグモードでビルドします。注: UIコンポーネントと同様に、行単位のデバッグはリリースビルドでは機能しません。
- アプリをインストールします。
- プロジェクトルートからMetroサーバーを実行します(
npm start)。 - アプリとMetroで使用するように構成されているポート(通常は
8081)に、デバイス(target)から開発コンピューター(host)への逆方向のポートフォワーディングを設定します。この手順を実行しないと、アプリからMetroサーバーに接続することはできません。vega device start-port-forwarding --device <デバイス名> -p 8081 --forward false - アプリを起動します。これで、すべてのJSバンドル(UIとヘッドレスJSの両方)がMetroによって提供されるようになります。
行単位のデバッグ
ヘッドレスJSタスク/サービスは行単位でデバッグできますが、いくつかの制限があります。
- Vega StudioのDev Toolsでのみ機能します。
- Dev Toolsには最後に起動されたJSコンポーネントだけが表示されます。
たとえば、ヘッドレスJSメディア再生アプリでは次のようになります。
- UIとサービスの両方が同時に実行されます。
- サービスが最後に起動するため、Dev Toolsにはservice.bundleが表示されます。
- 代わりにUIをデバッグするには、次の手順を実行する必要があります。
vega device launch-app -a <ヘッドレスJSコンポーネント名>を使用して、最初にヘッドレスサービスを起動します。- 次にUIコンポーネントを起動します。
- これでDev Toolsにindex.bundleが表示されます。
行単位のデバッグを使用するには、次の手順に従います。
- アプリ(UIとヘッドレスJSコンポーネント)をデバッグモードでビルドします。注: UIコンポーネントと同様に、行単位のデバッグはリリースビルドでは機能しません。
- アプリをインストールします。
- プロジェクトルートからMetroサーバーを実行します(
npm start)。 - ポート8081(またはアプリとMetroに構成したポート)に、デバイス(
target)から開発コンピューター(host)への逆方向のポートフォワーディングを設定します。この手順を実行しないと、アプリからMetroサーバーに接続してDev Toolsとやり取りすることはできません。vega device start-port-forwarding --device <デバイス名> -p 8081 --forward false - デバッグするヘッドレスJSタスクまたはサービスを起動します。
- 手動で起動するために、
vega device launch-app -a <ヘッドレスJSコンポーネント名>というコマンドを実行します。 - UIコンポーネントを起動します。
- 手動で起動するために、
- Vega Studioでコマンドパレットを開き、「Vega: Launch Dev Tools」を選択します。[Sources] タブに移動し、[React Native] を選択します。
- デバッグしようとしている目的のバンドル(
index.bundle/service.bundle/task.bundle)が表示され、そのソースが読み込まれていることを確認します。注: Dev Toolsでは、ソースマップの読み込みの失敗に関するエラーが表示されますが、これは無視して構いません。 - ブレークポイントを設定するには、ターゲットのコードを検索し、ブレークポイントを追加する行番号をクリックします。ブレークポイントがヒットするのは、そのブレークポイントの設定後に実行されるコードに対してだけです。つまり、起動直後に実行されるコード(ヘッドレスJSタスクの
doTaskや、ヘッドレスJSサービスのonStartServiceなど)にブレークポイントを設定してもトリガーされません。このような場合のデバッグには、引き続きログを使用してください。 - 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統合で利用されています。
- 電子番組表
- アプリのインストール時またはアップデート時の処理のスケジュール: EPGの更新、アプリマニフェストのタスク
ヘッドレスJSサービスは、次のユースケースで利用されています。
Last updated: 2025年12月3日

