跳转至

JS 应用入门与工程结构

本文档以 samples/js_samples/helloworld 为例,说明 HiDiTing JS 应用的基本概念、开发环境、工程创建、编译安装、工程代码结构、组件、接口、OH应用市场和类型定义,帮助开发者基于示例扩展自己的 JS demo。


OpenHarmony JS应用知识背景

JS 应用是基于 OpenHarmony Ability 模型运行的轻量应用形态,主要使用 HML、CSS 和 JavaScript 描述页面结构、页面样式和交互逻辑。对于 HiDiTing 穿戴设备,JS 应用通常以 HAP 包或转换后的 BIN 包形式交付,通过系统应用管理能力安装、卸载或预置到设备中。

开发者在实现 JS 应用时,需要关注三类内容:一是工程与构建配置,包括包名、设备类型、Ability 入口和页面路由;二是页面源码,包括 hmlcssjsapp.js 和多语言资源;三是运行环境提供的组件与接口,例如通用组件、容器组件、基础组件、页面路由、日志、定时器、网络和蓝牙 BLE 等能力。

本文后续章节按实际开发流程组织:先通过仓内已有 BIN 包快速跑通 Hello World JS Demo,再结合 HelloWorld Demo 走读工程文件;随后完成工具和环境准备、工程创建、编译打包、安装、卸载和预置。由于 HelloWorld 示例只展示最小页面能力,工程代码走读章节还会补充可用组件和接口参考,最后说明 OH应用市场和类型定义。

快速跑通 Hello World JS Demo

本章用于直接安装仓内已生成的 Hello World JS Demo BIN 包,帮助开发者在不重新创建工程的情况下验证 JS 应用安装和运行链路。示例应用包位于:

src/application/wearable/res/js/IDE5.0/com.vendor.helloworld.bin

准备 HelloWorld BIN 包

确认本地存在以下应用包:

<工程目录>\src\application\wearable\res\js\IDE5.0\com.vendor.helloworld.bin

该文件是可安装到板端的 Hello World JS Demo 应用包,包名对应 com.vendor.helloworld。如果本地文件不存在,需要先按“编译打包”章节重新生成应用包,或从仓库中恢复该 BIN 文件。

上传 HelloWorld BIN 包

com.vendor.helloworld.bin 上传到板端可访问路径,建议放到:

/user/jsapp/com.vendor.helloworld.bin

文件上传方式可参考《DebugKits工具使用指南》中的“数据上传与下载”章节。上传后需要确认板端路径和文件名与安装命令保持一致。

安装 HelloWorld BIN 包

如果当前是非签名调试包,可先在串口执行关闭验签命令;已签名应用可跳过此步骤。

AT+OHOS=OHOSFWK_BM_SET,disable

在串口执行安装命令:

AT+OHOS=OHOSFWK_BM_INSTALL,/user/jsapp/com.vendor.helloworld.bin

如果需要覆盖安装并清理应用沙箱历史数据,可在命令末尾增加 rmdata

AT+OHOS=OHOSFWK_BM_INSTALL,/user/jsapp/com.vendor.helloworld.bin,rmdata

验证 HelloWorld JS Demo

安装完成后,按以下项目验证:

  • 串口安装命令返回成功。
  • 设备应用列表中出现 Hello World。
  • 点击应用后可以进入首页。
  • 首页显示 HelloWorld 或多语言资源中配置的 Hello World 文本。

如果安装失败,优先检查 BIN 文件是否上传到 /user/jsapp/com.vendor.helloworld.bin、签名模式是否与应用包匹配,以及设备存储空间是否足够。

工程代码的文件结构与代码走读

本章结合 samples/js_samples/helloworld 示例说明 JS 应用工程的代码组织方式。开发者可以先通过 Demo 了解完整工程,再继续阅读通用的文件组织、页面配置、生命周期、语法和国际化规则。

JS Demo开发示例

本节以 samples/js_samples/helloworld 目录下的 HelloWorld 示例为参考,说明 JS 应用工程创建后,如何补充一个可运行的 JS Demo。该示例是一个完整的 JS 应用工程,包含工程级构建配置、entry 模块配置、页面源码和资源文件。示例通过 config.json 配置入口 Ability,通过 hmlcssjs 文件实现页面显示,并通过 i18n 资源完成中英文字符串适配。

示例目录

HelloWorld 示例工程目录如下:

helloworld/
├── build-profile.json5
├── code-linter.json5
├── hvigorfile.ts
├── oh-package.json5
├── hvigor/
│   └── hvigor-config.json5
└── entry/
    ├── build-profile.json5
    ├── hvigorfile.ts
    ├── oh-package.json5
    └── src/main/
        ├── config.json
        ├── js/MainAbility/
        │   ├── app.js
        │   ├── i18n/
        │   │   ├── en-US.json
        │   │   └── zh-CN.json
        │   └── pages/index/
        │       ├── index.css
        │       ├── index.hml
        │       └── index.js
        └── resources/
            ├── base/element/string.json
            ├── base/media/icon.png
            ├── base/media/icon_small.png
            ├── en_US/element/string.json
            └── zh_CN/element/string.json

其中,根目录的 build-profile.json5hvigorfile.tsoh-package.json5hvigor/hvigor-config.json5 用于描述工程构建信息;entry 目录是应用入口模块;entry/src/main/config.json 用于声明应用包名、设备类型、Ability 和 JS 页面入口;app.js 用于处理应用生命周期;pages/index 目录用于实现首页页面;i18nresources 目录用于配置页面文本、应用名称和图标等资源。

工程配置

HelloWorld 示例根目录的 build-profile.json5 声明工程产品、构建模式和模块路径。其中,modules 字段将 entry 模块映射到 ./entry

{
  "app": {
    "signingConfigs": [],
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "compatibleSdkVersion": "5.0.0(12)",
        "runtimeOS": "HarmonyOS",
        "buildOption": {
          "strictMode": {
            "caseSensitiveCheck": true
          }
        }
      }
    ],
    "buildModeSet": [
      {
        "name": "debug"
      },
      {
        "name": "release"
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    }
  ]
}

根目录的 hvigorfile.ts 引用 Hvigor 内置应用构建任务:

import { legacyAppTasks } from '@ohos/hvigor-ohos-plugin';

export default {
    system: legacyAppTasks,
    plugins:[]
}

entry/build-profile.json5 声明模块 API 类型和构建目标:

{
  "apiType": "faMode",
  "buildOption": {
  },
  "targets": [
    {
      "name": "default"
    }
  ]
}

配置入口Ability

entry/src/main/config.json 中配置应用基础信息、设备类型和入口 Ability。HelloWorld 示例中,deviceType 配置为 liteWearable,入口 Ability 名称为 .MainAbility,JS 页面入口为 pages/index/index

{
  "app": {
    "bundleName": "com.vendor.helloworld",
    "vendor": "example",
    "version": {
      "code": 1000000,
      "name": "1.0.0"
    }
  },
  "deviceConfig": {},
  "module": {
    "deviceType": [
      "liteWearable"
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry"
    },
    "abilities": [
      {
        "name": ".MainAbility",
        "srcLanguage": "js",
        "srcPath": "MainAbility",
        "icon": "$media:icon",
        "description": "$string:MainAbility_desc",
        "label": "$string:MainAbility_label",
        "type": "page"
      }
    ],
    "js": [
      {
        "pages": [
          "pages/index/index"
        ],
        "name": ".MainAbility"
      }
    ]
  }
}

app.js 可用于监听应用创建和销毁事件,示例如下:

export default {
    onCreate() {
        console.info('Application onCreate');
    },
    onDestroy() {
        console.info('Application onDestroy');
    }
};

实现页面

JS 页面通常由同名的 hmlcssjs 文件组成。HelloWorld 示例在 pages/index 下实现首页。

index.hml 用于描述页面结构:

<div class="container">
    <text class="title">
        {{ $t('strings.hello') }} {{ title }}
    </text>
</div>

index.css 用于配置页面布局和文本样式:

.container {
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
  flex-direction:column;
}
.title {
  width: 200px;
  font-size: 30px;
  text-align: center;
}

index.js 用于声明页面数据并在 onInit 生命周期中初始化显示内容:

import app from '@system.app';
export default {
    data: {
        title: ''
    },
    onInit() {
        this.title = this.$t('strings.world');
    },
}

页面运行后,index.hml 会读取 strings.hellotitle 的值,组合显示 “您好 世界” 或 “Hello World”。

配置多语言资源

页面中通过 $t 读取 i18n 目录下的字符串资源。中文资源文件 js/MainAbility/i18n/zh-CN.json 示例:

{
  "strings": {
    "hello": "您好",
    "world": "世界"
  }
}

应用标签、描述等系统资源在 resources/*/element/string.json 中配置。基础资源示例如下:

{
  "string": [
    {
      "name": "module_desc",
      "value": "module description"
    },
    {
      "name": "MainAbility_desc",
      "value": "description"
    },
    {
      "name": "MainAbility_label",
      "value": "helloworld"
    }
  ]
}

config.json 中的 $string:MainAbility_label$string:MainAbility_desc$media:icon 会分别关联到资源目录中的字符串和图片资源。

运行验证

  1. 可直接使用 DevEco Studio 打开 samples/js_samples/helloworld 完整工程进行编译和预览。
  2. 如果是在新建工程中合入示例,需参考 HelloWorld 根目录的工程配置文件,并将 entry 模块内容合入新工程对应目录。
  3. 确认 config.jsonbundleNamedeviceType、Ability 名称和 pages 路径符合当前工程配置。
  4. 使用 DevEco Studio 执行编译和预览。
  5. 预览或安装运行后,首页应显示 HelloWorld 文本;切换系统语言时,页面文本应读取对应 i18n 资源。

说明: 如果当前工程已存在同名 Ability 或首页路径,请按工程实际目录调整 srcPathnamepages 配置,避免入口配置和页面目录不一致。

文件组织

目录结构

JS 应用的 JS 模块(应用工程内的 entry/src/main/js/module)典型目录结构如下:

├── app.js
├── pages
│     ├── index
│     │       ├── index.hml
│     │       ├── index.css
│     │       └── index.js
│     └── detail(可选)
│            ├── detail.hml
│            ├── detail.css
│            └── detail.js
├── common(可选)
│     ├── xxx.png
│     ├── style.css
│     └── utils.js
└── i18n(可选)
├── zh-CN.json
└── en-CN.json

目录结构中文件分类如下:

  • .hml结尾的HML模板文件,此文件用来描述当前页面的文件布局结构。
  • .css结尾的CSS样式文件,此文件用于描述页面样式。
  • .js结尾的JS文件,此文件用于处理页面和用户的交互。

各个文件夹的作用:

  • pages目录用于存放所有组件页面。
  • common目录用于存放公共资源文件,如:媒体资源和JS文件。
  • i18n目录用于配置不同语言场景资源内容,如应用文本词条、图片路径等资源。

须知:

  • i18n是开发保留文件夹,不可重命名。
  • 在使用DevEco Studio进行应用开发时,目录结构中的可选文件夹需要开发者根据实际情况自行创建。

文件访问规则

应用资源可通过绝对路径或相对路径的方式进行访问,本开发框架中绝对路径以“/”开头,相对路径以“./”或“../”。具体访问规则如下:

  • 引用代码文件,推荐使用相对路径,如:../common/utils.js。
  • 引用资源文件,推荐使用绝对路径,如:/common/xxx.png。
  • 公共代码文件和资源文件建议放在common下,通过以上两条规则进行访问。
  • CSS样式文件中通过url()函数创建<url>数据类型,如:url(/common/xxx.png)。

说明: 当代码文件A需要引用代码文件B时:

  • 如果代码文件A和文件B位于同一目录,则代码文件B引用资源文件时可使用相对路径,也可使用绝对路径。
  • 如果代码文件A和文件B位于不同目录,则代码文件B引用资源文件时必须使用绝对路径。因为Webpack打包时,代码文件B的目录会发生变化。

媒体文件格式

说明: 以下是JS应用工程可用的图片类型,当编译安装包时,会由IDE转换为海思压缩图片格式。

表 1 支持的图片格式

格式

支持的文件类型

BMP

.bmp

JPEG

.jpg

PNG

.png

音频资源文件

音频资源文件可跟随应用一起打包编译,通过相对路径的方式进行访问;也可以预置在系统目录,使用绝对路径的方式进行访问,具体使用规则如下:

  • 跟随应用打包的音频资源文件必须放置在resources下(默认文件夹或新增自定义子目录),如:resources/base/media/xxx.mp3。

    相对路径引用时,设置播放器的srcInner属性,如:player.srcInner = "resources/base/media/xxx.mp3" 。

  • 预置在系统目录,如:/user/music/xxx.mp3。

    绝对路径引用时,设置播放器的src属性,如:player.src = "/user/music/xxx.mp3" 。

js标签配置

js标签中包含实例名称、页面路由信息如表1所示。

表 1 js标签配置

标签

类型

默认值

必填

说明

name

string

default

标识JS实例的名字。

pages

Array

-

路由信息,请参见“pages”内容。

说明: name、pages 标签配置需在“配置文件”(config.json)中的“js”标签中完成设置。

pages

定义每个页面的路由信息,每个页面由页面路径和页面名组成,页面的文件名即页面名。如:

{
    ...
    "pages": [
        "pages/index/index",
        "pages/detail/detail"
    ]
    ...
}

说明:

  • 应用首页固定为“pages/index/index”。
  • 页面文件名不能使用组件名称,如:text.hml、button.hml等。

示例

{
    "app": {
        "bundleName": "com.example.player",
        "version": {
            "code": 1,
            "name": "1.0"
        },
        "vendor": "example"
    }
    "module": {
        ...
        "js": [
        {
            "name": "default",
            "pages": [
                "pages/index/index",
                "pages/detail/detail"
            ]
        }
        ],
        "abilities": [
        {
            ...
        }
        ]
    }
}

app.js

应用生命周期

每个应用可以在app.js中自定义“生命周期”的实现逻辑,以下示例仅在生命周期函数中打印对应日志:

// app.js
export default {
    onCreate() {
        console.info('Application onCreate');
    },

    onDestroy() {
        console.info('Application onDestroy');
    },
}