Vega无头任务和服务
无头JavaScript任务和服务允许以独立于用户界面 (UI) 的方式,在后台执行JavaScript代码。这意味着代码无需用户界面即可运行,因此名为“无头”。 无头JavaScript任务和服务都适用于长时间运行的任务。区别在于它们的预期用途: 无头JavaScript任务专为触发后便不用交互的任务而设计,而无头JavaScript服务则专为在运行时与之进行交互而设计。例如,您可以利用无头JavaScript任务从后端获取频道及其时间安排信息,然后将其发布到Fire TV的电子节目指南 (EPG),而无需启动应用的用户界面。在这种情况下,预计不会与无头JavaScript任务进行交互。另一方面,您可以使用无头JavaScript服务进行媒体播放,将主要的JavaScript运行时腾出来用于用户界面,并利用次要JavaScript运行时下载和解析HLS清单,以使用适用于媒体的W3C API来馈送到Vega的媒体管道。在这种情况下,用户界面与无头JavaScript服务进行交互以控制媒体(例如,播放、暂停等)。
用于无头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”导入模块。只有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 |
使用不受支持的模块
使用上面未列出的任何模块或库都会导致运行时错误,如下例所示。此错误指出DeviceInfo模块在无头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.
您可能没有直接导入违规模块,但仍然会看到这个错误。如果您导入其他一些可传递性导入违规模块的模块或库,则可能会发生这种情况。如果您尝试使用尚不受支持的库,或者您导入模块的方式与上述指定方式不同,则会发生这种情况。
例如,在专用于在无头JS上下文中运行的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上下文中安全执行的模块。如果在导入时未使用无头,则无头JS任务/服务Bundle最终会导入和初始化与用户界面相关的模块,然后这些模块传递性地尝试初始化不受支持的模块,例如来自@amazon-devices/react-native-kepler的DeviceInfo,从而导致上述错误。
未来的版本将引入工具,这些工具可以在构建过程中检测不受支持的模块或库的使用情况。在此之前,请确保您仅使用Vega认为安全的模块和库来执行无头JavaScript任务和服务。
构建无头JS任务和服务
要注册您的无头JS任务和服务,您需要执行以下操作:
步骤1: 在应用的清单 (manifest.toml) 中公开您的组件
// manifest.toml
* 版权所有 (c) 2024 Amazon.com, Inc.或其关联公司。 保留所有权利。
#
* 专有/机密信息。 相关使用受许可条款的约束。
#
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任务或服务的运行进程(在与用户界面组件相同的进程中运行或单独运行)是特定于用例的。例如,无头JS播放与应用的用户界面组件在同一进程中运行,而EPG同步任务被声明为在与应用的界面组件不同的进程中运行。
因此,查阅各个功能的文档以确定manifest.toml文件的确切内容至关重要,而不是在不同的无头JS用例之间复制配置,因为即使是细微的差异也可能产生关键影响。
步骤2: 注册入口点
要注册任务(使用doTask函数)和服务(使用onStartService和onStopService函数)的入口点,我们建议您创建两个单独的文件:task.js和service.js。这些文件应放在index.js旁边,后者使用AppRegistry.registerComponent注册用户界面的入口点。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-kepler来构建您的应用(参见下面package.json的片段),那么要为无头JS任务 (task.hermes.bundle) 和服务 (service.hermes.bundle) 构建hermes Bundle,您需要做的就是将task.js和/或service.js放在package.json旁边,build-kepler会自动查找它们并为任务 (task.hermes.bundle) 和服务 (service.hermes.bundle) 生成Hermes字节码Bundle,然后把它们置于应用程序包 (VPKG) 中。
.js。如果它们被命名为task.ts或service.ts,则react-native build-kepler命令将无法提取它们,从而导致应用VPKG中缺少task.hermes.bundle或service.hermes.bundle。这可能导致ANR(应用无响应)崩溃或其他运行时错误。
// 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",
.
},
但是,如果您不使用react-native build-kepler来生成用户界面Hermes字节码Bundle (index.hermes.bundle) 并将其打包到VPKG中,那么您必须使用同样的方法来获取无头JS任务(通常是task.js)和服务(通常是service.js)的入口点文件,然后为它们生成单独的Bundle并将它们置于VPKG中。
调试无头JS任务和服务
日志记录
要在无头JS任务/服务中调试代码,您可以使用控制台日志 (console.log) 并在设备日志中查看它们。
从您的设备/模拟器shell运行以下命令:
loggingctl log -f | grep -i "<程序包名称>\|KeplerScript-Native\|KeplerScript-JavaScript"
要限制对日志的修剪,请在设备/模拟器shell中使用以下命令:
loggingctl config --set-rate all 60000
<重启设备>
loggingctl config --set-rate all 60000 // 再次运行此命令一次
无需重新构建即可快速更新JS Bundle
无头JS任务和服务现在可以获取更新后的JS Bundle,而无需重新构建和重新安装应用。
无头JS任务和服务不支持热重载或快速刷新,而通过这两个功能,无需重新启动即可显示更改。因此必须重新启动无头JS任务和服务才能拉取更新后的JS Bundle。但是,此过程仍然比需要重建和重新安装应用时快得多,并且将大幅加快您的开发工作流程。
要使用此特性,请按照以下步骤操作。
- 在调试模式下构建应用(用户界面和无头JS组件)。注意: 与用户界面组件一样,逐行调试不适用于发布构建。
- 安装应用。
- 从项目根目录运行Metro服务器 (
npm start)。 - 为应用和Metro经过配置而要使用的端口(通常为
8081)设置从您的设备(目标)到开发计算机(主机)的反向端口转发。如果不执行此步骤,应用将无法连接到Metro服务器。kepler device start-port-forwarding --device <设备名称> -p 8081 --forward false - 启动应用。您应该看到所有JS Bundle(包括用户界面和无头JS)现在都由Metro提供服务。
逐行调试
无头JS任务和服务支持逐行调试。当前的逐行调试实现存在一种限制:它仅适用于Vega Studio附带的开发工具,而在多个组件(用户界面、任务、服务)同时运行时,开发工具仅显示最近启动的JS组件。例如,在无头JS媒体播放应用中,用户界面和无头JS播放服务一起运行。由于无头JS服务在用户界面之后启动,因此它成为最后启动的JS组件。因此,开发工具会自动将service.bundle显示为源。如果您想在无头JS媒体播放应用中逐行调试用户界面组件,请先使用kepler device launch-app -a <无头JS组件名称>手动启动无头JS服务,然后启动用户界面组件。这个序列将使开发工具改为将index.bundle显示为源。
按照以下步骤使用逐行调试。
- 在调试模式下构建应用(用户界面和无头JS组件)。注意: 与用户界面组件一样,逐行调试不适用于发布构建。
- 安装应用。
- 从项目根目录运行Metro服务器 (
npm start)。 - 为端口8081(或为您的应用和Metro配置的端口)设置从您的设备(目标)到开发计算机(主机)的反向端口转发。如果不执行此步骤,该应用将无法连接到Metro服务器并与开发工具进行交互。
kepler device start-port-forwarding --device <设备名称> -p 8081 --forward false - 启动您要调试的无头JS任务或服务。
- 使用以下命令手动启动:
kepler device launch-app -a <无头JS组件名称>。 - 启动用户界面组件。
- 使用以下命令手动启动:
- 在Vega Studio中,打开命令面板并选择“Vega: Launch Dev Tools”。导航到“Sources”(源)选项卡并选择“React Native”。
- 验证列出的Bundle (
index.bundle/service.bundle/task.bundle) 是否是您要调试的Bundle,以及其源是否已加载。注意: 开发工具将显示有关无法加载源映射的错误 - 可以忽略该错误。 - 要设置断点,请搜索目标代码并单击要添加断点的行号。请注意,只有在设置断点后执行的代码才会命中断点。这意味着启动时立即执行的代码(例如无头JS任务的
doTask或服务的onStartService)中的断点不会被触发。对于这些情况,请继续使用日志进行调试。 - 请记住关闭开发工具实例并在两次应用启动之间重新启动它,因为开发工具不会自动刷新。

崩溃报告
来自无头JS任务或服务的未处理JS错误将导致应用崩溃并生成聚合崩溃报告 (ACR)。目前,此行为仅适用于无头JS任务和服务的发布构建。对于无头JS任务和服务的调试构建,请继续使用设备日志来检测任何未处理的JS异常。
无头JS任务和服务问题故障排除
我的无头JS任务/服务在调试模式下运行,但在发布模式下无法启动或出错
检查日志,如果您看到如下错误,则说明您的任务/服务Bundle正在尝试初始化或使用无头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任务/服务包的构成
例如,比较task.bundle意外从@amazon-devices/react-native-kepler中提取了不受支持的模块时的构成。
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的组成中可以看出,它清楚地表明该Bundle中包含了来自@amazon-devices/react-native-kepler的许多模块,甚至包含那些在无头JS上下文中不支持的模块。确认任务/服务Bundle确实包含不受支持的模块后,请继续执行步骤2以确定是什么引入了这些模块。
步骤2: 手动检查调试构建的task.bundle/service.bundle
打开服务/任务(以引发错误者为准)的JS Bundle(不是Hermes字节码Bundle)。您通常可以在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使用NativeDeviceInfo而非RCTDeviceEventEmitter来添加侦听器事件
addListener: function addListener(eventName, handler) {
NativeModule.addListener(eventName, handler);
},
getDimensionsV2: function getDimensionsV2(rootTag) {
return NativeModule.getDimensionsV2(rootTag);
},
// amznmod_react使用NativeDeviceInfo而非RCTDeviceEventEmitter来添加侦听器事件
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中搜索模块ID 247。
在上面的task.bundle中,有两个模块依赖于模块ID 247:
},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: 联系您的亚马逊联系人
如果您由于缺乏合适的工具来检测不受支持的模块而陷入困境,亚马逊将非常愿意协助您诊断问题。您同样可以联系自己的亚马逊联系人。
无头JS任务和服务的当前应用
以下Fire TV集成采用了无头JS任务:
无头JS服务用于以下用例:
Last updated: 2025年10月21日

