OpenHarmony应用开发-PageAbility组件开发指导

素年锦时静待君丶
发布于 2023-4-10 17:35
浏览
0收藏

版本:v3.2 Beta5

PageAbility组件概述

PageAbility是包含UI界面、提供展示UI能力的应用组件,主要用于与用户交互。

开发者通过DevEco Studio开发平台创建PageAbility时,DevEco Studio会自动创建相关模板代码。PageAbility相关能力通过单独的featureAbility实现,生命周期相关回调则通过app.js/app.ets中各个回调函数实现。

PageAbility组件配置

PageAbility的相关配置在config.json配置文件的"module"对象的"abilities"对象中,"icon"属性表示Ability图标资源文件的索引,"lable"属性表示Ability对用户显示的名称,"skills"属性表示Ability能够接收的want的特征。

表1 PageAbility部分配置项说明

属性名称

含义

数据类型

是否可缺省

icon

表示Ability图标资源文件的索引。取值示例:$media:ability_icon。如果在该Ability的skills属性中,actions的取值包含 “action.system.home”,entities取值中包含"entity.system.home",则该Ability的icon将同时作为应用的icon。如果存在多个符合条件的Ability,则取位置靠前的Ability的icon作为应用的icon。

说明:应用的"icon"和"label"是用户可感知配置项,需要区别于当前所有已有的应用"icon"或"label"(至少有一个不同)。

字符串

可缺省,缺省值为空。

label

表示Ability对用户显示的名称。取值可以是Ability名称,也可以是对该名称的资源索引,以支持多语言。如果在该Ability的skills属性中,actions的取值包含 “action.system.home”,entities取值中包含"entity.system.home",则该Ability的label将同时作为应用的label。如果存在多个符合条件的Ability,则取位置靠前的Ability的label作为应用的label。

说明: 应用的"icon"和"label"是用户可感知配置项,需要区别于当前所有已有的应用"icon"或"label"(至少有一个不同)。该标签为资源文件中定义的字符串的引用,或以"{}"包括的字符串。该标签最大长度为255字节。

字符串

可缺省,缺省值为空。

skills

表示Ability能够接收的want的特征。

对象数组

可缺省,缺省值为空。

PageAbility的生命周期

PageAbility生命周期是PageAbility被调度到INACTIVE、ACTIVE、BACKGROUND等各个状态的统称。PageAbility生命周期流转及状态说明见如下图1、表1所示。

图1 PageAbility生命周期流转

OpenHarmony应用开发-PageAbility组件开发指导-鸿蒙开发者社区

表1 PageAbility生命周期状态说明

生命周期状态

生命周期状态说明

UNINITIALIZED

未初始状态,为临时状态,PageAbility被创建后会由UNINITIALIZED状态进入INITIAL状态。

INITIAL

初始化状态,也表示停止状态,表示当前PageAbility未运行,PageAbility被启动后由INITIAL态进入INACTIVE状态。

INACTIVE

失去焦点状态,表示当前窗口已显示但是无焦点状态。

ACTIVE

前台激活状态,表示当前窗口已显示,并获取焦点。

BACKGROUND

后台状态,表示当前PageAbility退到后台,PageAbility在被销毁后由BACKGROUND状态进入INITIAL状态,或者重新被激活后由BACKGROUND状态进入ACTIVE状态。

应用开发者可以在app.js/app.ets中重写生命周期相关回调函数,PageAbility生命周期相关回调函数见下表。

表2 PageAbility生命周期回调接口说明

接口名

接口描述

onCreate()

Ability第一次启动创建Ability时调用onCreate方法,开发者可以在该方法里做一些应用初始化工作。

onDestroy()

应用退出,销毁Ability对象前调用onDestroy方法,开发者可以在该方法里做一些回收资源、清空缓存等应用退出前的准备工作。

onActive()

Ability切换到前台,并且已经获取焦点时调用onActive方法。

onInactive()

Ability失去焦点时调用onInactive方法,Ability在进入后台状态时会先失去焦点,再进入后台。

onShow()

Ability由后台不可见状态切换到前台可见状态调用onShow方法,此时用户在屏幕可以看到该Ability。

onHide()

Ability由前台切换到后台不可见状态时调用onHide方法,此时用户在屏幕看不到该Ability。

PageAbility生命周期回调与生命周期状态的关系如下图所示。

图2 PageAbility生命周期回调与生命周期状态的关系

OpenHarmony应用开发-PageAbility组件开发指导-鸿蒙开发者社区

说明: 

1、PageAbility的生命周期回调均为同步接口。

2、目前app.js环境中仅支持onCreate和onDestroy回调,app.ets环境支持全量生命周期回调。

PageAbility的启动模式

启动模式对应PageAbility被启动时的行为,支持单实例模式、标准模式两种启动模式。

表1 PageAbility的启动模式

启动模式

描述

说明

singleton

单实例模式

每次调用startAbility方法时,如果应用进程中该类型的Ability实例已经存在,则复用已有的实例,系统中只存在唯一一个实例。表现为在最近任务列表中只有一个Ability实例。

典型场景:当用户打开视频播放应用并观看视频,回到桌面后,再次打开视频播放应用,应用仍为回到桌面之前正在观看的视频。

standard

标准模式

缺省启动模式。每次调用startAbility方法时,都会在应用进程中创建一个新的Ability实例。表现为在最近任务列表中可以看到有多个该类型的Ability实例。

典型场景:当用户打开文档应用,选择新建文档的时候,每次点击新建文档,都会创建一个新的文档任务,在最近任务列表中可以看到多个新建的文档任务。

应用开发者可在config.json配置文件中通过“launchType”配置启动模式。示例如下:

{
  "module": {
    // ...
    "abilities": [
      {
        // singleton: 单实例模式
        // standard: 标准模式
        "launchType": "standard",
        // ...
      }
    ]
  }
}

启动PageAbility时,对于标准启动模式(多实例启动模式)以及单实例启动模式首次启动,​​PageAbility生命周期回调​​均会被触发。单实例非首次启动时不会再触发onCreate()接口,而是触发onNewWant(),onNewWant()的说明如下表2所示。

表2 单实例启动模式特有的回调函数说明

接口名

接口描述

onNewWant(want: Want)

单实例启动模式,PageAbility非首次启动时调用onNewWant方法,开发者可以在该方法中获取want,进而根据want做进一步处理。例如,单实例PageAbility迁移场景,指定页面拉起PageAbility场景。

创建PageAbility

开发者需要重写app.js/app.ets中的生命周期回调函数,开发者通过DevEco Studio开发平台创建PageAbility时,DevEco Studio会在app.js/app.ets中默认生成onCreate()和onDestroy()方法,其他方法需要开发者自行实现。接口说明参见前述章节,创建PageAbility示例如下:

export default {
  onCreate() {
    console.info('Application onCreate')
  },
  onDestroy() {
    console.info('Application onDestroy')
  },
  onShow() {
    console.info('Application onShow')
  },
  onHide() {
    console.info('Application onHide')
  },
  onActive() {
    console.info('Application onActive')
  },
  onInactive() {
    console.info('Application onInactive')
  },
  onNewWant() {
    console.info('Application onNewWant')
  },
}

PageAbility创建成功后,其abilities相关的配置项在config.json中体现,一个名字为MainAbility的config.json配置文件示例如下:

{
  "abilities": [
    {
      "skills": [
        {
          "entities": [
            "entity.system.home"
          ],
          "actions": [
            "action.system.home"
          ]
        }
      ],
      "orientation": "unspecified",
      "visible": true,
      "srcPath": "MainAbility",
      "name": ".MainAbility",
      "srcLanguage": "ets",
      "icon": "$media:icon",
      "description": "$string:MainAbility_desc",
      "formsEnabled": false,
      "label": "$string:MainAbility_label",
      "type": "page",
      "launchType": "singleton"
    }
  ]
}

FA模型中,可以通过featureAbility的getContext接口获取应用上下文,进而使用上下文提供的能力。

表1 featureAbility接口说明

接口名

接口描述

getContext()

获取应用上下文。

通过getContext获取应用上下文并获取分布式目录的示例如下:

import featureAbility from '@ohos.ability.featureAbility'
import fileIo from '@ohos.fileio'

(async () => {
  let dir: string
  try {
    console.info('Begin to getOrCreateDistributedDir')
    dir = await featureAbility.getContext().getOrCreateDistributedDir()
    console.info('distribute dir is ' + dir)
  } catch (error) {
    console.error('getOrCreateDistributedDir failed with ' + error)
  }

  let fd: number;
  let path = dir + "/a.txt";
  fd = fileIo.openSync(path, 0o2 | 0o100, 0o666);
  fileIo.close(fd);
})()

启动本地PageAbility

PageAbility相关的能力通过featureAbility提供,启动本地Ability通过featureAbility中的startAbility接口实现。

表1 featureAbility接口说明

接口名

接口描述

startAbility(parameter: StartAbilityParameter)

启动Ability。

startAbilityForResult(parameter: StartAbilityParameter)

启动Ability,并在该Ability被销毁时返回执行结果。

如下示例通过startAbility显式启动PageAbility。启动Ability的参数包含want,关于want的说明详见​​对象间信息传递载体Want​​,相应的,隐式启动与显式启动也不在此赘述。

import featureAbility from '@ohos.ability.featureAbility'
(async () => {
  try {
    console.info('Begin to start ability')
    let param = {
      want: {
        bundleName: "com.example.myapplication",
        moduleName: "entry",
        abilityName: "com.example.myapplication.MainAbility"
      }
    }
    await featureAbility.startAbility(param)
    console.info(`Start ability succeed`)
  } 
  catch (error) {
    console.error('Start ability failed with ' + error)
  }
})()

停止PageAbility

停止PageAbility通过featureAbility中的terminateSelf接口实现。

表1 featureAbility接口说明

接口名

接口描述

terminateSelf()

停止Ability。

terminateSelfWithResult(parameter: AbilityResult)

设置该PageAbility停止时返回给调用者的结果及数据并停止Ability。

如下示例展示了停止Ability的方法。

import featureAbility from '@ohos.ability.featureAbility'

(async () => {
  try {
    console.info('Begin to terminateSelf')
    await featureAbility.terminateSelf()
    console.info('terminateSelf succeed')
  } 
  catch (error) {
    console.error('terminateSelf failed with ' + error)
  }
})()

启动远程PageAbility(仅对系统应用开放)

启动远程PageAbility同样通过featureAbility中的startAbility接口实现。

除引入’@ohos.ability.featureAbility’外,还需引入’@ohos.distributedHardware.deviceManager’,通过DeviceManager(该组件在OpenHarmony上提供帐号无关的分布式设备的认证组网能力)的getTrustedDeviceListSync接口(获取信任设备列表)获取远端的deviceId,写入want中,用于启动远程PageAbility。

由于当前DeviceManager的getTrustedDeviceListSync接口仅对系统应用开放,故现阶段非系统应用无法获取其他设备信息,无远程启动设备选择入口,远程启动Ability开发。

表1 featureAbility接口说明

接口名

接口描述

startAbility(parameter: StartAbilityParameter)

启动Ability。

startAbilityForResult(parameter: StartAbilityParameter)

启动Ability,并在该Ability被销毁时返回执行结果。

表2 deviceManager接口说明

接口名

接口描述

getTrustedDeviceListSync(): Array<DeviceInfo>

同步获取所有可信设备列表。

在跨设备场景下,启动远程PageAbility首先需要向用户申请数据同步的权限,相关接口说明如下:

表3 AtManager接口说明

接口名

接口描述

checkAccessToken(tokenID: number, permissionName: string)

: Promise<GrantStatus>

校验应用是否授予权限。使用Promise异步回调。返回值GrantStatus。建议使用checkAccessToken代替verifyAccessToken(已废弃),verifyAccessToken从API version 9开始不再维护。

表4 context接口说明

接口名

接口描述

requestPermissionsFromUser(permissions: Array<string>, 

requestCode: number, resultCallback: AsyncCallback<

PermissionRequestResult>): void

以callback形式从系统请求某些权限,详见对应​​接口文档​​。

如下示例代码展示了向用户申请数据同步权限的方法:

import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import featureAbility from '@ohos.ability.featureAbility';
import bundle from '@ohos.bundle.bundleManager';
async function RequestPermission() {
  console.info('RequestPermission begin');
  let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];
  let bundleFlag = 0;
  let tokenID = undefined;
  let userID = 100;
  let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID);
  tokenID = appInfo.accessTokenId;
  let atManager = abilityAccessCtrl.createAtManager();
  let requestPermissions: Array<string> = [];
  for (let i = 0;i < array.length; i++) {
    let result = await atManager.verifyAccessToken(tokenID, array[i]);
    console.info("checkAccessToken result:" + JSON.stringify(result));
    if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      requestPermissions.push(array[i]);
    }
  }
  console.info("requestPermissions:" + JSON.stringify(requestPermissions));
  if (requestPermissions.length == 0 || requestPermissions == []) {
    return;
  }
  let context = featureAbility.getContext();
  context.requestPermissionsFromUser(requestPermissions, 1, (error, data)=>{
    console.info("data:" + JSON.stringify(data));
    console.info("data requestCode:" + data.requestCode);
    console.info("data permissions:" + data.permissions);
    console.info("data authResults:" + data.authResults);
  });
  console.info('RequestPermission end');
}

在获取数据同步权限后,需要获取可信设备列表,进行设备选择。

如下示例展示了通过getTrustedDeviceListSync获取可信设备列表,选择设备的方法。

import deviceManager from '@ohos.distributedHardware.deviceManager';  
let dmClass;  
function getDeviceManager() {
    deviceManager.createDeviceManager('ohos.example.distributedService', (error, dm) => {
        if (error) {
            console.info('create device manager failed with ' + error)
        }
        dmClass = dm;
    })
}
function getRemoteDeviceId() {      
    if (typeof dmClass === 'object' && dmClass != null) {          
        let list = dmClass.getTrustedDeviceListSync();          
        if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {            
            console.info("MainAbility onButtonClick getRemoteDeviceId err: list is null");            
            return;          
        }          
        console.info("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);          
        return list[0].deviceId;      
    } else {          
        console.info("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");      
    }  
}

设备选择完成后,通过调用startAbility接口,显式启动远程PageAbility。

如下示例展示了通过startAbility显式启动远程PageAbility的方法。

import featureAbility from '@ohos.ability.featureAbility';
function onStartRemoteAbility() {  
    console.info('onStartRemoteAbility begin');  
    let params;  
    let wantValue = {      
        bundleName: 'ohos.samples.etsDemo',      
        abilityName: 'ohos.samples.etsDemo.RemoteAbility',      
        deviceId: getRemoteDeviceId(), // getRemoteDeviceId的定义在前面的示例代码中
        parameters: params  
    };  
    console.info('onStartRemoteAbility want=' + JSON.stringify(wantValue));  
    featureAbility.startAbility({      
        want: wantValue  
    }).then((data) => {      
        console.info('onStartRemoteAbility finished, ' + JSON.stringify(data));  
    });  
    console.info('onStartRemoteAbility end');  
}

启动指定页面

当PageAbility的启动模式设置为单例时(具体设置方法和典型场景示例见​​PageAbility的启动模式​​,缺省情况下是单实例模式),若PageAbility已被拉起,再次启动PageAbility会触发onNewWant回调(即非首次拉起)。应用开发者可以通过want传递启动参数,例如开发者希望指定页面启动PageAbility,可以通过want中的parameters参数传递pages信息,具体示例代码如下:

调用方PageAbility的app.ets中或者page中,使用startAbility再次拉起PageAbility,通过want中的uri参数传递页面信息:

import featureAbility from '@ohos.ability.featureAbility';

async function restartAbility() {
    let wantInfo = {
        bundleName: "com.sample.MyApplication",
        abilityName: "MainAbility",
        parameters: {
            page: "pages/second"
        }
    };
    featureAbility.startAbility({
        want: wantInfo
    }).then((data) => {
        console.info('restartAbility success.');
    });
}

在目标端PageAbility的onNewWant回调中获取包含页面信息的want参数:

export default {  
    onNewWant(want) {    
        globalThis.newWant = want  
    }
}

在目标端页面的自定义组件中获取包含页面信息的want参数并根据uri做路由处理:

import router from '@ohos.router'
@Entry
@Component
struct Index {
  @State message: string = 'Router Page'
  newWant = undefined
  onPageShow() {
    console.info('Index onPageShow')
    let newWant = globalThis.newWant
    if (newWant.hasOwnProperty("page")) {
      router.push({ url: newWant.page });
      globalThis.newWant = undefined
    }
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

当PageAbility的启动模式设置为标准模式或为首次启动单例模式的PageAbility时(具体设置方法和典型场景示例见​​PageAbility的启动模式​​),在调用方PageAbility中,通过want中的parameters参数传递要启动的指定页面的pages信息,调用startAbility()方法启动PageAbility。被调用方可以在onCreate中使用featureAbility的getWant方法获取want,再通过调用router.push实现启动指定页面。

调用方的页面中实现按钮点击触发startAbility方法启动目标端PageAbility,startAbility方法的入参want中携带指定页面信息,示例代码如下:

import featureAbility from '@ohos.ability.featureAbility'
@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    // ...
    Button("startAbility")
      .onClick(() => {
        featureAbility.startAbility({
          want: {
            bundleName: "com.exm.myapplication",
            abilityName: "com.exm.myapplication.MainAbility",
            parameters: { page: "pages/page1" }
          }
        }).then((data) => {
          console.info("startAbility finish");
        }).catch((err) => {
          console.info("startAbility failed errcode:" + err.code)
        })
      })
    // ...
    Button("page2")
      .onClick(() => {
        featureAbility.startAbility({
          want: {
            bundleName: "com.exm.myapplication",
            abilityName: "com.exm.myapplication.MainAbility",
            parameters: { page: "pages/page2" }
          }
        }).then((data) => {
          console.info("startAbility finish");
        }).catch((err) => {
          console.info("startAbility failed errcode:" + err.code)
        })
      })
    // ...
  }
}

目标端PageAbility的onCreate生命周期回调中通过featureAbility的getWant方法获取want,并对参数进行解析,实现指定页面拉起:

import featureAbility from '@ohos.ability.featureAbility';
import router from '@ohos.router';

export default {
  onCreate() {
    featureAbility.getWant().then((want) => {
      if (want.parameters.page) {
        router.push({
          url: want.parameters.page
        })
      }
    })
  },
  onDestroy() {
    // ...
  },
}

窗口属性

具体获取窗口实例、设置窗口属性的接口描述及示例见​​接口文档​​。

申请授权

应用需要获取用户的隐私信息或使用系统能力时,例如获取位置信息、使用相机拍摄照片或录制视频等,需要向用户申请授权。

在开发过程中,首先需要明确涉及的敏感权限并在config.json中声明需要的权限,同时通过接口requestPermissionsFromUser以动态弹窗的方式向用户申请授权。

在config.json声明需要的权限,在module下添加"reqPermissions",并写入对应权限。

如申请访问日历权限,需要申请​​ohos.permission.READ_CALENDAR​​​权限,配置方式请参阅​​访问控制授权申请指导​​。

对应config.json文件的示例代码如下所示:

{
  "module": {
    // ...
    "reqPermissions": [
      {
        "name": "ohos.permission.READ_CALENDAR"
        // ...
      }
    ]
  }
}

通过动态弹窗向用户申请授权:

import featureAbility from '@ohos.ability.featureAbility';

let context = featureAbility.getContext();  
let permissions: Array<string> = ['ohos.permission.READ_CALENDAR']
context.requestPermissionsFromUser(permissions, 1).then((data) => {    
    console.info("Succeed to request permission from user with data: " + JSON.stringify(data))
}).catch((error) => {    
    console.info("Failed to request permission from user with error: " + JSON.stringify(error))
})

跳转规则

一般情况下,应用中的界面跳转由用户触发,应用本身通过startAbility启动跳转其他界面。

PageAbility作为可见Ability,可以通过startAbility启动有界面的且对外可见的Ability。

应用可通过在config.json中设置"abilities"中的"visible"属性设置Ability是否可由其他应用的组件启动,"visible"属性的具体参数和意义如下表所示。

表1 visible属性说明

属性名称

描述

是否可缺省

visible

表示Ability是否可以被其他应用调用。

true:该Ability可以被任何应用调用。

false:该Ability只能被同一应用的其他组件调用。

可缺省,缺省时默认属性值为"false"。

如果需设置当前Ability可由任何应用访问,对应config.json文件的示例代码如下所示:

{
  "module": {
    // ...
    "abilities": [
      {
        "visible": "true",
        // ...
      }
    ]
  }
}

如果应用中的Ability包含skills过滤器,建议此属性设置为"true",以允许其他应用通过​​隐式调用​​​启动该Ability。如果此属性设为"false",其他应用尝试启动该Ability时系统会返回PERMISSION_DENIED。这种情况下系统应用可以通过申请​​START_INVISIBLE_ABILITY​​权限启动visible为false的组件,例如系统桌面、语音助手、搜索助手等。




文章转载自:​​https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/application-models/redirection-rules.md/​

已于2023-4-10 17:35:17修改
收藏
回复
举报
回复
    相关推荐