1# Ability开发指导 2## 场景介绍 3Stage模型是区别于FA模型的一种应用开发模型,对此模型的介绍详见[Stage模型综述](stage-brief.md)。开发Stage模型应用时,需要在module.json5和app.json5配置文件中对应用的包结构进行声明,对应用包结构配置文件的说明详见[应用包结构配置文件的说明](../quick-start/application-package-structure-stage.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| multiton | 多实例模式 | 每次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-app-ability-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|:------|:------| 48|onCreate(want: Want, param: AbilityConstant.LaunchParam): void|Ability生命周期回调,Ability启动时被调用。| 49|onDestroy(): void|Ability生命周期回调,Ability销毁时被调用。| 50|onWindowStageCreate(windowStage: window.WindowStage): void|Ability生命周期回调,创建window stage时被调用,应用开发者可通过window.WindowStage的接口执行页面加载等操作。| 51|onWindowStageDestroy(): void|Ability生命周期回调,销毁window stage时被调用。| 52|onForeground(): void|Ability生命周期回调,Ability切换至前台时被调用。| 53|onBackground(): void|Ability生命周期回调,Ability切换至后台时被调用。| 54|onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void|Ability回调,Ability的启动模式设置为单例时被调用。| 55|onConfigurationUpdated(config: Configuration): void|Ability回调,Ability的系统配置更新时被调用。| 56### 实现AbilityStage及Ability生命周期 57创建Stage模型的Page Ability应用,需实现AbilityStage接口及Ability生命周期接口,并使用窗口提供的方法设置页面。具体示例代码如下: 581. 导入AbilityStage模块。 59 ``` 60 import AbilityStage from "@ohos.application.AbilityStage" 61 ``` 622. 实现AbilityStage接口,接口生成的默认相对路径:entry\src\main\ets\Application\AbilityStage.ts。 63 ```ts 64 export default class MyAbilityStage extends AbilityStage { 65 onCreate() { 66 console.log("MyAbilityStage onCreate") 67 } 68 } 69 ``` 703. 导入Ability模块。 71 ```js 72 import Ability from '@ohos.application.Ability' 73 ``` 744. 实现Ability生命周期接口,接口默认生成的相对路径:entry\src\main\ets\MainAbility\MainAbility.ts。 75 76 在`onWindowStageCreate(windowStage)`中通过loadContent接口设置应用要加载的页面,window接口的使用详见[窗口开发指导](../windowmanager/application-window-stage.md)。 77 ```ts 78 export default class MainAbility extends Ability { 79 onCreate(want, launchParam) { 80 console.log("MainAbility onCreate") 81 } 82 83 onDestroy() { 84 console.log("MainAbility onDestroy") 85 } 86 87 onWindowStageCreate(windowStage) { 88 console.log("MainAbility onWindowStageCreate") 89 90 windowStage.loadContent("pages/index").then(() => { 91 console.log("MainAbility load content succeed") 92 }).catch((error) => { 93 console.error("MainAbility load content failed with error: " + JSON.stringify(error)) 94 }) 95 } 96 97 onWindowStageDestroy() { 98 console.log("MainAbility onWindowStageDestroy") 99 } 100 101 onForeground() { 102 console.log("MainAbility onForeground") 103 } 104 105 onBackground() { 106 console.log("MainAbility onBackground") 107 } 108 } 109 ``` 110### 获取AbilityStage及Ability的配置信息 111AbilityStage类及Ability类均拥有context属性,应用可以通过`this.context`获取Ability实例的上下文,进而获取详细的配置信息。 112 113如下示例展示了AbilityStage通过context属性获取包代码路径、hap包名、Ability名以及系统语言的方法。具体示例代码如下: 114 115```ts 116import AbilityStage from "@ohos.application.AbilityStage" 117export default class MyAbilityStage extends AbilityStage { 118 onCreate() { 119 console.log("MyAbilityStage onCreate") 120 let context = this.context 121 console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir) 122 123 let currentHapModuleInfo = context.currentHapModuleInfo 124 console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name) 125 console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName) 126 127 let config = this.context.config 128 console.log("MyAbilityStage config language" + config.language) 129 } 130} 131``` 132 133如下示例展示了Ability通过context属性获取包代码路径、hap包名、Ability名以及系统语言的方法。具体示例代码如下: 134```ts 135import Ability from '@ohos.application.Ability' 136export default class MainAbility extends Ability { 137 onCreate(want, launchParam) { 138 console.log("MainAbility onCreate") 139 let context = this.context 140 console.log("MainAbility bundleCodeDir" + context.bundleCodeDir) 141 142 let abilityInfo = this.context.abilityInfo; 143 console.log("MainAbility ability bundleName" + abilityInfo.bundleName) 144 console.log("MainAbility ability name" + abilityInfo.name) 145 146 let config = this.context.config 147 console.log("MainAbility config language" + config.language) 148 } 149} 150``` 151### 系统环境变化通知 152环境变化,包括全局配置的变化和Ability配置的变化。全局配置指全局的、系统的配置,目前包括“语言”和“颜色模式”,全局配置的变化一般由“设置”中的配置项或“控制中心”中的图标触发。Ability配置指与单个Ability实例相关的配置,目前包括“displayId”(物理屏幕Id)、“屏幕分辨率”,“横竖屏”,这些配置与Ability所在的Display有关,Ability配置的变化一般由窗口触发。配置项目前均定义在[Configuration](../reference/apis/js-apis-application-configuration.md)类中。 153 154对于Stage模型的应用,配置发生变化时,不会重启Ability,会触发应用的`onConfigurationUpdated(config: Configuration)`回调,若应用希望根据配置变化做相应处理,可以重写`onConfigurationUpdated`回调,若无需处理配置变化,则可以不必实现`onConfigurationUpdated`回调。应该注意的是,回调中的Configuration对象包括当前Ability所有的配置,不仅是发生变化的配置。 155 156如下示例展示了AbilityStage的`onConfigurationUpdated`回调实现,系统语言和颜色模式发生变化时触发该回调。具体示例代码如下: 157```ts 158import AbilityStage from '@ohos.application.AbilityStage' 159import ConfigurationConstant from '@ohos.application.ConfigurationConstant' 160 161export default class MyAbilityStage extends AbilityStage { 162 onConfigurationUpdated(config) { 163 if (config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) { 164 console.log('colorMode changed to dark') 165 } 166 } 167} 168``` 169 170如下示例展示了Ability的`onConfigurationUpdated`回调实现,系统语言、颜色模式以及Display相关的参数,比如方向、Density,发生变化时触发该回调。具体示例代码如下: 171```ts 172import Ability from '@ohos.application.Ability' 173import ConfigurationConstant from '@ohos.application.ConfigurationConstant' 174 175export default class MainAbility extends Ability { 176 direction : number; 177 178 onCreate(want, launchParam) { 179 this.direction = this.context.config.direction 180 } 181 182 onConfigurationUpdated(config) { 183 if (this.direction !== config.direction) { 184 console.log(`direction changed to ${config.direction}`) 185 } 186 } 187} 188``` 189## 启动Ability 190### 接口说明 191Ability类拥有context属性,context属性为AbilityContext类,AbilityContext类拥有abilityInfo、currentHapModuleInfo等属性,启动Ability等方法。具体的API详见[接口文档](../reference/apis/js-apis-inner-application-applicationContext.md)。 192 193**表3** AbilityContext API接口功能介绍 194|接口名|描述| 195|:------|:------| 196|startAbility(want: Want, callback: AsyncCallback\<void>): void|启动Ability。| 197|startAbility(want: Want, options?: StartOptions): Promise\<void>|启动Ability。| 198|startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback\<void>): void|带AccountId启动Ability。| 199|startAbilityWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\<void>|带AccountId启动Ability。| 200|startAbilityForResult(want: Want, callback: AsyncCallback\<AbilityResult>): void|带返回结果启动Ability。| 201|startAbilityForResult(want: Want, options?: StartOptions): Promise\<AbilityResult>|带返回结果启动Ability。| 202|startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback\<AbilityResult>): void|带返回结果及AccountId启动Ability。| 203|startAbilityForResultWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\<AbilityResult>|带返回结果及AccountId启动Ability。| 204### 相同设备启动Ability 205应用可以通过`this.context`获取Ability实例的上下文,进而使用AbilityContext中的StartAbility相关接口启动Ability。启动Ability可指定Want、StartOptions、accountId,通过callback形式或promise形式实现。具体示例代码如下: 206```ts 207let context = this.context 208var want = { 209 "deviceId": "", 210 "bundleName": "com.example.MyApplication", 211 "abilityName": "MainAbility" 212}; 213context.startAbility(want).then(() => { 214 console.log("Succeed to start ability") 215}).catch((error) => { 216 console.error("Failed to start ability with error: "+ JSON.stringify(error)) 217}) 218``` 219 220### 跨设备启动Ability(当前仅对系统应用开放) 221>说明:由于DeviceManager的getTrustedDeviceListSync接口仅对系统应用开放,当前跨设备启动Ability仅支持系统应用 222跨设备场景下,需指定对端设备deviceId,具体示例代码如下: 223```ts 224let context = this.context 225var want = { 226 "deviceId": getRemoteDeviceId(), 227 "bundleName": "com.example.MyApplication", 228 "abilityName": "MainAbility" 229}; 230context.startAbility(want).then(() => { 231 console.log("Succeed to start remote ability") 232}).catch((error) => { 233 console.error("Failed to start remote ability with error: " + JSON.stringify(error)) 234}) 235``` 236从DeviceManager获取指定设备的deviceId。具体示例代码如下: 237```ts 238import deviceManager from '@ohos.distributedHardware.deviceManager'; 239function getRemoteDeviceId() { 240 if (typeof dmClass === 'object' && dmClass != null) { 241 var list = dmClass.getTrustedDeviceListSync(); 242 if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { 243 console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); 244 return; 245 } 246 console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); 247 return list[0].deviceId; 248 } else { 249 console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); 250 } 251} 252``` 253向用户申请数据同步'ohos.permission.DISTRIBUTED_DATASYNC'的权限。申请授权示例代码见[abilityAccessCtrl.requestPermissionsFromUse](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)。 254### 指定页面启动Ability 255当Ability的启动模式设置为单例时,若Ability已被拉起,再次启动Ability会触发onNewWant回调。应用开发者可以通过want传递启动参数,比如希望指定页面启动Ability,可以通过want中的uri参数或parameters参数传递pages信息。目前,Stage模型中Ability暂时无法直接使用router的能力,可以将启动参数传递给自定义组件,在自定义组件的生命周期中调用router接口显示指定页面。具体示例代码如下: 256 257使用startAbility再次拉起Ability,通过want中的uri参数传递页面信息: 258```ts 259async function reStartAbility() { 260 try { 261 await this.context.startAbility({ 262 bundleName: "com.sample.MyApplication", 263 abilityName: "MainAbility", 264 uri: "pages/second" 265 }) 266 console.log('start ability succeed') 267 } catch (error) { 268 console.error(`start ability failed with ${error.code}`) 269 } 270} 271``` 272 273在Ability的onNewWant回调中获取包含页面信息的want参数: 274```ts 275import Ability from '@ohos.application.Ability' 276 277export default class MainAbility extends Ability { 278 onNewWant(want, launchParams) { 279 globalThis.newWant = want 280 } 281} 282``` 283 284在自定义组件中获取包含页面信息的want参数并根据uri做路由处理: 285```ts 286import router from '@ohos.router' 287 288@Entry 289@Component 290struct Index { 291 newWant = undefined 292 293 onPageShow() { 294 console.info('Index onPageShow') 295 let newWant = globalThis.newWant 296 if (newWant.hasOwnProperty("uri")) { 297 router.push({ url: newWant.uri }); 298 globalThis.newWant = undefined 299 } 300 } 301} 302``` 303 304## 相关实例 305 306基于Stage模型下的Ability开发,有以下相关实例可供参考: 307 308- [Ability内和Ability间页面的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/StageAbility) 309 310- [Stage模型下Ability的创建和使用(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/StageAbilityDemo) 311 312- [Ability内页面间的跳转(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Ability/PagesRouter)