前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

深度链接是 flutter_web_auth 在 OpenHarmony 上能工作的基础设施。没有深度链接,浏览器完成认证后就没办法把结果回传给 App。这篇把 OpenHarmony 的深度链接机制从底层讲清楚——Want 是什么、skills 怎么配、singleton 为什么必须、系统怎么匹配。

一、什么是深度链接

1.1 定义

深度链接(Deep Link)是一种通过 URL 直接打开 App 特定页面的技术。

普通链接:https://example.com/page → 在浏览器中打开
深度链接:myapp://callback?code=abc → 打开 myapp 应用

1.2 URL Scheme vs App Links

在这里插入图片描述

1.3 flutter_web_auth 使用的是 URL Scheme

FlutterWebAuth.authenticate(
  url: "https://auth.example.com/authorize?redirect_uri=myapp://callback",
  callbackUrlScheme: "myapp",  // URL Scheme
);

💡 flutter_web_auth 使用 URL Scheme 而不是 App Links,因为 URL Scheme 配置简单,不需要域名验证。对于 OAuth 回调来说,URL Scheme 的安全性已经足够(配合 PKCE 使用)。

二、OpenHarmony 的 Want 机制

2.1 什么是 Want

Want 是 OpenHarmony 中 Ability 之间通信的载体,类似 Android 的 Intent。

import { Want } from '@kit.AbilityKit';

let want: Want = {
  action: 'ohos.want.action.viewData',
  uri: 'myapp://callback?code=abc123',
};

2.2 Want 的核心字段

字段 类型 说明 示例
action string 操作类型 ohos.want.action.viewData
uri string 目标 URI myapp://callback?code=abc
bundleName string 目标应用包名 com.example.myapp
abilityName string 目标 Ability 名 EntryAbility
entities string[] 实体类别 ["entity.system.browsable"]

2.3 隐式 Want vs 显式 Want

// 显式 Want:指定目标应用和 Ability
let explicitWant: Want = {
  bundleName: 'com.example.myapp',
  abilityName: 'EntryAbility',
};

// 隐式 Want:通过 action + uri 匹配
let implicitWant: Want = {
  action: 'ohos.want.action.viewData',
  uri: 'myapp://callback',
};

深度链接使用的是隐式 Want——系统根据 URI 的 Scheme 找到匹配的 Ability。

三、module.json5 中的 skills 配置

3.1 宿主应用的配置

{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          },
          {
            "entities": ["entity.system.browsable"],
            "actions": ["ohos.want.action.viewData"],
            "uris": [{ "scheme": "myapp" }]
          }
        ],
        "launchType": "singleton"
      }
    ]
  }
}

3.2 skills 三要素

要素 作用
entities entity.system.browsable 表示可以从浏览器启动
actions ohos.want.action.viewData 表示处理"查看数据"操作
uris.scheme myapp 匹配 myapp:// 开头的 URI

3.3 与 Android Intent Filter 的对应

Android OpenHarmony 说明
<action android:name="android.intent.action.VIEW" /> "actions": ["ohos.want.action.viewData"] 查看操作
<category android:name="android.intent.category.BROWSABLE" /> "entities": ["entity.system.browsable"] 可从浏览器启动
<data android:scheme="myapp" /> "uris": [{"scheme": "myapp"}] Scheme 匹配

3.4 多 Scheme 配置

"uris": [
  { "scheme": "myapp" },
  { "scheme": "com.example.myapp" }
]

如果你的应用需要处理多个 Scheme(比如不同的 OAuth 提供商使用不同的回调 Scheme),可以在 uris 数组中添加多个。

四、singleton launchType 的必要性

4.1 三种启动模式

模式 行为 适用场景
singleton 只有一个实例,复用已有的 flutter_web_auth 必须用
multiton 每次创建新实例 独立的页面
specified 指定实例 特殊场景

4.2 为什么必须是 singleton

场景:用户点击登录
1. App 在前台 → 打开浏览器(App 进入后台)
2. 用户在浏览器中完成认证
3. 浏览器重定向到 myapp://callback
4. 系统需要把 Want 传给 App

如果是 singleton:
→ 系统找到已有的 EntryAbility 实例
→ 调用 onNewWant(want)
→ 插件从 want.uri 中提取回调 URL ✅

如果是 multiton:
→ 系统创建新的 EntryAbility 实例
→ 调用 onCreate(want)
→ 新实例中没有 FlutterWebAuthPlugin 的 callbacks ❌
→ 认证结果丢失

4.3 singleton 的生命周期

首次启动:onCreate(want) → 创建实例
    ↓
深度链接唤起:onNewWant(want) → 复用实例
    ↓
再次深度链接:onNewWant(want) → 继续复用
    ↓
用户关闭:onDestroy() → 销毁实例

📌 singleton 模式下,深度链接通过 onNewWant 回调传递。这是 flutter_web_auth 能工作的前提条件。如果开发者把 launchType 改成 multiton,认证回调就会丢失。

五、系统级匹配流程

5.1 从浏览器到 App 的完整流程

1. 浏览器加载 https://auth.example.com/authorize
2. 用户完成认证
3. 服务器返回 302 重定向到 myapp://callback?code=abc123
4. 浏览器尝试打开 myapp://callback?code=abc123
5. 系统查找能处理 myapp:// 的 Ability
6. 匹配规则:
   - action = ohos.want.action.viewData ✓
   - entity = entity.system.browsable ✓
   - uri.scheme = myapp ✓
7. 找到 EntryAbility(singleton 模式)
8. 调用 EntryAbility.onNewWant(want)
9. want.uri = "myapp://callback?code=abc123"

5.2 匹配优先级

如果多个 App 注册了相同的 Scheme:

情况 行为
只有一个 App 匹配 直接打开
多个 App 匹配 系统弹出选择器
没有 App 匹配 浏览器显示错误

5.3 Scheme 冲突的风险

App A 注册了 myapp://
App B 也注册了 myapp://
→ 用户需要选择打开哪个 App
→ 认证结果可能发到错误的 App

⚠️ Scheme 冲突是一个安全风险。建议使用反向域名格式的 Scheme,如 com.example.myapp,降低冲突概率。

六、深度链接调试

6.1 使用 hdc 测试深度链接

# 模拟深度链接唤起
hdc shell aa start -a EntryAbility -b com.example.myapp -U "myapp://callback?code=test123"

6.2 检查 skills 配置是否生效

# 查看应用的 Ability 信息
hdc shell bm dump -n com.example.myapp

6.3 常见调试问题

问题 原因 解决
深度链接不触发 skills 配置错误 检查 entities/actions/uris
打开了新实例 launchType 不是 singleton 修改为 singleton
onNewWant 不调用 没有在 EntryAbility 中重写 添加 onNewWant 方法
want.uri 为空 URI 格式不正确 检查 Scheme 拼写

七、与 Android 深度链接的对比

7.1 配置对比

<!-- Android: AndroidManifest.xml -->
<activity android:name=".CallbackActivity" android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myapp" />
  </intent-filter>
</activity>
// OpenHarmony: module.json5
{
  "abilities": [{
    "name": "EntryAbility",
    "skills": [{
      "entities": ["entity.system.browsable"],
      "actions": ["ohos.want.action.viewData"],
      "uris": [{ "scheme": "myapp" }]
    }],
    "launchType": "singleton"
  }]
}

7.2 核心差异

维度 Android OpenHarmony
配置格式 XML JSON5
回调接收者 独立 Activity 复用 EntryAbility
回调方法 onCreate(intent) onNewWant(want)
启动模式 singleTop/singleTask singleton
数据字段 intent.data want.uri

总结

本文全面解析了 OpenHarmony 的深度链接机制:

  1. Want 机制:类似 Android Intent,通过 action + uri 匹配
  2. skills 配置:entities + actions + uris 三要素缺一不可
  3. singleton 必须:确保深度链接通过 onNewWant 传递给已有实例
  4. 系统匹配:浏览器重定向 → 系统匹配 Scheme → 唤起 App
  5. Scheme 冲突:建议使用反向域名格式降低风险

下一篇我们讲 EntryAbility 的集成代码——宿主应用需要做什么。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

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

更多推荐