在这里插入图片描述

你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌 关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀

前言

上一篇如果已经把 Want 理解成“描述我要去哪里、要做什么”的信息载体,那么继续往下就会遇到一个很实际的问题:显式 Want 可以直接写 bundleName、abilityName,隐式 Want 没有指定目标组件,系统凭什么知道该把请求交给谁?

答案就在目标应用的 skills。

隐式匹配并不是系统“猜”哪个应用合适,而是调用方给出 action、entities、URI 等条件,目标 UIAbility 再通过 module.json5 中的 skills 声明自己能够处理哪些请求。两边条件能够匹配,目标组件才有机会进入后续启动流程。华为当前官方文档也把“显式 Want 与隐式 Want 匹配规则”作为 Want 的核心内容单独说明。

本文继续沿着“Want → skills”这条线,用一个 URL 跳转的最小场景,把 action、entities、URI 和 module.json5 串起来。

需要先说明版本背景:HarmonyOS 7.0 对应 API 26.0.0,华为官方建议使用 26.0.0 开发套件进行升级适配。本文涉及的 UIAbilityContext 属于 Stage 模型能力,其接口体系从 API version 9 开始提供;文中用于 URL 跳转的 openLink 从 API version 12 开始支持,因此在 HarmonyOS 7 / API 26.0.0 范围内可用。

一、隐式 Want 为什么离不开 skills

显式 Want 的思路很直接:

let want: Want = {
  bundleName: 'com.example.target',
  abilityName: 'EntryAbility'
};

这里已经把目标应用和目标 UIAbility 写出来了,系统不需要再根据业务意图寻找候选组件。

隐式 Want 则不同。它更像是在描述:

let want: Want = {
  action: 'ohos.want.action.viewData',
  entities: ['entity.system.browsable'],
  uri: 'https://www.example.com/article/1001'
};

这段代码的重点不是让大家直接把它作为 HarmonyOS 7 跨应用 URL 跳转的推荐实现,而是观察隐式请求携带的三个维度:

  • action:想执行什么操作;
  • entities:目标组件还应该属于什么类别;
  • uri:准备处理什么数据或资源。

官方对 action 的定义也是“调用方要执行的通用操作”,而 entities 是目标应用组件的类别信息,是对 action 的补充。调用方在 Want 中声明这些条件,被调用方则在配置文件的 skills 中通过 actions、entities 等字段声明自己支持什么。

因此,排查隐式 Want 找不到目标应用时,不能只盯着调用方代码。

Want 是请求条件,skills 是目标组件提供给系统的匹配条件。

这就是从上一篇 Want 继续往下理解 skills 的关键。

二、action:不是目标组件名,而是“我要做什么”

action 最容易被误解成某个 Ability 的别名。

实际上它表达的是操作意图。例如官方目前仍明确列出的 ohos.want.action.viewData,对应查看数据这一类操作;当它和网址 URI 配合时,可以表达“查看这个网址所对应的数据”。目标应用如果要参与这种匹配,就需要在对应 UIAbility 的 skills.actions 中声明支持相应 action。

也就是说,调用侧和目标侧形成的是这样的关系:

Want.action
        ↓
skills.actions

这里有一个 HarmonyOS 7 开发时尤其应该注意的变化:华为当前文档已经将“常见 action 与 entities”标记为不推荐使用,原因是 action/entity 曾被泛化使用,系统难以约束应用虚假声明,官方表示后续会逐步废弃非必要 action/entity,并建议通过指定类型的方式拉起应用。

所以本文并不建议为了自己的业务随意设计一套通用 action/entity,然后期待任意第三方应用参与匹配。

但这不代表 skills.actions 已经没有作用。恰恰相反,在官方明确规定的场景中仍然需要严格配置。例如 openLink 处理 App Linking 时,目标 UIAbility 就必须包含 ohos.want.action.viewData。

三、entities:在 action 基础上继续缩小范围

如果说 action 回答“做什么”,entities 更接近“由哪一类组件来做”。

官方文档将 entities 定义为目标应用组件的类别信息,是对 action 的补充。例如 entity.system.browsable 表示浏览器类别。在 Want 中设置 entities,可以进一步过滤匹配的 Ability;目标组件则在 skills.entities 中声明自己支持的类别。

关系可以继续补完整:

Want.action      → skills.actions
Want.entities    → skills.entities

在 App Linking 场景中,这两个条件是配套出现的。官方对 UIAbilityContext.openLink 的要求很明确:目标 UIAbility 的过滤器中,actions 要包含 ohos.want.action.viewData,entities 要包含 entity.system.browsable。

这也是为什么只看调用方的 URL 往往排查不出问题。

URL 完全正确,并不代表目标 UIAbility 已经声明“我愿意处理这种请求”。

四、URI:不仅要有链接,还要匹配链接特征

到了 URI,匹配条件会更具体。

URI 可以继续拆成 scheme、host、path 等部分。官方应用链接配置文档中,skills.uris 可以描述这些 URI 特征;其中还提供 path、pathStartWith、pathRegex 等路径匹配方式。官方特别提醒,scheme 和 host 建议使用小写;配置 path、pathStartWith、pathRegex 时,值的前后不要添加 /。

例如准备处理:

https://www.example.com/article/1001

目标应用可以围绕 https、www.example.com 和 article 这几个特征声明自己的处理范围,而不是笼统地认为“我的应用能打开网页,所以任何 https 地址都应该找到我”。

真正需要关注的是:

请求 URI
   ↓
scheme
host
path
   ↓
skills.uris

action、entities、URI 放在一起之后,隐式匹配的思路就清楚很多了:系统不是拿一个字符串去搜索应用名,而是在用请求特征筛选具备对应处理能力的组件。

五、module.json5 到底怎么参与匹配

module.json5 不是普通的业务参数文件。

HarmonyOS 应用中的每个 Module 都有独立的 module.json5,其中包含 Module 基本信息、UIAbility / ExtensionAbility 等组件描述以及运行所需配置。官方应用程序包术语中也明确说明,每个模块都有自己的 module.json5。

对于 UIAbility,skills 就配置在 abilities 对应组件下面。

下面把场景缩小到一个容易复现的例子:目标应用希望处理本站文章链接:

https://www.example.com/article/...

按照官方 App Linking 对目标组件过滤器的要求,可以把关键配置组织为:

{
  "module": {
    // 省略其他模块配置
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "exported": true,
        "skills": [
          {
            "actions": [
              "ohos.want.action.viewData"
            ],
            "entities": [
              "entity.system.browsable"
            ],
            "uris": [
              {
                "scheme": "https",
                "host": "www.example.com",
                "pathStartWith": "article",
                "domainVerify": true
              }
            ]
          }
        ]
      }
    ]
  }
}

这里真正应该看的不是 JSON5 有多少字段,而是 skills 里的三层条件:

actions  → 处理什么操作
entities → 组件属于什么类别
uris     → 能处理什么链接

对于 App Linking,官方要求 actions 包含 ohos.want.action.viewData、entities 包含 entity.system.browsable,并且 uris 中存在 scheme 为 https、domainVerify 为 true 的元素。

pathStartWith: "article" 则继续把处理范围限制到相应路径。URI 配置字段和路径规则可参考官方 Application Link Description。

六、搭一个最小调用场景

到了 HarmonyOS 7,如果目标是通过 URL 打开对应应用,更合适的最小示例不是继续用一个泛化 action 调用任意第三方应用,而是按照官方应用间跳转能力使用 openLink。

UIAbilityContext.openLink 从 API version 12 开始提供,通过标准 URL 基于隐式 Want 匹配规则拉起目标 UIAbility。官方最新 API 文档显示该接口覆盖 Phone、PC/2in1、Tablet、TV、Wearable 对应版本,并明确给出了前面提到的 skills 过滤条件。

页面中可以写一个最小调用:

import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button('打开文章')
        .onClick(async () => {
          const context =
            this.getUIContext().getHostContext() as common.UIAbilityContext;

          try {
            await context.openLink(
              'https://www.example.com/article/1001'
            );
          } catch (err) {
            const error = err as BusinessError;
            console.error(
              `openLink failed, code=${error.code}, message=${error.message}`
            );
          }
        });
    }
    .width('100%')
    .height('100%')
  }
}

这段代码只解决一个问题:发起一个标准 URL 的应用链接跳转。

真正决定目标应用能不能进入匹配范围的部分,反而主要在目标方 module.json5。

这也是本文最想强调的排查思路:调用 API 没写错,并不意味着匹配条件已经成立。

根据官方接口定义,openLink 还可能返回 16000019,含义就是没有找到匹配的 Ability。因此看到这类错误时,与其立刻怀疑 ArkUI 按钮、Promise 或页面生命周期,不如先回到目标方的 skills。

七、几个比较容易理解错的地方

1. skills 属于目标方,不是调用方

Want 描述“我要什么”,skills 描述“我能处理什么”。

如果 A 应用希望打开链接,B 应用希望成为处理方,那么需要重点检查的是 B 应用目标 UIAbility 对应的 skills,而不是给 A 应用也复制一份相同配置。

2. skills 要放到真正负责接收请求的 UIAbility 下

module.json5 中可能存在多个 Ability。

skills 是组件级匹配条件。如果把配置写在 EntryAbility,但实际设计中希望另一个 UIAbility 承接请求,就需要重新核对配置归属。官方工程配置也明确把 skills 放在具体的 abilities 项内。

3. 不要只检查 action

这是隐式 Want 排查中很容易形成的思维惯性:

action 一样
= 应该能匹配

实际上 URL 场景还要继续检查 entities 和 uris。以 App Linking 为例,官方对 action、entity、HTTPS URI 和 domainVerify 都有明确要求。

4. URI 看起来一样,不代表配置一定一样

下面这些差异都值得单独核对:

http  / https
example.com / www.example.com
article / articles
path / pathStartWith / pathRegex

官方还特别提醒 scheme、host 的大小写以及路径配置中 / 的写法。URI 匹配失败时,建议把完整链接拆成 scheme、host、path 三部分逐项比对,而不是盯着整条字符串看。

5. HarmonyOS 7 不应继续照搬旧版本的“万能隐式 action”思路

这一点非常关键。

华为当前已经明确将通用 action/entities 文档标记为“不推荐使用”,并建议针对应用跳转采用指定类型等方式。与此同时,startAbility 最新 API 文档还列出了 API version 12+ 的第三方应用重定向限制错误 16000018。所以学习 skills 的目的,不应该变成“设计一个 action 就能随便拉起任何应用”,而应该理解系统的匹配模型,再根据具体业务选择官方当前推荐的应用跳转方式。

URL 场景使用 Deep Linking / App Linking,导航、邮件、图片编辑等垂类场景则应该继续查对应的官方“指定类型应用”能力,而不是把所有需求都塞进自定义 action。

八、实际项目中怎么排查

如果出现“隐式 Want 发出去了,但找不到目标应用”,可以按下面顺序检查:

  1. 先确认场景和 API 版本。 HarmonyOS 7 对应 API 26.0.0,不要直接照搬早期 HarmonyOS NEXT 示例;同时确认当前场景应该使用 startAbility、openLink 还是指定类型应用启动能力。
  2. 确认请求是不是隐式匹配。 如果已经给出 bundleName、abilityName,就应优先按显式 Want 的思路排查,而不是一直检查 skills。
  3. 检查 action。 调用侧表达的操作与目标 UIAbility 的 skills.actions 是否符合该能力的官方要求。
  4. 检查 entities。 不要因为 action 对上了,就忽略类别过滤条件。
  5. 拆开检查 URI。 分别核对 scheme、host 和 path,特别留意大小写、pathStartWith 等规则。
  6. 确认 skills 配置到了正确 UIAbility。 一个 Module 里存在多个 Ability 时尤其容易看错位置。
  7. 再检查组件启动约束。 如果已经完成匹配但仍无法启动,再继续核对组件可见性、应用间跳转规则以及对应 API 返回的错误码。startAbility 与 openLink 的最新文档都列出了明确的启动错误码,可以根据错误码继续缩小范围。

开发经验总结

从 Want 继续理解 skills,真正需要建立的不是“记住几个 JSON 字段”,而是一套匹配思维:

显式 Want 是直接指定目标,隐式 Want 是描述目标应该具备什么能力。

而目标应用能否被找到,要看对应 UIAbility 有没有通过 module.json5 的 skills 声明匹配条件。

action 解决“做什么”,entities 继续描述目标类别,URI 把范围收缩到具体数据或链接;到了 HarmonyOS 7,还要额外关注官方当前的应用间跳转规则,不能把早期的通用 action/entity 用法直接当成所有场景的推荐方案。

如果遇到 No matching ability is found,这里先别急着改业务代码。把 Want 或链接条件放在左边,把目标 UIAbility 的 skills 放在右边,一项一项对照,通常比从页面逻辑开始翻代码更接近问题本身。

而这也正好把 Want 的学习链条接了起来:

Want
  ↓
显式 / 隐式
  ↓
action + entities + URI
  ↓
module.json5
  ↓
skills
  ↓
目标 UIAbility

理解到这里,再继续看 Deep Linking、App Linking、文件处理或指定类型应用启动时,会发现它们并不是几套互不相关的 API,而是在不同业务约束下,对“如何描述请求、如何声明接收能力”这件事做了更具体的规定。

如果正在排查自己的隐式匹配问题,可以先问一个很简单的问题:调用方已经说清楚“我要什么”了,那么目标 UIAbility 有没有在 skills 里准确声明“这个请求我能处理”?

❤️ 如果本文帮到了你…

  • 请点个赞,让我知道你还在坚持阅读技术长文!
  • 请收藏本文,因为你以后一定还会用上!
  • 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐