再学Harmony-03

  • ~11.28K 字

前面总结了鸿蒙开发的调试环境配置,今天来看看相关配置规范

1 配置规范

1.1 工程结构

1.1.1 代码目录结构

目前新建项目可选内置的功能生成新项目,默认采用Stage模型构建

其目录结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
├──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资源目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

1
2
3
4
5
6
7
8
9
10
{
"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

1
2
3
4
5
6
7
{
"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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"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 需遵循以下原则

1
[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

1
2
3
4
5
6
7
8
9
{
"module": {
// ...
"deviceTypes": [
"phone",
"tablet"
],
}
}

目前只需处理手机和平板

1.2.6 Module权限配置

Module访问系统或其他应用受保护部分所需的权限信息需要在module.json5配置文件中配置requestPermission标签。该标签用于声明需要申请权限的名称、申请权限的原因以及权限使用的场景。

module目录下的module.json5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"module": {
// ...
"requestPermissions": [
{
"name": "ohos.abilitydemo.permission.PROVIDER",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when": "inuse"
}
}
]
}
}

“reason”会直接体现在下图红线位置,根据当前应用需求,自行处理即可

2 权限

2.1 权限使用的基本原则

在进行权限的申请和使用时,需要满足以下基本原则:

  1. 应用申请的权限,都必须有明确、合理的使用场景和功能说明,确保用户能够清晰明了地知道申请权限的目的、场景、用途;禁止诱导、误导用户授权;应用使用权限必须与申请所述一致。
  2. 应用权限申请遵循最小化原则,只申请业务功能所必要的权限,禁止申请不必要的权限。
  3. 应用在首次启动时,避免频繁弹窗申请多个权限;权限须在用户使用对应业务功能时动态申请。
  4. 用户拒绝授予某个权限时,与此权限无关的其他业务功能应能正常使用,不能影响应用的正常注册或登录。
  5. 业务功能所需要的权限被用户拒绝且禁止后不再提示,当用户主动触发使用此业务功能或为实现业务功能所必须时,应用程序可通过界面内文字引导,让用户主动到“系统设置”中授权。
  6. 当前不允许应用自行定义权限,应用申请的权限应该从已有的权限列表中选择。

对于第三点,可根据实际情况,保证系统首次授权的完整性,自行决定。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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

未完待续…

赞助喵
非常感谢您的喜欢!
赞助喵
分享这一刻
让朋友们也来瞅瞅!