鸿蒙应用开发UI基础第六节:Want拉起应用跳转传参匹配规则实战

【学习目标】

  1. 理解 Want 本质:掌握 Want 作为组件间信息传递载体的核心作用,明确显式/隐式 Want 的划分与适用场景;
  2. 掌握显式启动:精通跨应用通过 bundleName+abilityName 精准启动组件;
  3. 掌握隐式启动:吃透 linkFeatureactionentitiesuritype 的完整层级匹配规则;
  4. 数据传递与校验:规范使用 parameters 传递数据,合理运用功能标识实现精准匹配。

【内容铺垫】

在 HarmonyOS 中,Want 是组件(Ability/Extension)间交互的标准信息载体,核心用于描述"操作目标""操作意图"和"附加数据",是应用内/跨应用组件通信的核心桥梁。无论是应用内页面跳转、跨应用功能调用(如打开文档、分享内容),本质都是通过传递 Want 对象实现的。

在之前的章节中,我们已多次使用 Want 实现 Ability 拉起操作,本节将所有 Want 核心能力直接在 Index 页演示,无需额外跳转页面。

核心规范提示:从 API 12 开始,已不再推荐三方应用使用指定 Ability 方式(即显式 Want)拉起其他应用,推荐使用指定应用链接方式(下一节讲),但作为开发者,我们仍需掌握显式/隐式 Want 的核心原理,以便应对各类组件通信场景。

示意图如下:

一、Want 核心概念与结构

Want 是对象类型,核心字段决定组件匹配与启动逻辑,关键字段及约束如下:

1. 核心字段解析

字段名 类型 核心作用 必选性 核心说明
deviceId string 目标设备ID 空字符串表示本机,跨设备场景需指定设备标识;隐式 Want 暂不支持跨设备调用
bundleName string 目标应用包名 显式必选 显式 Want 必须指定
abilityName string 目标组件名称 显式必选 显式 Want 核心字段;API 12+ 跨应用场景不推荐使用
moduleName string 目标模块名称 同一应用多模块存在重名组件时,需指定,否则默认匹配第一个模块
uri string 统一资源标识符 隐式可选 格式为 scheme://host:port/path;自定义 scheme 不可与系统应用重复(如 ohos 前缀)
action string 操作意图 隐式核心 常用值:ohos.want.action.viewData(查看数据)、ohos.want.action.share(分享)、ohos.want.action.search(搜索)
entities Array 组件类别约束 隐式可选 常用值:entity.system.browsable(浏览器类组件)、entity.system.home(桌面应用)
type string 数据MIME类型 隐式可选 text/plain(纯文本)、image/png(PNG图片),需与 uri 协同匹配
parameters Object 自定义附加数据 支持基础数据类型(字符串、数字、布尔值等);可通过 linkFeature 字段标记功能类型(隐式匹配最高优先级)
flags number 启动模式标记 FLAG_START_WITHOUT_TIPS 支持隐式 Want 取消"暂无可用打开方式"弹框;无法取消"是否允许跳转"系统弹框

2. Want 的两种核心类型

  • 显式 Want :同时指定 bundleNameabilityName,直接定位目标组件,无需系统遍历匹配,匹配效率高、无系统开销。
  • 隐式 Want :不指定 abilityName,通过 linkFeatureactionentitiesuritype 描述操作意图,由系统匹配声明对应 skills 的组件,适用于跨应用通用功能调用(如调用系统分享、打开浏览器)。

3. 隐式 Want 匹配规则(核心重点)

(1)匹配基础前提

隐式 Want 匹配的基础前提:若 action/entities/uri/type/parameters(linkFeature) 五个属性均未配置,系统直接判定匹配失败,无需后续校验。

(2)匹配优先级(从高到低)

linkFeature(parameters 内置字段)actionentitiesuri + type

linkFeature 是 HarmonyOS API 11+ 新增的最高优先级匹配字段,通过 parameters 传递,专门解决传统隐式匹配范围过宽的问题,适用于跨应用固定功能的精准隐式调用。

(3)分步详细规则

表格中 action 值如 abc 仅为表达匹配,工程中取值要规范。

① linkFeature 匹配(最高优先级)
核心匹配字段及校验逻辑(精准匹配为唯一规则)
校验字段 触发校验条件 匹配规则 失败判定
linkFeature 调用方传该参数则必校验 需与 skills 配置值完全一致 配置值≠调用方值(如 link≠errLink)
scheme(URI) 调用方传 uri 则必校验 scheme 需与 uri 的 scheme 完全一致 scheme≠uri 的 scheme(如 https≠file)
type 调用方传 type 则必校验 需与调用方 type 完全一致 type≠调用方值(如 text/plain≠image/png)
分场景匹配规则
  1. 场景1(仅传 linkFeature):仅校验 linkFeature,scheme/type 不参与,一致则成功,否则失败;
  2. 场景2(传 uri+linkFeature):需同时满足 scheme 匹配 + linkFeature 匹配,任一不满足则失败;
  3. 场景3(传 type+linkFeature):需同时满足 type 匹配 + linkFeature 匹配,任一不满足则失败;
  4. 场景4(传 uri+type+linkFeature):需同时满足 scheme 匹配 + type 匹配 + linkFeature 匹配,任一不满足则失败。
补充说明
  • 无通配符、前缀匹配等宽松规则,所有参与校验的字段均为精准完全匹配
  • 调用方未传的字段(如 uri/type),skills 中对应字段不参与校验;
  • 无"部分匹配""降级匹配"逻辑,任一需校验字段不匹配则整体失败。
② action 匹配规则
调用方 wantaction 目标方 skills.actions 匹配结果 核心说明
空值 action:"" 空值 actions: [] 失败 双方均未声明操作意图,系统无法匹配
空值 action:"" 非空值 actions: ["abc"] 成功 调用方未指定意图,目标方声明了能力,默认匹配
非空值 action:"abc" 空值 actions: [] 失败 调用方指定了意图,目标方未声明对应能力
非空值 action:"abc" 包含调用方 actions: ["abc"] 成功 目标方声明的能力包含调用方意图
非空值 action:"abc" 不包含调用方 actions: ["bcd"] 失败 目标方未声明调用方所需能力
③ entities 匹配规则
调用方 entities 目标方 skills.entities 匹配结果 核心说明
空(entities: [] 非空(entities: ["a","b"] 成功 调用方未限定组件类别,目标方无论是否声明类别均匹配
空(entities: [] 空(entities: [] 成功 调用方未限定组件类别,目标方无论是否声明类别均匹配
非空(entities: ["a"] 空(entities: [] 失败 调用方限定了组件类别,目标方未声明任何类别
非空(entities: ["a","b"] 包含所有调用方(entities: ["a","b","c"] 成功 目标方声明的类别完全包含调用方需求
非空(entities: ["a","b"] 未包含所有调用方(entities: ["a","c"] 失败 目标方声明的类别缺失调用方所需类别(如调用方要 browsable,目标方仅声明 home
④ uri + type 匹配规则(协同校验)
场景 调用方配置 匹配规则
场景1 uri 空 + type 空 1. 目标方 skills.uris 为空 → 成功; 2. 目标方 skills.uris 存在「scheme 和 type 均空」的元素 → 成功; 3. 其他情况 → 失败
场景2 uri 非空 + type 空 1. 目标方 skills.uris 为空 → 失败; 2. 目标方 skills.uris 存在「uri 匹配 + type 空」的元素 → 成功; 3. 前两步失败且 uri 为文件路径 → 按后缀推导 MIME 类型,匹配目标方 type → 成功/失败
场景3 uri 空 + type 非空 1. 目标方 skills.uris 为空 → 失败; 2. 目标方 skills.uris 存在「scheme 空 + type 匹配」的元素 → 成功; 3. 其他情况 → 失败
场景4 uri 非空 + type 非空 1. 目标方 skills.uris 为空 → 失败; 2. 目标方 skills.uris 存在「uri 匹配 + type 匹配」的元素 → 成功; 3. 其他情况 → 失败
Type 单独匹配规则(仅调用方 type 非空时生效)

Type 匹配核心为 MIME 媒体类型匹配,遵循 HarmonyOS 官方规范,无降级匹配逻辑,规则如下:

  1. 精准匹配(最高优先级) :调用方 type 与目标方 skills.uristype 完全一致 → 匹配成功;
  2. 通配符匹配 :仅支持「主类型/*」格式,目标方 type 为此格式且调用方 type 属于该主类型范畴 → 成功;不支持 */子类型 格式;
  3. 匹配失败场景
    • 目标方 type 为具体值但与调用方 type 不一致;
    • 目标方 type 通配符格式不规范;
    • 调用方 type 为复合 MIME 类型,目标方无对应配置。

补充说明:Type 匹配仅在「调用方传递 type」且「进入 uri+type 协同校验环节」时触发;若目标方 type 为空,仅当调用方 type 也为空时匹配成功。

uri 匹配规则

URI 匹配以 scheme → host → port → 路径 为核心层级,仅当前一级匹配通过时触发下一级校验,任一层级失败则整体 URI 匹配失败,具体规则:

  1. scheme 层级(首验层级)
    • 目标 URI 项 scheme 为空 → 仅调用方 uri 为空时匹配成功,否则失败;
    • 目标 URI 项 scheme 非空 → 调用方 urischeme 需与其完全一致(大小写敏感,官方建议全小写),否则失败。
  2. host 层级(仅 scheme 匹配成功后触发)
    • 目标 URI 项 host 为空 → 直接匹配成功;
    • 目标 URI 项 host 非空 → 调用方 urihost 需与其完全一致,否则失败。
  3. port 层级(仅 scheme+host 匹配成功后触发)
    • 目标 URI 项 port 为空 → 直接匹配成功;
    • 目标 URI 项 port 非空 → 调用方 uriport 需与其完全一致(数字格式),否则失败。
  4. 路径层级(仅 scheme+host+port 匹配成功后触发)
    path → pathStartWith → pathRegex 优先级校验,任一规则匹配成功则终止校验,全部失败则 URI 匹配失败:
    • path 精准匹配 :目标 URI 项 path 非空 → 调用方 uri 全路径与其完全一致 → 成功,否则进入下一级;
    • pathStartWith 前缀匹配 :目标 URI 项 pathStartWith 非空 → 调用方 uri 路径包含该前缀 → 成功,否则进入下一级;
    • pathRegex 正则匹配 :目标 URI 项 pathRegex 非空 → 调用方 uri 路径符合该正则表达式 → 成功,否则 URI 匹配失败;
    • 路径字段均为空 :目标 URI 项 pathpathStartWithpathRegex 均为空 → 直接匹配成功。

补充说明:

  1. 最左 URI 匹配:仅当目标 URI 项仅配置 scheme/scheme+host/scheme+host+port(路径字段均为空)时生效,调用方 uri 需以目标配置为前缀;
  2. 文件 URI 解析:file:// 开头的 URI,系统自动解析文件后缀推导 MIME 类型,用于补充场景2的 type 匹配;
  3. URI 格式规范:自定义 scheme 不可与系统内置(ohos/http/https/file)重复。

(4)匹配结果说明

根据系统中待匹配应用组件的匹配情况不同,使用隐式 Want 启动应用组件时会出现以下三种情况:

  • 未匹配到满足条件的应用组件:启动失败。
  • 匹配到一个满足条件的应用组件:直接启动该应用组件。
  • 匹配到多个满足条件的应用组件(UIAbility):弹出选择框让用户选择。

二、本节工程

(一)工程创建

1. 调用方工程:WantAndLinkingDemo

  • 基础配置:HarmonyOS 5.0+、API 18+、Stage 模型;
  • 核心用途:演示显式/隐式 Want 启动;
  • 包名:com.example.wantandlinkingdemo

2. 接收方工程:ImplicitReceiverDemo

  • 基础配置:HarmonyOS 5.0+、API 18+、Stage 模型;
  • 核心用途:作为跨应用显式/隐式启动的目标应用,接收并展示传递的参数;
  • 包名:com.example.implicitreceiverdemo

(二)调用方工程核心目录结构

复制代码
WantAndLinkingDemo/                  # 项目根目录(Want实战Demo)
├─ AppScope/                        # 应用全局配置目录(多模块应用共享)
│  ├─ resources/                    # 应用全局资源文件(如全局样式、多语言字符串)
│  └─ app.json5                     # 应用级配置文件(应用名称、版本号等)
├─ entry/                           # 主模块目录(核心代码所在)
│  ├─ src/
│  │  ├─ main/                      # 主代码目录(应用运行的核心代码)
│  │  │  ├─ ets/                    # ArkTS代码目录(逻辑实现核心)
│  │  │  │  ├─ entryability/        # 主Ability目录(应用入口)
│  │  │  │  │  └─ EntryAbility.ets  # 应用入口Ability(处理启动初始化)
│  │  │  │  └─ pages/               # 主Ability对应的页面目录
│  │  │  │     └─ Index.ets          # 核心功能页(整合显式/隐式Want启动所有案例)
│  │  │  ├─ resources/              # 模块级资源目录(页面布局、图片、局部样式)
│  │  │  └─ module.json5            # 模块配置文件(核心!配置skills、exported等)
│  ├─ build-profile.json5           # 模块构建配置文件(编译、打包参数)
│  ├─ hvigorfile.ts                 # 模块构建脚本(hvigor构建任务配置)
│  ├─ obfuscation-rules.txt         # 代码混淆规则文件(发布时加密代码,可选)
│  └─ oh-package.json5              # 模块依赖配置文件(第三方库、工具依赖)

(三)隐式/显示拉起应用传参示例

调用方:WantAndLinkingDemo Index.ets

构造Want数据,演示显式/隐式不同模式拉起应用,通过不同匹配规则。

javascript 复制代码
import { BusinessError } from '@ohos.base';
import { common, Want, wantConstant } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { promptAction } from '@kit.ArkUI';

const DOMAIN = 0xFF00;
const TAG = 'WantAndLinkingDemo';

@Entry
@Component
struct Index {
  // 获取UIAbility上下文
  private context = this.getUIContext().getHostContext() as common.UIAbilityContext;

  build() {
    Column({ space: 15 }) {
      // 页面标题
      Text('Want 显式/隐式启动实战(匹配规则修正版)')
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 30 })

      // 1. 显式Want(精准匹配,无规则问题)
      Button('1. 显式Want跨应用拉起传参')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor('#1890ff')
        .fontColor('#ffffff')
        .onClick(() => {
          this.crossAppExplicitStart();
        })

      // 2. 隐式Want - linkFeature(最高优先级,需精准匹配)
      Button('2. 隐式Want-linkFeature匹配(最高优先级)')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor('#1890ff')
        .fontColor('#ffffff')
        .onClick(() => {
          this.implicitStartShare();
        })

      // 3. 隐式Want - action单独匹配(核心:仅传action,无其他干扰字段)
      Button('3. 隐式Want-action单独匹配')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor('#1890ff')
        .fontColor('#ffffff')
        .onClick(() => {
          this.implicitStartActionMatch();
        })

      // 4. 隐式Want - entities单独匹配
      Button('4. 隐式Want-entities单独匹配')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor('#1890ff')
        .fontColor('#ffffff')
        .onClick(() => {
          this.implicitStartEntitiesMatch();
        })

      // 5. 隐式Want - uri+type协同匹配(核心:仅传uri+type,配通用action)
      Button('5. 隐式Want-uri+type协同匹配')
        .width('80%')
        .height(50)
        .fontSize(18)
        .backgroundColor('#1890ff')
        .fontColor('#ffffff')
        .onClick(() => {
          this.implicitStartUriTypeMatch();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#f5f5f5')
  }

  /**
   * 场景1:显式Want
   * 规则:指定bundleName+abilityName,无需匹配skills,仅需接收方设置 exported=true
   */
  private async crossAppExplicitStart() {
    try {
      const want: Want = {
        bundleName: "com.example.implicitreceiverdemo", // 接收方包名(必须与实际一致)
        abilityName: "EntryAbility", // 接收方组件名(必须与实际一致)
        parameters: {
          "shareContent": "显式Want测试:跨应用精准传递内容",
          "linkFeature": "Explicit"
        }
      };

      await this.context.startAbility(want);
      hilog.info(DOMAIN, TAG, "显式Want跨应用拉起成功");
    } catch (err) {
      const businessErr = err as BusinessError;
      promptAction.showToast({
        message: `启动失败:${businessErr.message}`,
        duration: 3000
      });
    }
  }

  /**
   * 场景2:隐式Want - linkFeature(最高优先级)
   * 规则:uri和type均为空时,仅校验linkFeature精准匹配
   * 规则:uri或type不为空时,需同时满足linkFeature精准匹配 + uri的scheme匹配 + type精准匹配
   */
  private async implicitStartShare() {
    const want: Want = {
      uri: "data://com.example.wantandlinkingdemo/share/text", // scheme/host需匹配
      type: "text/plain", // 必须精准匹配
      parameters: {
        shareContent: "隐式Want测试:linkFeature匹配成功!",
        linkFeature: "Share" // 最高优先级,接收方必须精准配置
      },
    };

    try {
      await this.context.startAbility(want);
      hilog.info(DOMAIN, TAG, "隐式Want(linkFeature)跨应用拉起成功");
    } catch (error) {
      const businessErr = error as BusinessError;
      hilog.error(DOMAIN, TAG, `linkFeature匹配失败:${businessErr.message}`);
      promptAction.showToast({
        message: '启动失败,未匹配到支持分享的应用',
        duration: 3000
      });
    }
  }

  /**
   * 场景3:隐式Want - action单独匹配
   * 规则:调用方action需匹配接收方skills中的action配置
   */
  private async implicitStartActionMatch() {
    const want: Want = {
      action: 'ohos.want.action.viewData',
      parameters: {
        "shareContent": "隐式Want测试:action匹配成功!",
      }
    };

    try {
      await this.context.startAbility(want);
      hilog.info(DOMAIN, TAG, "隐式Want(action)跨应用拉起成功");
    } catch (error) {
      const businessErr = error as BusinessError;
      hilog.error(DOMAIN, TAG, `action匹配失败:${businessErr.message}`);
      promptAction.showToast({
        message: '启动失败,未匹配到支持查看数据的应用',
        duration: 3000
      });
    }
  }
  
  /**
   * 场景4:隐式Want - entities匹配
   * entities匹配规则:调用方传递的所有entities值,需被目标方skills.entities完全包含才匹配成功(本示例为"abc")
   * 系统标准值参考:entity.system.browsable(浏览器类别,处理网页链接)、entity.system.home(应用主入口组件)
   */
  private async implicitStartEntitiesMatch() {
    const want: Want = {
      action: 'ohos.want.action.viewData', // 查看数据
      entities: ["abc"],
      parameters: {
        "shareContent": "隐式Want测试:entities匹配成功!",
      }
    };

    try {
      await this.context.startAbility(want);
      hilog.info(DOMAIN, TAG, "隐式Want(entities)跨应用拉起成功");
    } catch (error) {
      const businessErr = error as BusinessError;
      hilog.error(DOMAIN, TAG, `entities匹配失败:${businessErr.message}`);
      promptAction.showToast({
        message: '启动失败,未匹配到浏览器类应用',
        duration: 3000
      });
    }
  }

  /**
   * 场景5:隐式Want - uri+type协同匹配
   * 核心:需同时满足uri层级匹配(scheme→host→port→路径) + type精准匹配
   */
  private async implicitStartUriTypeMatch() {
    const want: Want = {
      action: 'ohos.want.action.viewData',
      uri: "data://com.implicitreceiverdemo:8080/detail/page123",
      type: "text/plain",
      flags: wantConstant.Flags.FLAG_START_WITHOUT_TIPS // 取消失败弹窗提示
    };

    try {
      await this.context.startAbility(want);
      hilog.info(DOMAIN, TAG, "隐式Want(uri+type)跨应用拉起成功");
    } catch (error) {
      const businessErr = error as BusinessError;
      hilog.error(DOMAIN, TAG, `uri+type匹配失败:${businessErr.message}`);
      promptAction.showToast({
        message: '启动失败,未匹配到符合uri+type规则的应用',
        duration: 3000
      });
    }
  }
}
(2)接收方:ImplicitReceiverDemo

跨应用接收调用方Want传递的参数(拉起组件内Ability接收参数同理,本节不做示例演示)

javascript 复制代码
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { ConfigurationConstant } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;
const TAG = 'ImplicitReceiverDemo';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, TAG, '%{public}s', 'ImplicitReceiverDemo onCreate 触发');
    try {
      // 解析 Want 中的参数(显式传递的 data + 隐式传递的 shareContent)
      const parameters = want.parameters as Record<string, Object>;
      // 存储参数到 AppStorage,供 UI 页面展示(默认值避免空显示)
      AppStorage.setOrCreate("shareContent", parameters["shareContent"] || '未接收分享数据');

      // 设置应用颜色模式(可选,保持系统默认)
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, TAG, 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
  }

  /**
   * 已启动时接收新的 Want 参数(如隐式启动多次触发)
   */
  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, TAG, '%{public}s', 'ImplicitReceiverDemo onNewWant 触发');
    const parameters = want.parameters as Record<string, Object>;
    // 更新参数(实时同步到 UI 页面)
    AppStorage.setOrCreate("shareContent", parameters["shareContent"] || '未接收分享数据');
    // 打印接收的参数
    console.log(`ImplicitReceiverDemo 接收参数:${JSON.stringify(want.parameters)}`);
  }

  /**
   * 加载 UI 页面
   */
  onWindowStageCreate(windowStage:  window.WindowStage): void {
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, TAG, 'Succeeded in loading the content: Index');
    });
  }
}
② 接收方:Index.ets(展示跨应用接收的参数)
javascript 复制代码
@Entry
@Component
struct Index {
  @StorageProp('shareContent') shareContent: string = '隐式/显式分享数据未接收';

  build() {
    Column({ space: 20 }) {
      Text('ImplicitReceiverDemo(参数接收)')
        .fontSize(25)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })

      Text(`接收的内容:${this.shareContent}`)
        .fontColor(Color.Red)
        .fontSize(18)
        .textWrap(true)
        .padding(10)
    }.justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
    .padding(20)
  }
}
③ 接收方:module.json5配置
json 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true, // 必须开启:允许外部应用调用(显式/隐式均需)
        "skills": [
          {
            // 基础技能:桌面应用(默认配置)
            "entities": ["entity.system.home"],
            "actions": ["ohos.want.action.home"]
          },
          // 场景2:linkFeature匹配规则
          {
            "uris": [
              {
                "scheme": "data",
                "host": "com.example.wantandlinkingdemo",
                "type": "text/plain",
                "linkFeature": "Share"
              }
            ]
          },
          // 场景3:action单独匹配规则
          {
            "actions": ["ohos.want.action.viewData"]
          },
          // 场景4:entities单独匹配规则
          {
            "actions": ["ohos.want.action.viewData"],
            "entities": ["abc"]
          },
          // 场景5:uri+type协同匹配规则
          {
            "actions": ["ohos.want.action.viewData"],
            "uris": [
              {
                "scheme": "data",                   // 协议必须完全一致
                "host": "com.implicitreceiverdemo", // 域名需完整匹配
                "port": "8080",                     // 端口不可省略
                "path": "detail/page123",            // 路径需完全一致或使用通配符
                "type": "text/plain"                // MIME类型需严格匹配
              }
            ]
          }
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",
        "exported": false,
        "metadata": [
          {
            "name": "ohos.extension.backup",
            "resource": "$profile:backup_config"
          }
        ]
      }
    ]
  }
}

运行结果

四、开发核心规范与避坑指南

1. 核心约束

  • 所有对外提供调用的 Ability(显式/隐式),必须在 module.json5 中配置 exported: true,否则无法被外部调用;
  • 自定义 scheme 不可与系统内置 scheme(如 ohoshttphttpsfile)重复,建议采用"应用标识+功能"命名(如 harmonydemo);
  • 隐式 Want 若使用 linkFeature 匹配,actions 字段可忽略;使用 action/entities/uri+type 匹配时,对应字段不可为空。

2. 避坑指南

问题现象 排查/解决方法
隐式启动匹配失败 检查 linkFeatureactionentitiesuritype 是否与接收方配置一致,尤其是 schemehost 大小写(建议全小写);
参数传递失败 确保传递的参数为基础数据类型(避免传递复杂对象),接收方通过 want.parameters 解析时需做类型断言;
跨应用显式启动失败 确认目标应用已安装、bundleNameabilityName 配置正确,且目标 Ability 已设置 exported: true
uri 匹配失败 scheme→host→port→路径 层级逐一校验,路径匹配优先精准匹配,前缀/正则匹配需确保规则正确。

五、内容总结

  1. 核心载体:Want 是组件间通信的核心载体,显式 Want 用于跨应用精准启动,隐式 Want 用于跨应用通用功能调用;
  2. 隐式匹配规则:按 linkFeature→action→entities→uri+type 优先级校验,前序字段匹配失败则整体失败,所有参与匹配的字段均为精准匹配(uri路径除外);
  3. 配置关键:对外调用的 Ability 需设 exported: true,隐式启动需保证调用方 Want 字段与接收方 skills 配置完全一致;
  4. 实践原则:按场景选择匹配规则,重视异常处理和用户体验,遵循 API 12+ 规范(优先使用应用链接替代显式 Want)。

六、代码仓库

七、下节预告

下一节我们将学习 Deep Linking 与 App Linking 应用链接 的完整配置与调用,重点包括:

  1. 掌握 Deep Linking 自定义 scheme 配置、openLink 调用及 canOpenLink 校验;
  2. 掌握 App Linking HTTPS 域名配置、域名校验、参数解析及未安装应用的降级处理;
  3. 明晰 Deep Linking 与 App Linking 的安全性、适用场景核心差异,能按需选型;
  4. 掌握应用链接与 Want 结合的最佳实践,实现跨应用通信的解耦与高安全性。