本文将介绍 OpenHarmony 中北向应用实现页面跳转的几种方式,涵盖了目前 (OpenHarmony v3.2) 常见的所有方法,开发者可以根据场景需求自行选择。

OpenHarmony 迭代迅速,版本间差异巨大。实际开发时,请确认设备的支持能力以及官方最新文档。

页面路由

@ohos.router (页面路由) 本模块从 API Version 8 开始支持。

@system.router (页面路由) 自 API Version 8 开始,该接口不再维护,推荐使用新接口 @ohos.router

这种方式只适用于在单一 Ability 内部的页面间跳转,不支持跨 Ability。

但这种方式的使用场景十分常见,例如点击查看详情 (router.push) 并返回 (router.back)。

导入模块

import router from '@ohos.router'

@ohos.router 模块中最常用的就是 router.pushrouter.backrouter.getParams

  • router.push 用于跳转到应用内的指定页面。
  • router.back 返回上一页面或指定的页面。
  • router.getParams 获取发起跳转的页面往当前页传入的参数。

除此之外,某些情况下也会使用 router.clear。(清空页面栈中的所有历史页面,仅保留当前页面作为栈顶页面)

完整示例请见 GitHub 仓库,如果文章对您有所帮助的话,不妨点个 Star 再走。

// MainAbility Index Page

import router from '@ohos.router';

async routePage(url: string, params = {}) {
    let options = {
      url: url,
      params: params
    }
    try {
      await router.push(options)
    } catch (err) {
      console.info(`Fail in routePage(), code: ${err.code}, msg: ${err.msg}`)
    }
}

......

@Entry
@Component
struct Index {

    abilityName: string
    pageName: string

......

.onClick(() => this.routePage('pages/param', { data: `Route From ${this.abilityName} ${this.pageName}` }))

······

}
// MainAbility Param Page

import router from '@ohos.router';

......

@Entry
@Component
struct Index {

    @State data: number | string = router.getParams()['data']

......

.onClick(() => router.back())

······

}

若你使用 DevEco Studio 进行开发(大概没有人不用),请在侧边栏中右键选择 NewPage 新建页面。通过这种方式,DevEco Studio 将自动配置好 config.json

若你选择手动创建新页面,请参考 应用包结构说明(FA 模型)应用包结构说明(Stage 模型)自行配置 config.json 文件。

router.pushrouter.back 接受的参数格式都为 RouterOptions

  • url 为目标页面的绝对路径,其中若该值为 "/",则跳转到首页。
  • params 为跳转时要同时传递到目标页面的数据,目标页面可通过 router.getParams 获取发起跳转的页面往当前页传入的参数。

FeatureAbility 模块

在旧的 FA 模型中,使用 @ohos.ability.featureAbility 模块。

在新的 Stage 模型中,使用 @ohos.application.Ability 模块。

这种方式只适用于在不同 Ability 间跳转。

导入模块

import featureAbility from '@ohos.ability.featureAbility'

该模块提供了丰富的能力,包括启动新的 Ability、获取 dataAbilityHelper、设置此 Page Ability、获取当前 Ability 对应的窗口,连接服务等。

这里,我们只会用到 featureAbility.startAbilityfeatureAbility.getWant

  • featureAbility.startAbility 用于启动新的 Ability。
  • featureAbility.getWant 用于获取从 Ability 发送的 Want。

除此之外,featureAbility.terminateSelffeatureAbility.terminateSelfWithResult 也是十分实用的 API。

完整示例请见 GitHub 仓库,如果文章对您有所帮助的话,不妨点个 Star 再走。

// MainAbility Index Page

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

async startAbility(bundleName: string, abilityName: string, parameters = {}) {
    let want = {
      bundleName: bundleName,
      abilityName: abilityName,
      parameters: parameters
    }
    try {
      await featureAbility.startAbility({ want: want });
    } catch (err) {
      console.info(`Fail in startAbility(), code: ${err.code}, msg: ${err.msg}`)
    }
  }

......

@Entry
@Component
struct Index {

    abilityName: string
    pageName: string

......

.onClick(() => this.startAbility('com.github.hydrotho.router', 'com.example.entry.SecondAbility', { url: 'pages/second', isPassingData: true }))

······

}
// SecondAbility Second Page

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

async startAbility(bundleName: string, abilityName: string, parameters = {}) {
    let want = {
      bundleName: bundleName,
      abilityName: abilityName,
      parameters: parameters
    }
    try {
      await featureAbility.startAbility({ want: want });
    } catch (err) {
      console.info(`Fail in startAbility(), code: ${err.code}, msg: ${err.msg}`)
    }
  }

......

@Entry
@Component
struct Index {

    abilityName: string
    pageName: string
    @State isPassingData: boolean = false

......

async getWant() {
    let want = await featureAbility.getWant()
    if (!want) {
      return
    }
    if (want.parameters.isPassingData === true) {
      this.isPassingData = want.parameters.isPassingData
    }
}

aboutToAppear() {
    this.getWant()
}

······

.onClick(() => this.startAbility('com.github.hydrotho.router', 'com.example.entry.MainAbility'))

······

}

若你使用 DevEco Studio 进行开发(大概没有人不用),请在侧边栏右键菜单中新建 AbilityPage。通过这种方式,DevEco Studio 将自动配置好 config.json

若你选择手动创建新页面,请参考 应用包结构说明(FA 模型)应用包结构说明(Stage 模型)自行配置 config.json 文件。

这种方法使用时的关键在于 featureAbility.startAbility 接受的 Want 类型参数。

  • bundleName 其实就是 config.jsonapp 里的 bundleName 属性所对应的值,也就是新建北向应用工程时输入的 Bundle Name。
  • abilityName 值的构成为 package + Ability Name。packageconfig.jsonmodule 里的 package 属性所对应的值。
  • parameters 由开发者自行决定传入的键值对,例如目标页面不为其所在的 Ability 的默认页面时,传入 url 指定目标页面。默认会携带以下键值:
    • ohos.aafwk.callerPid 表示拉起方的 pid。
    • ohos.aafwk.param.callerToken 表示拉起方的 token。
    • ohos.aafwk.param.callerUid 表示发起方的 uid。

在许多网络上的教程以及官方文档中,bundleNamepackage 的值相同,导致人们误解以为 abilityName 的前缀为 bundleName 实际上并不是如此。

例如官方开发指导文档中的这段代码

import featureAbility from '@ohos.ability.featureAbility';
let promise = featureAbility.startAbility (
    {
        want:
        {
            bundleName: "com.jstest.service",
            abilityName: "com.jstest.service.ServiceAbility",
        },
    }
);

看似 bundleNameabilityName 的前缀相同,其实只不过是这里 bundleNamepackage 的值相同。

初学者如果理不清这些概念,待到实际开发时,这就是个大坑。

@ohos.router 模块中,我们直接使用 RouterOptions 类型里的 url 属性指定目标页面。

而在 @ohos.ability.featureAbility 模块中,Want 类型里也有到看似类似的属性 uri。初学者容易想当然地使用 uri 指定目标 Ability 的目标页面,这是不对的。实际上我们需要将目标页面地址包裹在 parameters 属性中,键名为 url

若进行页面跳转时携带了数据,目标页面可以在页面生命周期的早期调用 featureAbility.getWant() 获取源页面跳转时所传递的数据。

关于页面的生命周期,OpenHarmony 中 JS 语言和 eTS 语言有所不同,请参考 JS 语言页面生命周期函数eTS 语言页面生命周期函数

例如,可以在 eTS 语言中的 aboutToAppear 生命周期函数中调用 featureAbility.getWant() 在页面显示前获取传递的数据,对页面进行调整。

WantAgent 模块

这种方式只适用于在不同 Ability 间跳转。

导入模块

import WantAgent from '@ohos.wantAgent';

WantAgent 模块提供了触发、取消、比较 WantAgent 实例等能力。

WantAgent 不仅可以开启 Ability,还可以发送公共事件,其行为可以通过 OperationType 操控。这里我们只使用 START_ABILITY

完整示例请见 GitHub 仓库,如果文章对您有所帮助的话,不妨点个 Star 再走。

// MainAbility Index Page

import wantAgent from '@ohos.wantAgent';

startAbilityViaWantAgent(bundleName: string, abilityName: string) {
    let wantAgentInfo = {
      wants: [
        {
          bundleName: bundleName,
          abilityName: abilityName
        }
      ],
      operationType: wantAgent.OperationType.START_ABILITY,
      requestCode: 0,
      wantAgentFlags: [wantAgent.WantAgentFlags.CONSTANT_FLAG]
    }

    wantAgent.getWantAgent(wantAgentInfo, (error, wantAgentObj) => {
      if (error.code) {
        console.error("[WantAgent]getWantAgent error: " + JSON.stringify(error))
      } else {
        console.log("[WantAgent]getWantAgent success")
        let triggerInfo = {
          code: 0
        }
        wantAgent.trigger(wantAgentObj, triggerInfo, (completeData) => {
          console.log("[WantAgent]getWantAgent success, completeData: ", +JSON.stringify(completeData))
        })
      }
    })
}

......

@Entry
@Component
struct Index {

    abilityName: string
    pageName: string

......

.onClick(() => this.startAbilityViaWantAgent('com.github.hydrotho.router', 'com.example.entry.WantAgentAbility'))

······

}

若你使用 DevEco Studio 进行开发(大概没有人不用),请在侧边栏右键菜单中新建 AbilityPage。通过这种方式,DevEco Studio 将自动配置好 config.json

若你选择手动创建新页面,请参考 应用包结构说明(FA 模型)应用包结构说明(Stage 模型)自行配置 config.json 文件。

这里的 wants 属性也是 Want 类型,具体注意事项请见上文。

WantAgent 模块一般还是其公共事件功能 (SEND_COMMON_EVENT) 较为常用,更多功能请参考官方文档

总结

本文介绍了目前 (OpenHarmony v3.2) 北向应用实现页面跳转常见的所有方法,开发者可以根据场景需求自行选择。

一般来说,我们可以这样选择:

  • 若使用场景为同一 Ability 内部的不同页面间跳转,选择 @ohos.router 模块。
  • 若使用场景为不同 Ability 间跳转,选择 @ohos.ability.featureAbility 模块(FA 模型)或 @ohos.application.Ability 模块(Stage 模型)。