Vega无头任务和服务
JavaScript (JS) 可以通过两种方式在没有用户界面 (UI) 的情况下在后台运行:无头任务和无头服务。任务是独立运行的一次性操作,而服务允许持续交互。例如,任务可能会在不打开应用的情况下获取电视频道数据并更新节目指南。服务处理媒体播放等功能 - 用户界面可以向服务发送命令(例如播放或暂停),同时它可以在单独的运行时管理媒体串流和处理。这种方法通过将繁重的处理移至后台来保持主界面的响应。
用于无头JS任务和服务的JS运行时
无头JS任务和服务在后台使用Vega应用组件。应用组件在顶部添加了辅助JS运行时(由Hermes提供支持),以启用JS代码执行并可让您侦听代码中的生命周期事件。无头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”导入模块。只有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编写代码时直接导入@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,从而导致错误。
虽然我们计划添加在构建期间检测不支持的模块的工具,但目前,请确保您仅使用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"
清单文件中的变体
不同的无头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播放的运行进程与您的用户界面相同
- EPG同步任务在单独的进程中运行
请务必查看您正在实现的每项功能的具体文档。不要在不同的无头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-vega构建应用时,该过程会自动处理无头JS Bundle。将这些文件放在您的项目根目录中:
- 用于无头任务的task.js
- 用于无头服务的service.js
构建系统会找到这些文件并创建:
- 用于任务的task.hermes.bundle
- 用于服务的service.hermes.bundle
这些捆绑包会自动包含在您的应用程序包 (VPKG) 中。
.js。如果它们被命名为task.ts或service.ts,则rreact-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字节码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)设置从您的设备(target)到开发计算机(host)的反向端口转发。如果不执行此步骤,该应用将无法连接到Metro服务器。vega device start-port-forwarding --device <设备名称> -p 8081 --forward false - 启动应用。您应该看到所有JS Bundle(包括用户界面和无头JS)现在都由Metro提供服务。
逐行调试
您可以逐行调试无头JS任务和服务,但有一些限制:
- 仅适用于Vega Studio的开发工具
- 开发工具仅显示最近推出的JS组件
例如,在无头JS媒体播放应用中:
- 用户界面和服务一起运行
- 该服务最后启动,因此开发工具显示的是service.bundle
- 要改为调试用户界面,您必须:
- 首先使用
vega device launch-app -a <无头JS组件名称>启动无头服务 - 然后启动用户界面组件。
- 开发工具现在显示index.bundle
- 首先使用
按照以下步骤使用逐行调试。
- 在调试模式下构建应用(用户界面和无头JS组件)。注意: 与用户界面组件一样,逐行调试不适用于发布构建。
- 安装应用。
- 从项目根目录运行Metro服务器 (
npm start)。 - 为端口8081(或为您的应用和Metro配置的端口)设置从您的设备(
target)到开发计算机(host)的反向端口转发。如果不执行此步骤,该应用将不能连接到Metro服务器并与开发工具进行交互。vega device start-port-forwarding --device <设备名称> -p 8081 --forward false - 启动您要调试的无头JS任务或服务。
- 使用以下命令手动启动:
vega 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年12月3日

