1.概述
在基于Stage模型开发应用之前,开发者需要了解应用的设计机制、应用程序包结构等基础知识。
应用与应用程序包
用户应用程序泛指运行在设备的操作系统之上,为用户提供特定服务的程序,简称"应用"。一个应用所对应的软件包文件,称为"应用程序包"。
当前系统提供了应用程序包开发、安装、查询、更新、卸载的管理机制,便于开发者开发和管理应用。同时,系统还屏蔽了不同的芯片平台的差异(包括x86/ARM,32位/64位等),应用程序包在不同的芯片平台都能够安装运行,这使得开发者可以聚焦于应用的功能实现。
应用的多Module设计机制
- 支持模块化开发 : 一个应用通常会包含多种功能,将不同的功能特性按模块来划分和管理是一种良好的设计方式。在开发过程中,我们可以将每个功能模块作为一个独立的Module进行开发,Module中可以包含源代码、资源文件、第三方库、配置文件等,每一个Module可以独立编译,实现特定的功能。这种模块化、松耦合的应用管理方式有助于应用的开发、维护与扩展。
- 支持多设备适配: 一个应用往往需要适配多种设备类型,在采用多Module设计的应用中,每个Module都会标注所支持的设备类型。有些Module支持全部类型的设备,有些Module只支持某一种或几种类型的设备(比如平板),那么在应用市场分发应用包时,也能够根据设备类型做精准的筛选和匹配,从而将不同的包合理的组合和部署到对应的设备上。
工程目录结构
2.应用配置
每个应用项目的代码目录下必须包含应用配置文件,这些配置文件会向编译工具、操作系统和应用市场提供应用的基本信息。
在基于Stage模型开发的应用项目代码下,都存在一个app.json5配置文件、以及一个或多个module.json5配置文件。
app.json5配置文件主要包含以下内容:
- 应用的全局配置信息,包含应用的Bundle名称、开发厂商、版本号等基本信息。
- 特定设备类型的配置信息。
module.json5配置文件主要包含以下内容:
- Module的基本配置信息,包含Module名称、类型、描述、支持的设备类型等基本信息。
- 应用组件信息,包含UIAbility组件和ExtensionAbility组件的描述信息。
- 应用运行过程中所需的权限信息。
配置图标与文字
打开模拟器或者真机,我们需要配置应用和桌面上的图标和文字,如何配置?
图标和标签通常一起配置,对应app.json5配置文件和module.json5配置文件中的icon和label标签。
注意:
- DevEco Studio从5.0.3.800版本开始,不再对module.json5中的icon和label做强制校验,因此module.json5与app.json5只需要选择其一配置即可
- 如果两个同时存在:module.json5中的配置会覆盖app.json5中的配置
3.UIAbility 组件
1. 概述
UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。
UIAbility的设计理念:
- 原生支持应用组件级的跨端迁移和多端协同。
- 支持多设备和多窗口形态。
UIAbility划分原则与建议:
UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。例如,在支付应用中,可以将入口功能和收付款功能分别配置为独立的UIAbility。
每一个UIAbility组件实例都会在最近任务列表中显示一个对应的任务。
对于开发者而言,可以根据具体场景选择单个还是多个UIAbility,划分建议如下:
- 如果开发者希望在任务视图中看到一个任务,建议使用"一个UIAbility+多个页面"的方式,可以避免不必要的资源加载。
- 如果开发者希望在任务视图中看到多个任务,或者需要同时开启多个窗口,建议使用多个UIAbility实现不同的功能。
例如,即时通讯类应用中的消息列表与音视频通话采用不同的UIAbility进行开发,既可以方便地切换任务窗口,又可以实现应用的两个任务窗口在一个屏幕上分屏显示。
说明
任务视图用于快速查看和管理当前设备上运行的所有任务或应用。
声明配置
为使应用能够正常使用UIAbility,需要在module.json5配置文件的abilities标签中声明UIAbility的名称、入口、标签等相关信息。
kotlin
{
"module": {
// ...
"abilities": [
{
"name": "EntryAbility", // UIAbility组件的名称
"srcEntry": "./ets/entryability/EntryAbility.ets", // UIAbility组件的代码路径
"description": "$string:EntryAbility_desc", // UIAbility组件的描述信息
"icon": "$media:icon", // UIAbility组件的图标
"label": "$string:EntryAbility_label", // UIAbility组件的标签
"startWindowIcon": "$media:icon", // UIAbility组件启动页面图标资源文件的索引
"startWindowBackground": "$color:start_window_background", // UIAbility组件启动页面背景颜色资源文件的索引
// ...
}
]
}
}
是什么?UIAbility组件是 一种包含UI的应用组件 ,为应用提供绘制界面的窗口,主要用于和用户交互
一个应用可以 包含一个 或多个UIAbility组件
每一个UIAbility组件实例都会在最近任务列表中显示一个对应的任务
应用的UIAbility划分:
- 单UIAbility -> 在手机操作系统的任务列表中只有一个任务窗口
- 多UIAbility-> 在手机操作系统的任务列表中有多个任务窗口
场景选择:
对于开发者而言,可以根据具体场景选择单个还是多个UIAbility
- 如果开发者希望在任务视图中看到一个任务,建议使用"一个UIAbility+多个页面"的方式,可以避免不必要的资源加载。
- 如果开发者希望在任务视图中看到多个任务,或者需要同时开启多个窗口,建议使用多个UIAbility实现不同的功能。
例如,微信【消息列表】与【音视频通话】采用不同的UIAbility进行开发,既可以方便地切换任务窗口,又可以实现应用的两个任务窗口在一个屏幕上分屏显示
2. 指定 UIAbility 的启动页
在UIAbility的onWindowStageCreate()生命周期回调中,通过 WindowStage 对象的 loadContent() 方法设置启动页面。
注意:
- 设置的页面路径,需要在 main_page.json5中存在(否则会出现白屏)
- 页面必须有一个入口组件(@Entry修饰的组件)
3.UIAbility的生命周期
当用户打开、切换和返回到应用时,应用中的UIAbility实例会在其生命周期的不同状态之间转换UIAbility类提供了一系列【回调函数】,如果需要在特定的时间添加自定义逻辑,往对应的回调函数内添加代码即可
UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态:
回调函数编写位置和作用:
执行时序图:
4.更改默认启动的UIAbility
当有多个UIAbility时,我们可以通过调整src/main/module.json5中的配置来更改默认启动的UIAbility
步骤:
- 创建一个新的UIAbility
- 调整
src/main/module.json5
中 ->mainElement属性指向abilities属性中的UIAbility名字 - 调整
src/main/module.json5
中 ->abilities节点中的UIAbility的"exported"为true,加上skills
ruby
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
//修改默认启动的UIAbility名
"mainElement": "EntryAbility_demo",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
//标识当前Module是否在用户主动安装的时候安装,即该Module对应的HAP是否跟随应用一起安装。
"deliveryWithInstall": true,
//标识当前Module是否支持免安装特性。
//true:表示支持免安装特性,且符合免安装约束。
"installationFree": false,
// 标识当前Module的profile资源
"pages": "$profile:main_pages",
"abilities": [
{
// UIAbility组件的名称
"name": "EntryAbility",
// UIAbility组件的代码路径
"srcEntry": "./ets/entryability/EntryAbility.ets",
// UIAbility组件的描述信息
"description": "$string:EntryAbility_desc",
// "icon": "$media:layered_image",
// "label": "$string:EntryAbility_label",
//UIAbility组件启动页面图标资源文件的索引
"startWindowIcon": "$media:jd_logo",
// UIAbility组件启动页面背景颜色资源文件的索引
"startWindowBackground": "$color:start_window_background",
},
{
"name": "EntryAbility_demo",
"srcEntry": "./ets/entryability_demo/EntryAbility_demo.ets",
"description": "$string:EntryAbility_demo_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_demo_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
//
//标识当前UIAbility组件是否可以被其他应用调用。
//true:表示可以被其他应用调用。
"exported": true,
//标识当前UIAbility组件或ExtensionAbility组件能够接收的Want特征集,为数组格式。
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
],
}
]
}
}
exported 与skills 只有一个用来说明该 UIability 具有调起其他页面的能力
5.拉起同一个模块的不同的UIAbility
同一个模块中,从一个UIAbility中拉起另一个UIAbility
举例:同EntryAbility中的一个页面中,点击按钮,拉起EntryAbility
typescript
import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct demo {
build() {
Column() {
Button('调起另一个UIAbility').onClick(() => {
// 1. 获得上下文对象
const context = getContext(this) as common.UIAbilityContext
//2. 调用startAbility()拉起secondAbility
context.startAbility({
bundleName: 'com.example.myapplication_3', // 包名称 AppScope/app.json5中查看
moduleName:'entry',// 模块名称 entry/src/main/module.json5 -> module->name
abilityName: 'EntryAbility', // ability名称 entry/src/main/module.json5 -> abilities找
parameters:{ // 向Ability传入参数
info:'这是entry传入的参数内容'
}
})
.then(() => {
console.log('startAbility success.');
})
.catch((error: BusinessError) => {
console.log('startAbility failed.');
});
})
}.width('100%').height('100%').backgroundColor(Color.Orange)
}
}
javascript
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 在onCreate生命周期里面的want参数就会自动接收拉起方传入的数据
console.log('--->',JSON.stringify(want))
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
}
6.拉起不同模块的UIAbility
从一个UIAbility中拉起不同模块中的一个UIAbility
步骤:
- 创建一个新模块
--->
- 配置Entry启动项
- 编写拉起代码
typescript
import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct demo {
build() {
Column() {
Button('调起同一个模块的UIAbility').onClick(() => {
// 1. 获得上下文对象
const context = getContext(this) as common.UIAbilityContext
//2. 调用startAbility()拉起secondAbility
context.startAbility({
bundleName: 'com.example.myapplication_3', // 包名称 AppScope/app.json5中查看
moduleName:'entry',// 模块名称 entry/src/main/module.json5 -> module->name
abilityName: 'EntryAbility', // ability名称 entry/src/main/module.json5 -> abilities找
parameters:{ // 向Ability传入参数
info:'这是entry传入的参数内容'
}
})
.then(() => {
console.log('startAbility success.');
})
.catch((error: BusinessError) => {
console.log('startAbility failed.');
});
})
Button('调起跨模块的UIAbility').onClick(() => {
// 1. 获得上下文对象
const context = getContext(this) as common.UIAbilityContext
context.startAbility({
bundleName: 'com.example.myapplication_3', // 包名称 AppScope/app.json5中查看
moduleName:'Moudle_demo',// 模块名称 entry/src/main/module.json5 -> module->name
abilityName: 'Moudle_demoAbility', // ability名称 entry/src/main/module.json5 -> abilities找
parameters:{ // 向Ability传入参数
info:'这是entry传入的参数内容'
}
})
})
}.width('100%').height('100%').backgroundColor(Color.Orange)
}
}