• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Ability开发指导
2## 场景介绍
3Stage模型是区别于FA模型的一种应用开发模型,对此模型的介绍详见[Stage模型综述](stage-brief.md)。开发Stage模型应用时,需要在module.json5app.json5配置文件中对应用的包结构进行声明,对应用包结构配置文件的说明详见[应用包结构配置文件的说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)。基于Stage模型的Ability应用开发,主要涉及如下功能逻辑:
4- 创建支持使用屏幕浏览及人机交互的Ability应用,包括实现Ability的生命周期、获取Ability配置信息、向用户申请授权及环境变化通知等场景。
5- 启动Ability应用,包括相同设备启动Ability、跨设备启动Ability以及指定页面启动Ability等场景。
6- 通用组件Call功能,详见[Call调用开发指导](stage-call.md)。
7- 连接ServiceExtensionAbility,与ServiceExtensionAbility断开连接,详见[ServiceExtensionAbility开发指导](stage-serviceextension.md)。
8- 应用迁移,详见[应用迁移开发指导](stage-ability-continuation.md)。
9
10### 启动模式
11ability支持单实例、多实例和指定实例3种启动模式,在module.json5中通过launchType配置。启动模式对应Ability被启动时的行为,对启动模式的详细说明如下:
12
13| 启动模式     | 描述     |说明             |
14| ----------- | -------  |---------------- |
15| standard    | 多实例   | 每次startAbility都会启动一个新的实例 |
16| singleton   | 单实例   | 系统中只存在唯一一个实例,startAbility时,如果已存在,则复用系统中的唯一一个实例 |
17| specified   | 指定实例 | 运行时由ability内部业务决定是否创建多实例 |
18
19缺省情况下是singleton模式,module.json5示例如下:
20```json
21{
22  "module": {
23    "abilities": [
24      {
25        "launchType": "singleton",
26      }
27    ]
28  }
29}
30```
31## 创建Ability
32### 接口说明
33AbilityStage功能如下(AbilityStage类,拥有context属性,具体的API详见[接口文档](../reference/apis/js-apis-application-abilitystage.md)):
34
35**表1** AbilityStage API接口功能介绍
36|接口名|描述|
37|:------|:------|
38|onCreate(): void|AbilityStage初始化时被调用。|
39|onAcceptWant(want: Want): string|启动指定Ability时被调用。|
40|onConfigurationUpdated(config: Configuration): void|全局配置发生变更时被调用。|
41
42Ability功能如下(Ability类,具体的API详见[接口文档](../reference/apis/js-apis-application-ability.md)):
43
44**表2** Ability API接口功能介绍
45|接口名|描述|
46|:------|:------|
47|onCreate(want: Want, param: AbilityConstant.LaunchParam): void|Ability生命周期回调,Ability启动时被调用。|
48|onDestroy(): void|Ability生命周期回调,Ability销毁时被调用。|
49|onWindowStageCreate(windowStage: window.WindowStage): void|Ability生命周期回调,创建window stage时被调用,应用开发者可通过window.WindowStage的接口执行页面加载等操作。|
50|onWindowStageDestroy(): void|Ability生命周期回调,销毁window stage时被调用。|
51|onForeground(): void|Ability生命周期回调,Ability切换至前台时被调用。|
52|onBackground(): void|Ability生命周期回调,Ability切换至后台时被调用。|
53|onNewWant(want: Want): void|Ability回调,Ability的启动模式设置为单例时被调用。|
54|onConfigurationUpdated(config: Configuration): void|Ability回调,Ability的系统配置更新时被调用。|
55### 实现AbilityStage及Ability生命周期
56创建Stage模型的Page Ability应用,需实现AbilityStage接口及Ability生命周期接口,并使用窗口提供的方法设置页面。具体示例代码如下:
571. 导入AbilityStage模块。
58   ```
59   import AbilityStage from "@ohos.application.AbilityStage"
60   ```
612. 实现AbilityStage接口,接口生成的默认相对路径:entry\src\main\ets\Application\AbilityStage.ts62   ```ts
63   export default class MyAbilityStage extends AbilityStage {
64    onCreate() {
65        console.log("MyAbilityStage onCreate")
66    }
67   }
68   ```
693. 导入Ability模块。
70   ```js
71   import Ability from '@ohos.application.Ability'
72   ```
734. 实现Ability生命周期接口,接口默认生成的相对路径:entry\src\main\ets\MainAbility\MainAbility.ts74
75   在`onWindowStageCreate(windowStage)`中通过loadContent接口设置应用要加载的页面,window接口的使用详见[窗口开发指导](../windowmanager/window-guidelines.md)。
76   ```ts
77   export default class MainAbility extends Ability {
78    onCreate(want, launchParam) {
79        console.log("MainAbility onCreate")
80    }
81
82    onDestroy() {
83        console.log("MainAbility onDestroy")
84    }
85
86    onWindowStageCreate(windowStage) {
87        console.log("MainAbility onWindowStageCreate")
88
89        windowStage.loadContent("pages/index").then(() => {
90            console.log("MainAbility load content succeed")
91        }).catch((error) => {
92            console.error("MainAbility load content failed with error: "+ JSON.stringify(error))
93        })
94    }
95
96    onWindowStageDestroy() {
97        console.log("MainAbility onWindowStageDestroy")
98    }
99
100    onForeground() {
101        console.log("MainAbility onForeground")
102    }
103
104    onBackground() {
105        console.log("MainAbility onBackground")
106    }
107   }
108   ```
109### 获取AbilityStage及Ability的配置信息
110AbilityStage类及Ability类均拥有context属性,应用可以通过`this.context`获取Ability实例的上下文,进而获取详细的配置信息。
111如下示例展示了AbilityStage通过context属性获取包代码路径、hap包名、ability名以及系统语言的方法。具体示例代码如下:
112```ts
113import AbilityStage from "@ohos.application.AbilityStage"
114export default class MyAbilityStage extends AbilityStage {
115    onCreate() {
116        console.log("MyAbilityStage onCreate")
117        let context = this.context
118        console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir)
119
120        let currentHapModuleInfo = context.currentHapModuleInfo
121        console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name)
122        console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName)
123
124        let config = this.context.config
125        console.log("MyAbilityStage config language" + config.language)
126    }
127}
128```
129
130如下示例展示了Ability通过context属性获取包代码路径、hap包名、ability名以及系统语言的方法。具体示例代码如下:
131```ts
132import Ability from '@ohos.application.Ability'
133export default class MainAbility extends Ability {
134    onCreate(want, launchParam) {
135        console.log("MainAbility onCreate")
136        let context = this.context
137        console.log("MainAbility bundleCodeDir" + context.bundleCodeDir)
138
139        let abilityInfo = this.context.abilityInfo;
140        console.log("MainAbility ability bundleName" + abilityInfo.bundleName)
141        console.log("MainAbility ability name" + abilityInfo.name)
142
143        let config = this.context.config
144        console.log("MainAbility config language" + config.language)
145    }
146}
147```
148### 应用向用户申请授权
149应用需要获取用户的隐私信息或使用系统能力时,比如获取位置信息、使用相机拍摄照片或录制视频等,需要向用户申请授权。在开发过程中,首先需要明确涉及的敏感权限并在module.json5中声明需要的权限,同时通过接口`requestPermissionsFromUser`以动态弹窗的方式向用户申请授权。以访问日历为例,具体示例代码如下:
150
151module.json5声明需要的权限:
152```json
153"requestPermissions": [
154    {
155    "name": "ohos.permission.READ_CALENDAR"
156    }
157]
158```
159通过动态弹窗向用户申请授权:
160```ts
161let context = this.context
162let permissions: Array<string> = ['ohos.permission.READ_CALENDAR']
163context.requestPermissionsFromUser(permissions).then((data) => {
164    console.log("Succeed to request permission from user with data: " + JSON.stringify(data))
165}).catch((error) => {
166    console.log("Failed to request permission from user with error: " + JSON.stringify(error))
167})
168```
169### 系统环境变化通知
170环境变化,包括全局配置的变化和Ability配置的变化。全局配置指全局的、系统的配置,目前包括“语言”和“颜色模式”,全局配置的变化一般由“设置”中的配置项或“控制中心”中的图标触发。Ability配置指与单个Ability实例相关的配置,目前包括“displayId”、“屏幕分辨率”,“横竖屏”,这些配置与Ability所在的Display有关,Ability配置的变化一般由窗口触发。配置项目前均定义在[Configuration](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-configuration.md)类中。
171
172对于Stage模型的应用,配置发生变化时,不会重启Ability,会触发应用的`onConfigurationUpdated(config: Configuration)`回调,若应用希望根据配置变化做相应处理,可以重写`onConfigurationUpdated`回调,若无需处理配置变化,则可以不必实现`onConfigurationUpdated`回调。应该注意的是,回调中的Configuration对象包括当前Ability所有的配置,不仅是发生变化的配置。
173
174如下示例展示了AbilityStage的`onConfigurationUpdated`回调实现,系统语言和颜色模式发生变化时触发该回调。具体示例代码如下:
175```ts
176import Ability from '@ohos.application.Ability'
177import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
178
179export default class MyAbilityStage extends AbilityStage {
180    onConfigurationUpdated(config) {
181        if (config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
182            console.log('colorMode changed to dark')
183        }
184    }
185}
186```
187
188如下示例展示了Ability的`onConfigurationUpdated`回调实现,系统语言、颜色模式以及Display相关的参数,比如方向、Density,发生变化时触发该回调。具体示例代码如下:
189```ts
190import Ability from '@ohos.application.Ability'
191import ConfigurationConstant from '@ohos.application.ConfigurationConstant'
192
193export default class MainAbility extends Ability {
194    direction : number;
195
196    onCreate(want, launchParam) {
197        this.direction = this.context.config.direction
198    }
199
200    onConfigurationUpdated(config) {
201        if (this.direction !== config.direction) {
202            console.log(`direction changed to ${config.direction}`)
203        }
204    }
205}
206```
207## 启动Ability
208### 接口说明
209Ability类拥有context属性,context属性为AbilityContext类,AbilityContext类拥有abilityInfo、currentHapModuleInfo等属性,启动Ability等方法。具体的API详见[接口文档](../reference/apis/js-apis-ability-context.md)。
210
211**表3** AbilityContext API接口功能介绍
212|接口名|描述|
213|:------|:------|
214|startAbility(want: Want, callback: AsyncCallback\<void>): void|启动Ability。|
215|startAbility(want: Want, options?: StartOptions): Promise\<void>|启动Ability。|
216|startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback\<void>): void|带AccountId启动Ability。|
217|startAbilityWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\<void>|带AccountId启动Ability。|
218|startAbilityForResult(want: Want, callback: AsyncCallback\<AbilityResult>): void|带返回结果启动Ability。|
219|startAbilityForResult(want: Want, options?: StartOptions): Promise\<AbilityResult>|带返回结果启动Ability。|
220|startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback\<AbilityResult>): void|带返回结果及AccountId启动Ability。|
221|startAbilityForResultWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\<AbilityResult>|带返回结果及AccountId启动Ability。|
222### 相同设备启动Ability
223应用可以通过`this.context`获取Ability实例的上下文,进而使用AbilityContext中的StartAbility相关接口启动Ability。启动Ability可指定Want、StartOptions、accountId,通过callback形式或promise形式实现。具体示例代码如下:
224```ts
225let context = this.context
226var want = {
227    "deviceId": "",
228    "bundleName": "com.example.MyApplication",
229    "abilityName": "MainAbility"
230};
231context.startAbility(want).then(() => {
232    console.log("Succeed to start ability")
233}).catch((error) => {
234    console.error("Failed to start ability with error: "+ JSON.stringify(error))
235})
236```
237
238### 跨设备启动Ability(当前仅对系统应用开放)
239>说明:由于DeviceManager的getTrustedDeviceListSync接口仅对系统应用开放,当前跨设备启动Ability仅支持系统应用
240跨设备场景下,需指定对端设备deviceId,具体示例代码如下:
241```ts
242let context = this.context
243var want = {
244    "deviceId": getRemoteDeviceId(),
245    "bundleName": "com.example.MyApplication",
246    "abilityName": "MainAbility"
247};
248context.startAbility(want).then(() => {
249    console.log("Succeed to start remote ability")
250}).catch((error) => {
251    console.error("Failed to start remote ability with error: " + JSON.stringify(error))
252})
253```
254从DeviceManager获取指定设备的deviceId。具体示例代码如下:
255```ts
256import deviceManager from '@ohos.distributedHardware.deviceManager';
257function getRemoteDeviceId() {
258    if (typeof dmClass === 'object' && dmClass != null) {
259        var list = dmClass.getTrustedDeviceListSync();
260        if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
261            console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
262            return;
263        }
264        console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
265        return list[0].deviceId;
266    } else {
267        console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
268    }
269}
270```
271向用户申请数据同步'ohos.permission.DISTRIBUTED_DATASYNC'的权限。申请授权示例代码见[应用向用户申请授权](###应用向用户申请授权)。
272### 指定页面启动Ability
273当Ability的启动模式设置为单例时,若Ability已被拉起,再次启动Ability,不会触发onCreate,只会触发onNewWant回调。应用开发者可以通过want传递启动参数,比如希望指定页面启动Ability,可以通过want中的uri参数或parameters参数传递pages信息。目前,Stage模型中Ability暂时无法直接使用router的能力,可以将启动参数传递给自定义组件,在自定义组件的生命周期中调用router接口显示指定页面。具体示例代码如下:
274
275使用startAbility再次拉起Ability,通过want中的uri参数传递页面信息:
276```ts
277async function reStartAbility() {
278  try {
279    await this.context.startAbility({
280      bundleName: "com.sample.MyApplication",
281      abilityName: "MainAbility",
282      uri: "pages/second"
283    })
284    console.log('start ability succeed')
285  } catch (error) {
286    console.error(`start ability failed with ${error.code}`)
287  }
288}
289```
290
291在Ability的onNewWant回调中获取包含页面信息的want参数:
292```ts
293import Ability from '@ohos.application.Ability'
294
295export default class MainAbility extends Ability {
296  onNewWant(want) {
297    globalThis.newWant = want
298  }
299}
300```
301
302在自定义组件中获取包含页面信息的want参数并根据uri做路由处理:
303```ts
304import router from '@system.router'
305
306@Entry
307@Component
308struct Index {
309  newWant = undefined
310
311  onPageShow() {
312    console.info('Index onPageShow')
313    let newWant = globalThis.newWant
314    if (newWant.hasOwnProperty("uri")) {
315      router.push({ url: newWant.uri });
316      globalThis.newWant = undefined
317    }
318  }
319}
320```
321