JS 应用开发与发布
基于Hello World 新建 JS 应用
本章用于说明如何基于 Hello World 示例新建 JS 应用,并完成环境准备、工程创建、图形工具配置、签名配置、编译打包、安装、卸载和预置流程。HelloWorld 示例只包含基础页面显示,组件和接口能力可在“工程代码的文件结构与代码走读”章节继续查阅。
IDE
目前支持OpenHarmony JS应用开发的IDE为DevEco Studio 5.0 Release。
- 5.0版本,5.0版本支持API 10。
- 不推荐:2.1版本为早期版本,支持API 5。
DevEco Studio 5.0 Release
DevEco Studio For OpenHarmony(获取工具请单击链接下载,以下简称DevEco Studio)是基于IntelliJ IDEA Community开源版本打造,用作开发穿戴JS应用。
说明: 当前产品使用的IDE版本为DevEco Studio 5.0 Release。
haptobin_tool.jar工具使用
背景:商用应用建议上架release版本安装包,本工具支持将release hap转换为bin。
工具介绍:将IDE编译出的release的hap转为bin的工具。
获取路径:解压sdk发布包中的jsapp.zip,在“jsapp\js_sample\helper”路径下的“fastjson-1.2.83.jar”、“haptobin_tool.jar”。
使用方法:
- 将“fastjson-1.2.83.jar”、“haptobin_tool.jar”放在同一目录下。
-
执行命令“java -jar "xxx/haptobin_tool.jar" --hap-path "xxx/xxx.hap" --bin-path "xxx/xxx.bin"”。
--hap-path:hap包所在路径。
--bin-path:所生成bin包所在路径。
说明: 当前章节所指hap包是DevEco Studio使用release模式编译的“*.hap”产物。如果使用IDE的debug模式,无需使用“haptobin_tool.jar”。
工程创建
使用 DevEco Studio 5.0 Release 创建工程
-
选择“[Lite]Empty Ability(JS)”工程。

-
配置项目,包括包名、工程路径、项目类型等。

-
在Hello World程序中打开Previewer预览器显示预览界面。

说明: 页面视图逻辑主要由hml、css、js组成,详情请参考“文件组织”。
图形工具使用
使用 DevEco Studio 5.0 Release 配置图形工具
图片压缩工具详见《图形工具使用指南》。将图片资源解码成bin文件后打包到应用包中可以优化图片性能,使用步骤如下:
-
设置图像转换工具环境变量,本示例中设置如下,路径变量名为ImageTool:

-
进入DevEco Studio 5.0 Release版本新建工程entry目录,使用以下脚本替换替换“hvigorfile.ts”:
import { legacyHapTasks ,OhosPluginId ,OhosHapContext} from '@ohos/hvigor-ohos-plugin'; import { hvigor, HvigorNode, HvigorPlugin} from '@ohos/hvigor'; import {spawn,exec,execSync} from 'child_process' import * as fs from 'fs'; import * as path from 'path'; import { PythonShell } from 'python-shell'; function containsPng(filename: string): boolean { return filename.toLowerCase().includes('png') || filename.toLowerCase().includes('bmp') || filename.toLowerCase().includes('jpg'); } function copyDirectorySync(src: string, dest: string) { if (!fs.existsSync(dest)) { fs.mkdirSync(dest, { recursive: true }); } const entries = fs.readdirSync(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name); if (entry.isDirectory()) { copyDirectorySync(srcPath, destPath); } else { if (containsPng(srcPath)) { fs.copyFileSync(srcPath, destPath); } } } } function createDirSync(dir: string): void { if (!fs.existsSync(dir)) { createDirSync(path.dirname(dir)); fs.mkdirSync(dir); } } function delay(milliseconds: number) { return new Promise<void>(resolve => { setTimeout(() => { resolve(); }, milliseconds); }); } function deletePngBinFiles(folderPath: string): void { fs.readdirSync(folderPath).forEach((file) => { const filePath = path.join(folderPath, file); if (fs.lstatSync(filePath).isFile() && file.endsWith('.png.bin')) { console.log(filePath); fs.unlinkSync(filePath); } else if (fs.lstatSync(filePath).isDirectory()) { deletePngBinFiles(filePath); } }); } async function executeCommand(dirPath: string): Promise<void> { return new Promise((resolve, reject) => { const myVar = process.env.ImageTool; let options = { cwd: myVar }; console.log(myVar); const result = execSync('python ' + myVar + "\\images_tool.py -p file -c config.xml -i "+dirPath+" -o "+dirPath, options); console.log(result.toString()); }); } export function customPlugin(): HvigorPlugin { return { pluginId: 'customPlugin', context() { return { data: 'customPlugin xxx' }; }, async apply(currentNode: HvigorNode): Promise<void> { currentNode.registerTask({ // 任务名称 name: `default@makepicbin`, // 任务执行逻辑主体函数 async run() { const hapContext = currentNode.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosHapContext; hapContext?.targets((target: default) => { const outputPath = target.getBuildTargetOutputPath(); console.log(outputPath); const appName = 'MainAbility'; const srcDir = `${target.projectPath}/entry/src/main/js/` + appName; const destDir = `${target.projectPath}/entry/build/default/intermediates/lite_source/default/assets/js/` + appName; const destDir2 = `${target.projectPath}/entry/build/default/intermediates/loader_out_lite/default/js/` + appName; const testDir = `${target.projectPath}/test`; try { createDirSync(destDir); console.log('目录创建成功'); createDirSync(destDir2); console.log('目录创建成功'); copyDirectorySync(srcDir, destDir); console.log('文件夹拷贝完成'); copyDirectorySync(srcDir, destDir2); console.log('文件夹拷贝完成'); console.log(`${target.projectPath}/entry/build/default/intermediates`); executeCommand(`${target.projectPath}/entry/build/default/intermediates`); console.log('Command executed successfully11'); deletePngBinFiles(`${target.projectPath}/entry/build/default/intermediates`) } catch (error) { console.error('创建过程中出错:', error, destDir); } }); }, // 配置前置任务依赖 dependencies: [ `default@LegacyCompileLiteJS`, `default@LegacyCompileArkTS`, `default@LegacyGenerateLoaderJson`, `default@CacheNativeLibs`], // 配置任务的后置任务依赖 postDependencies: [ `default@LegacyGenerateLiteCode`, `default@LegacyBuildJS`, `default@LegacyPackageHap`, `default@SignHap`, `assembleHap` ] }); } }; } export default { system: legacyHapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[customPlugin()] /* Custom plugin to extend the functionality of Hvigor. */ }- process.env.ImageTool:1设置的图片转换工具所在目录。
说明: 图形工具源码及安装请参考《图形工具使用指南》。
签名介绍
说明: 应用签名密钥由产品厂商自行管理,解决方案不指定具体密钥。非商用调试场景,可采用调试模式关闭验签,或使用OpenHarmony社区签名。
商用产品默认开启验签,当使用厂商对应公钥和证书后,可验证所安装应用的完整性和真实性。
OpenHarmony 社区签名方法可参考 OpenHarmony hapsigntool 使用说明。
DevEco Studio自动签名如下图所示,调试阶段可使用默认配置,即OH社区签名。

调试模式下关闭验签方法如下:
-
方法一:串口调试命令
AT+OHOS=OHOSFWK_BM_SET,disable
-
方法二:使用调试接口
使用SetSignMode()接口,或修改“/src/ohos/foundation/bundlemanager/bundle_framework_lite/services/bundlemgr_lite/tools/signmode/sign_mode.cpp”中isSignMode_的值为false。
编译打包
按照下图中①标记的步骤构建应用包,并将在下图中②位置生成对应的应用包。

编译 Hello World JS 应用时,建议按以下顺序检查:
-
使用 DevEco Studio 打开 samples/js_samples/helloworld 工程。
-
确认
entry/src/main/config.json中bundleName、deviceType、Ability 名称和pages路径与当前工程一致。 -
使用 DevEco Studio 执行构建,生成 HAP 应用包。
-
如果需要安装 release 包或商用包,使用
haptobin_tool.jar将 HAP 转换为 BIN;如果是 IDE debug 模式,可按调试流程直接使用 HAP 产物。
应用安装
-
将“编译打包”中生成的应用包文件上传到板端任意位置,如“/user/jsapp/sample.bin”。
说明: 文件上传方式请参考《DebugKits 工具使用指南》“数据上传与下载”章节。
-
安装应用包:
-
如果调试非签名JSApp时,可以在串口上通过如下命令执行关闭验签。对已签名应用跳过此步骤。
AT+OHOS=OHOSFWK_BM_SET,disable
-
在串口上执行应用安装,允许覆盖安装:
AT+OHOS=OHOSFWK_BM_INSTALL,/user/jsapp/sample.bin
-
如果覆盖安装时,在命令末尾添加参数“rmdata”,则会删除应用沙箱历史数据:
AT+OHOS=OHOSFWK_BM_INSTALL,/user/jsapp/sample.bin,rmdata
-
应用卸载
在串口上执行卸载:AT+OHOS=OHOSFWK_BM_UNINSTALL,XXX
说明: XXX为需要卸载应用的包名,例如:AT+OHOS=OHOSFWK_BM_UNINSTALL,com.example.test。更多OHOS命令及参数,请见“/src/middleware/utils/at/at_ohos_cmd/at/at_ohos.c”中的g_at_ohos_cmd中对应OHOS命令及参数定义。
预置应用
- 请参见《文件系统使用指南》“YAFFS 镜像开发指导”,制作文件系统镜像,将需要预置的应用放到“/user/app/system/ace/vendor/”目录下。
- 烧录镜像并重启设备,预置应用将会在设备启动时自动安装。
说明:
- 卸载预置应用 当手动执行预置应用的卸载后,系统会在“/user/app/user/ace/etc/”目录下生成“uninstalled_delbundle.json”文件。这确保了在设备下次重启时,手动卸载的应用不会被自动重新安装。
- 恢复预置应用 如果希望恢复之前卸载的预置应用,只需删除“/user/app/user/ace/etc/”目录下的“uninstalled_delbundle.json”文件。在删除该文件后,下次设备重启时预置应用将会重新安装。
运行验收
安装完成后,按以下项目确认 Hello World JS 应用已跑通:
- 应用管理命令返回安装成功。
- 设备应用列表中出现 HelloWorld JS 应用。
- 点击应用后进入首页,页面显示 HelloWorld 或多语言资源中配置的文本。
- 切换系统语言后,页面文本可读取
i18n目录下对应语言资源。
如果应用未显示在列表中,优先检查安装包是否上传到正确路径、签名模式是否与安装包匹配,以及 config.json 中的 bundleName 是否与卸载或覆盖安装操作一致。
OH应用市场
穿戴设备配套的手机管理软件,在接入应用市场(https://www.openwearplay.com)后,可以安装管理OpenHarmony穿戴应用市场中的JsApp;应用安全安装需要使用根证书进行证书链的完整性校验。
穿戴设备端需上传证书链的根证书文件以及根证书文件的哈希列表、哈希列表签名文件到设备的“/user/app/user/certcfg”目录下,如下图所示:

- ohos_trusted_root_cert.bin:OpenHarmony社区根证书文件。
- app_market_root_cert.pem:穿戴应用市场根证书文件。
- root_cert_hash_list.bin:包含根证书文件名及根证书内容SHA256值的哈希列表文件。
- hash_list_sign.bin:使用穿戴市场私钥对哈希列表进行签名的签名文件,验签的公钥已预置在镜像内。
须知: 根证书可以只传一个,也支持可扩展,如上是同时支持OpenHarmony社区签名的应用也支持穿戴应用市场签名的应用;如果不推上述文件,开启应用验签的情况下,设备只能安装OpenHarmony社区签名的应用。
