前面总结了鸿蒙开发的调试环境配置,今天来看看相关配置规范
# 1 配置规范
# 1.1 工程结构
# 1.1.1 代码目录结构
目前新建项目可选内置的功能生成新项目,默认采用 Stage 模型构建
其目录结构如下

├──entry/src/main/ets // 代码区 | |
│ ├──common | |
│ │ ├──constants | |
│ │ │ └──CommonConstant.ets // 常量集合文件 | |
│ │ └──utils | |
│ │ ├──BroadCast.ets // 事件发布订阅管理器 | |
│ │ └──Log.ets // 日志打印 | |
│ ├──entryability | |
│ │ └──EntryAbility.ts // 应用入口,承载应用的生命周期 | |
│ ├──model | |
│ │ ├──EventSourceManager.ets // 事件资源管理器 | |
│ │ ├──TaskInfo.ets // 任务信息存放 | |
│ │ └──TaskInitList.ets // 初始化数据 | |
│ ├──pages | |
│ │ ├──ListIndexPage.ets // 页面入口 | |
│ │ └──TaskEditPage.ets // 编辑任务页 | |
│ ├──view | |
│ │ ├──CustomDialogView.ets // 自定义弹窗统一入口 | |
│ │ ├──TaskDetail.ets // 任务编辑详情组件 | |
│ │ ├──TaskEditListItem.ets // 任务编辑详情Item组件 | |
│ │ ├──TaskList.ets // 任务列表组件 | |
│ │ └──TaskSettingDialog.ets // 弹窗组件 | |
│ └──viewmodel | |
│ ├──FrequencySetting.ets // 频率范围设置 | |
│ └──TaskTargetSetting.ets // 任务目标设置 | |
└──entry/src/main/resources | |
├──base | |
│ ├──element // 字符串以及颜色的资源文件 | |
│ ├──media // 图片等资源文件 | |
│ └──profile // 页面配置文件存放位置 | |
├──en_US | |
│ └──element | |
│ └──string.json // 英文字符存放位置 | |
├──rawfile // 大体积媒体资源存放位置 | |
└──zh_CN | |
└──element | |
└──string.json // 中文字符存放位置 |
# 1.1.2 资源目录结构
resources | |
|---base | |
| |---element | |
| | |---string.json | |
| |---media | |
| | |---icon.png | |
| |---profile | |
| | |---test_profile.json | |
|---en_US // 默认存在的目录,设备语言环境是美式英文时,优先匹配此目录下资源 | |
| |---element | |
| | |---string.json | |
| |---media | |
| | |---icon.png | |
| |---profile | |
| | |---test_profile.json | |
|---zh_CN // 默认存在的目录,设备语言环境是简体中文时,优先匹配此目录下资源 | |
| |---element | |
| | |---string.json | |
| |---media | |
| | |---icon.png | |
| |---profile | |
| | |---test_profile.json | |
|---en_GB-vertical-car-mdpi // 自定义限定词目录示例,由开发者创建 | |
| |---element | |
| | |---string.json | |
| |---media | |
| | |---icon.png | |
| |---profile | |
| | |---test_profile.json | |
|---rawfile // 其他类型文件,原始文件形式保存,不会被集成到resources.index文件中。文件名可自定义。 |
# 1.2 应用 / 组件级配置
在开发应用时,需要配置应用的一些标签,例如应用的包名、图标等标识特征的属性。
图标和标签通常一起配置,可以分为应用图标、应用标签和入口图标、入口标签,分别对应 app.json5 配置文件和 module.json5 配置文件中的 icon 和 label 标签。应用图标和标签是在设置应用中使用,例如设置应用中的应用列表。入口图标是应用安装完成后在设备桌面上显示出来的,如下图所示。

AppScope 目录下的 app.json5
{ | |
"app": { | |
"bundleName": "com.wuhanins.hrlocation", | |
"vendor": "example", | |
"versionCode": 1000000, | |
"versionName": "1.0.0", | |
"icon": "$media:ins_logo", | |
"label": "$string:app_name" | |
} | |
} |
入口图标是以 UIAbility 为粒度,支持同一个应用存在多个入口图标和标签,点击后进入对应的 UIAbility 界面。此类图标显示在手机桌面。
# 1.2.1 应用包名配置
应用需要在工程的 AppScope 目录下的 app.json5 配置文件中配置 bundleName 标签,该标签用于标识应用的唯一性。推荐采用反域名形式命名(如 com.example.demo,建议第一级为域名后缀 com,第二级为厂商 / 个人名,第三级为应用名,也可以多级)。
# 1.2.2 应用图标和标签配置
Stage 模型的应用需要配置应用图标和应用标签。应用图标和标签是在设置应用中使用,例如设置应用中的应用列表,会显示出对应的图标和标签。
应用图标需要在工程的 AppScope 目录下的 app.json5 配置文件中配置 icon 标签。应用图标需配置为图片的资源索引,配置完成后,该图片即为应用的图标。
应用标签需要在工程的 AppScope 模块下的 app.json5 配置文件中配置 label 标签。标识应用对用户显示的名称,需要配置为字符串资源的索引。
AppScope 目录下的 app.json5
{ | |
"app": { | |
"icon": "$media:app_icon", | |
"label": "$string:app_name" | |
// ... | |
} | |
} |
# 1.2.3 入口图标和标签配置
Stage 模型支持对组件配置入口图标和入口标签。入口图标和入口标签会显示在桌面上。
入口图标需要在 module.json5 配置文件中配置,在 abilities 标签下面有 icon 标签。例如希望在桌面上显示该 UIAbility 的图标,则需要在 skills 标签下面的 entities 中添加 "entity.system.home"、actions 中添加 "action.system.home"。同一个应用有多个 UIAbility 配置上述字段时,桌面上会显示出多个图标,分别对应各自的 UIAbility。
module 目录下的 module.json5
{ | |
"module": { | |
// ... | |
"abilities": [ | |
{ | |
// $ 开头的为资源值 | |
"icon": "$media:icon", | |
"label": "$string:EntryAbility_label", | |
"skills": [ | |
{ | |
"entities": [ | |
"entity.system.home" | |
], | |
"actions": [ | |
"action.system.home" | |
] | |
} | |
], | |
} | |
] | |
} | |
} |
目前开发只有一个入口,应用图标和标签应该与入口图标和标签一致。
# 1.2.4 应用版本声明配置
未完待续... 应用版本声明需要在工程的 AppScope 目录下的 app.json5 配置文件中配置 versionCode 标签和 versionName 标签。versionCode 用于标识应用的版本号,该标签值为 32 位非负整数。此数字仅用于确定某个版本是否比另一个版本更新,数值越大表示版本越高。versionName 标签标识版本号的文字描述。
versionCode 每次更新版本需要手动增加
versionName 需遵循以下原则
[v][大版本号][.][过度版本号][.][自增版本号].[当前日期][_某天多版本号区分] |
[_某天多版本号] 为可选项,当天仅有一个版本时可以不需要
例如:v1.0.27.20240521 v1.0.27.20240521_1
# 1.2.5 Module 支持的设备类型配置
Module 支持的设备类型需要在 module.json5 配置文件中配置 deviceTypes 标签,如果 deviceTypes 标签中添加了某种设备,则表明当前的 Module 支持在该设备上运行。
类似于 android 项目中的 abiFilters
module 目录下的 module.json5
{ | |
"module": { | |
// ... | |
"deviceTypes": [ | |
"phone", | |
"tablet" | |
], | |
} | |
} |
目前只需处理手机和平板
# 1.2.6 Module 权限配置
Module 访问系统或其他应用受保护部分所需的权限信息需要在 module.json5 配置文件中配置 requestPermission 标签。该标签用于声明需要申请权限的名称、申请权限的原因以及权限使用的场景。
module 目录下的 module.json5
{ | |
"module": { | |
// ... | |
"requestPermissions": [ | |
{ | |
"name": "ohos.abilitydemo.permission.PROVIDER", | |
"reason": "$string:reason", | |
"usedScene": { | |
"abilities": [ | |
"FormAbility" | |
], | |
"when": "inuse" | |
} | |
} | |
] | |
} | |
} |
“reason” 会直接体现在下图红线位置,根据当前应用需求,自行处理即可

# 2 权限
# 2.1 权限使用的基本原则
在进行权限的申请和使用时,需要满足以下基本原则:
- 应用申请的权限,都必须有明确、合理的使用场景和功能说明,确保用户能够清晰明了地知道申请权限的目的、场景、用途;禁止诱导、误导用户授权;应用使用权限必须与申请所述一致。
- 应用权限申请遵循最小化原则,只申请业务功能所必要的权限,禁止申请不必要的权限。
应用在首次启动时,避免频繁弹窗申请多个权限;权限须在用户使用对应业务功能时动态申请。- 用户拒绝授予某个权限时,与此权限无关的其他业务功能应能正常使用,不能影响应用的正常注册或登录。
- 业务功能所需要的权限被用户拒绝且禁止后不再提示,当用户主动触发使用此业务功能或为实现业务功能所必须时,应用程序可通过界面内文字引导,让用户主动到 “系统设置” 中授权。
- 当前不允许应用自行定义权限,应用申请的权限应该从已有的权限列表中选择。
对于第三点,可根据实际情况,保证系统首次授权的完整性,自行决定。
# 2.2 权限等级说明
根据接口所涉数据的敏感程度或所涉能力的安全威胁影响,ATM 模块定义了不同开放范围的权限等级来保护用户隐私。
# 2.2.1 应用 APL 等级说明
元能力权限等级 APL(Ability Privilege Level)指的是应用的权限申请优先级的定义,不同 APL 等级的应用能够申请的权限等级不同。
应用的等级可以分为三个等级,分别是:
| APL 级别 | 说明 |
|---|---|
| system_core 等级 | 该等级的应用服务提供操作系统核心能力。 |
| system_basic 等级 | 该等级的应用服务提供系统基础服务。 |
| normal 等级 | 普通应用。 |
# 2.2.2 权限等级说明
根据权限对于不同等级应用有不同的开放范围,权限类型对应分为以下三种,等级依次提高。
normal 权限
normal 权限允许应用访问超出默认规则外的普通系统资源。这些系统资源的开放(包括数据和功能)对用户隐私以及其他应用带来的风险很小。
该类型的权限仅向 APL 等级为 normal 及以上的应用开放。
system_basic 权限
system_basic 权限允许应用访问操作系统基础服务相关的资源。这部分系统基础服务属于系统提供或者预置的基础功能,比如系统设置、身份认证等。这些系统资源的开放对用户隐私以及其他应用带来的风险较大。
该类型的权限仅向 APL 等级为 system_basic 及以上的应用开放。
system_core 权限
system_core 权限涉及到开放操作系统核心资源的访问操作。这部分系统资源是系统最核心的底层服务,如果遭受破坏,操作系统将无法正常运行。
鉴于该类型权限对系统的影响程度非常大,目前暂不向任何三方应用开放。
# 2.2.3 权限类型说明
根据授权方式的不同,权限类型可分为 system_grant(系统授权)和 user_grant(用户授权)。
system_grant
system_grant 指的是系统授权类型,在该类型的权限许可下,应用被允许访问的数据不会涉及到用户或设备的敏感信息,应用被允许执行的操作不会对系统或者其他应用产生大的不利影响。
如果在应用中申请了 system_grant 权限,那么系统会在用户安装应用时,自动把相应权限授予给应用。应用需要在应用商店的详情页面,向用户展示所申请的 system_grant 权限列表。
user_grant
user_grant 指的是用户授权类型,在该类型的权限许可下,应用被允许访问的数据将会涉及到用户或设备的敏感信息,应用被允许执行的操作可能对系统或者其他应用产生严重的影响。
该类型权限不仅需要在安装包中申请权限,还需要在应用动态运行时,通过发送弹窗的方式请求用户授权。在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。
应用需要在应用商店的详情页面,向用户展示所申请的 user_grant 权限列表。
# 2.2.4 不同权限类型的授权流程
权限申请
开发者需要在配置文件中声明目标权限。
权限授权
如果目标权限是 system_grant 类型,开发者在进行权限申请后,系统会在安装应用时自动为其进行权限预授予,开发者不需要做其他操作即可使用权限。
如果目标权限是 user_grant 类型,开发者在进行权限申请后,在运行时触发动态弹窗,请求用户授权。
ohos.permission.LOCATION 权限
申请条件:使用 API version 9 以下版本的 SDK 开发的应用,可以直接申请此权限。使用 API version 9 及 API version 9 以上版本的 SDK 开发的应用,需要先申请权限 ohos.permission.APPROXIMATELY_LOCATION,才可申请此权限。
动态请求授权实例
module 目录下的 module.json5
import type AbilityConstant from '@ohos.app.ability.AbilityConstant'; | |
import hilog from '@ohos.hilog'; | |
import UIAbility from '@ohos.app.ability.UIAbility'; | |
import type Want from '@ohos.app.ability.Want'; | |
import type window from '@ohos.window'; | |
import Package from '@system.package'; | |
import bundleManager from '@ohos.bundle.bundleManager'; | |
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; | |
const permissions: Array<Permissions> = ['ohos.permission.READ_CALENDAR']; | |
/** | |
* Lift cycle management of Ability. | |
*/ | |
export default class EntryAbility extends UIAbility { | |
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); | |
} | |
onDestroy(): void { | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); | |
} | |
onWindowStageCreate(windowStage: window.WindowStage): void { | |
// Main window is created, set main page for this ability | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); | |
let context = this.context; | |
let atManager = abilityAccessCtrl.createAtManager(); | |
//requestPermissionsFromUser 会判断权限的授权状态来决定是否唤起弹窗 | |
atManager.requestPermissionsFromUser(context, permissions).then((data) => { | |
let grantStatus: Array<number> = data.authResults; | |
let length: number = grantStatus.length; | |
for (let i = 0; i < length; i++) { | |
if (grantStatus[i] === 0) { | |
// 用户授权,可以继续访问目标操作 | |
this.loadSplash(windowStage) | |
} else { | |
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 | |
return; | |
} | |
} | |
// 授权成功 | |
this.loadSplash(windowStage) | |
}).catch((err) => { | |
console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`); | |
}) | |
} | |
loadSplash(windowStage: window.WindowStage){ | |
windowStage.loadContent("pages/SplashScreenPage", (err, data) => { | |
if (err.code) { | |
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); | |
return; | |
} | |
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); | |
}); | |
} | |
onWindowStageDestroy(): void { | |
// Main window is destroyed, release UI related resources | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); | |
} | |
onForeground(): void { | |
// Ability has brought to foreground | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); | |
} | |
onBackground(): void { | |
// Ability has back to background | |
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); | |
} | |
} |
此处提供官方权限列表及说明
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/permission-list-0000001544464017-V2
未完待续...