HarmonyOS 6 三方SDK对接:从半接模式看Share Kit原理------系统分享的运行机制与设计理念
-
- 前言:从代码复用困境看半接模式的价值
- 一:半接模式的设计理念
-
- [1.1 全接模式 vs 半接模式](#1.1 全接模式 vs 半接模式)
- [1.2 为什么需要半接模式?](#1.2 为什么需要半接模式?)
- 二:系统分享的核心机制
-
- [2.1 基于UTD的类型匹配机制](#2.1 基于UTD的类型匹配机制)
- [2.2 组件发现与路由](#2.2 组件发现与路由)
- [2.3 分享面板的组装机制](#2.3 分享面板的组装机制)
- [2.4 意图框架与推荐联系人](#2.4 意图框架与推荐联系人)
- 三:支付宝分享的接入逻辑
-
- 3.1Scheme回调与Ability路由-完整的支付宝分享流程
- [3.2 从支付宝SDK对接看Share Kit的设计思想](#3.2 从支付宝SDK对接看Share Kit的设计思想)
- 四:选型决策与最佳实践
-
- [4.1 基础选型决策树](#4.1 基础选型决策树)
- [4.2 设备能力带来的选型扩展](#4.2 设备能力带来的选型扩展)
- 常见问题
- 总结
前言:从代码复用困境看半接模式的价值
在上一篇文章中,我们将行程海报分享功能改造为支付宝AA收款,但受限于篇幅,还有一个核心问题悬而未决:如何根据不同的分享平台,提供差异化的分享内容?

这个问题看似简单,却直指系统分享的根本局限。让我们回顾一下上篇的场景:
- 分享到微信:只需要把行程海报图片和链接发给朋友,系统分享完全够用
- 分享到支付宝:需要让朋友能直接点击付款,这是一个完整的业务闭环,必须用支付宝SDK
同样是分享行程,两个平台的要求截然不同。如果沿用全接模式,我们只能给所有平台提供相同的内容,无法满足支付宝的业务诉求。这正是半接模式的核心价值所在:
半接模式让我们可以在同一个自定义面板中,同时提供"系统分享"和"三方SDK"两种能力------用系统分享覆盖通用场景,用三方SDK满足业务闭环,各取所长。
但半接模式只是Share Kit的冰山一角。当我们在上篇写下这些代码时,背后隐藏着更多值得深究的问题:
关于系统分享:
- 为什么调用
controller.show()就能弹出分享面板?(分享面板的组装机制) - 为什么有些应用能出现在面板里,有些不能?(UTD类型匹配)
- 分享面板里的"最近联系"是怎么来的?(意图框架与数据捐献)
关于支付宝分享:
- 为什么需要配置Scheme回调?(Ability路由机制)
- 为什么分享结果会回到
onNewWant?(应用生命周期管理) - 支付宝分享和系统分享在架构上有什么本质区别?
这些问题,正是本文要深入探讨的。我们将从上篇的半接模式案例出发,一步步深入Share Kit的内核,理解这些机制背后的设计思想。
一:半接模式的设计理念
1.1 全接模式 vs 半接模式
在深入原理之前,我们先了解这两个核心概念。Share Kit为宿主应用提供了两种接入模式,以应对开发者接入系统分享能力时的不同诉求。
| 维度 | 全接模式 | 半接模式 |
|---|---|---|
| 实现方式 | 直接调用controller.show()拉起系统面板 |
自定义面板 + 系统分享入口 |
| 控制权 | 系统控制 | 应用主导,系统补充 |
| UI定制 | 不可定制 | 完全自定义 |
| 商业空间 | 无 | 可植入推广、业务入口 |
| 开发成本 | 低 | 中 |
| 适用场景 | 通用分享需求 | 有商业诉求或业务闭环需求 |

上图的行程海报案例,就是典型的半接模式:
- 我们自定义了面板(多个按钮)
- 系统分享作为入口之一
- 支付宝SDK作为另一个入口("支付宝AA收款")
根据华为官方文档,半接模式的UI设计有明确的规范:为了确保用户获得良好的分享体验,图标应使用HarmonyOS系统资源
$r('sys.symbol.share'),文本使用"系统分享",不应自行更改。
1.2 为什么需要半接模式?
场景一:业务闭环
比如产品经理说:"我们想在分享面板里放自己的推广入口。"全接模式做不到,半接模式可以。上篇的支付宝AA收款,必须用支付宝SDK才能实现。半接模式允许我们在系统分享之外,接入三方SDK,实现完整的支付闭环。
场景二:高频操作
有些高频操作(如"复制链接"、"保存图片")放在自定义面板里,比藏在系统面板深层菜单里更方便。
但半接模式不是万能的,它有明确的边界:
- 系统分享部分:仍然遵循系统规则(UTD匹配、权限控制)
- 三方SDK部分:遵循各平台的规范(Scheme回调、签名验证)
- 自定义面板:应用完全掌控,但需要自行维护
上篇的案例完美体现了这个边界:
- 微信分享走系统渠道,遵循系统规则
- 支付宝走SDK渠道,遵循支付宝规范
- 面板由我们自定义,两个按钮各司其职
二:系统分享的核心机制

在深入理解系统分享之前,我们需要先了解Share Kit的整体架构。根据鸿蒙官方文档,Share Kit采用了分层设计,大家可以参考官方的这张图,了解整个过程,方便后续我们的内容讲解。
| 架构层级 | 职责 | 技术组件 |
|---|---|---|
| 接入层 | 提供统一接口,支持多种内容类型 | @kit.ShareKit,支持120+内容类型 |
| 路由层 | 基于意图框架精准匹配目标应用 | 包管理服务、意图框架 |
| 传输层 | 采用分布式安全通道优化传输路径 | DeviceManager + DistributeScheduler |
2.1 基于UTD的类型匹配机制
为什么有些应用能出现在系统分享面板,有些不能?答案就在UTD。
UTD(Uniform Type Descriptor) 是UDMF(统一数据管理框架)定义的类型描述符规范,类似MIME type但更强大:
typescript
// UTD示例
"general.text" // 纯文本
"general.image" // 图片(所有格式)
"general.image.jpeg" // JPEG图片(具体格式)
"general.video" // 视频
"general.hyperlink" // 超链接
目标应用如何声明自己支持的类型?
json5
// 应用的module.json5(示意)
{
"abilities": [{
"name": "ReceiveAbility",
"exported": true,
"skills": [{
"actions": ["ohos.want.action.sendData"],
"uris": [{
"utd": "general.image", // 声明支持接收图片
"utd": "general.text", // 声明支持接收文本
"utd": "general.hyperlink" // 声明支持接收链接
}]
}]
}]
}
匹配过程:
宿主分享:utd = "general.image"
↓
查询所有 exported = true 的组件
↓
过滤出 actions 包含 "ohos.want.action.sendData" 的组件
↓
过滤出 uris 中 utd 匹配 "general.image" 或其子类型的组件
↓
所有声明支持图片的应用都会出现 ✓
未声明的应用不会出现 ✗
这就是为什么上篇中微信能出现在分享面板------因为微信声明了支持这些UTD类型。
关键限制 :宿主应用和目标应用定义数据类型须遵照UTD规范,如支持全部图片类型,可声明为general.image。分享数据描述信息总量不能超过200KB,且分享条目总量不能超过500条。
2.2 组件发现与路由

系统分享面板里的应用列表,是包管理服务Bundle Manager动态查询的结果。
系统查询流程:
typescript
// 包管理服务内部逻辑
function queryTargetApps(utd: string): AbilityInfo[] {
// 1. 获取所有exported=true的Ability
let allAbilities = bundleManager.queryAllAbilities();
// 2. 过滤出支持该UTD的Ability
let matched = allAbilities.filter(ability => {
return ability.skills.some(skill =>
skill.actions.includes('ohos.want.action.sendData') &&
skill.uris.some(uri => matchUtd(uri.utd, utd))
);
});
// 3. 按优先级排序(使用频率、用户选择历史等)
return sortByPriority(matched);
}
2.3 分享面板的组装机制

当我们调用 controller.show() 时,Share Kit在背后做了这些事:
typescript
// 伪代码:Share Kit内部流程
function showSharePanel(shareData, context) {
// 1. 解析分享数据
let utd = shareData.getUtd();
let previewInfo = extractPreview(shareData);
// 2. 查询目标应用
let targetApps = queryTargetApps(utd);
// 3. 查询推荐联系人(从意图框架)
let recommendedContacts = queryRecommendedContacts(utd, context);
// 4. 组装面板
let panel = {
contentArea: renderPreview(previewInfo), // 内容区
recommendationArea: renderContacts(recommendedContacts), // 推荐区
shareMethodArea: renderApps(targetApps), // 分享方式区
operationArea: renderSystemOperations(utd) // 操作区
};
// 5. 显示面板
showPanel(panel);
}
这就是为什么系统面板会有四个区域------每个区域都有独立的职责和数据来源:
| 区域 | 职责 |
|---|---|
| 内容预览区 | 显示分享内容的预览图、标题、选择状态,帮助用户确认分享内容 |
| 推荐区 | 对接华为分享和意图框架,通过算法推荐最近联系人和支持的设备 |
| 分享方式区 | 展示所有支持当前分享内容的目标应用 |
| 操作区 | 系统提供的辅助功能,包括复制、保存、打印等 |

2.4 意图框架与推荐联系人

上篇中可能没注意到,系统分享面板底部有时会出现"最近联系"的推荐。这是**意图框架(Intent Framework)**在起作用。
数据捐献(社交应用需要实现):
typescript
import { intentFramework } from '@kit.IntentFramework';
// 用户与朋友聊天后,应用捐献这次交互
intentFramework.donateInteraction({
type: 'chat',
contact: {
id: 'contact_001',
name: '张三',
avatar: '...',
app: 'com.example.im' // 应用的bundleName
},
timestamp: Date.now()
});
数据查询(Share Kit查询):
typescript
// Share Kit获取推荐联系人
let contacts = intentFramework.queryRecommendedContacts({
utd: 'general.image', // 当前分享的内容类型
limit: 3, // 最多3个
context: currentUserContext // 当前用户上下文
});
隐私保护机制:
- 应用只能捐献自己的数据,不能读取其他应用的数据
- 意图框架只返回推荐结果,不暴露原始数据
- 用户可以在设置中清空意图数据
这就是为什么分享面板里会出现"最近联系"------你的聊天行为在默默影响着推荐结果。
你也可以通过配置操作区 ,像图片海报这种的,分享到中转站进行操作。

不同设备对Share Kit能力的支持存在差异,开发前需重点关注:
| 分享能力 | 手机 | 平板 | PC/2in1 | TV |
|---|---|---|---|---|
| 系统分享(应用间) | 支持 | 支持 | 支持 | 部分支持(仅分享到周边设备,无应用选择) |
| 碰一碰分享 | 支持 | 不支持 | 支持 | 不支持 |
| 隔空传送 | 支持 | 支持 | 支持 | 不支持 |
三:支付宝分享的接入逻辑

对于支付宝来说,业务闭环是最重要的。上篇的AA收款场景,必须知道:
- 用户是否成功分享?(用于统计)
- 用户取消的原因?(用于优化)
- 后续支付流程如何衔接?
系统分享给不了这么细的数据,所以支付宝选择了自建SDK。
3.1Scheme回调与Ability路由-完整的支付宝分享流程
上篇中我们配置了Scheme:
json5
{
"abilities": [
{
"name": "EntryAbility",
"skills": [
{
"uris": [
{
"scheme": "alipayshare"
}
]
}
]
}
]
}
这个配置的作用是:告诉系统,当有应用通过 alipayshare:// 开头的URL拉起时,交给EntryAbility处理。
完整的回调流程:
1. 用户从支付宝返回应用
2. 支付宝通过 Scheme 拉起应用:alipayshare://result?code=9000&message=success
3. 系统解析Scheme,找到对应的Ability
4. 调用该Ability的 onNewWant() 方法
5. 应用在 onNewWant() 中处理回调结果
typescript
// 上篇中的处理代码
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (want.parameters) {
// 将参数交给支付宝SDK解析
APAPIFactory.createZFBApi(this.context, Constants.APP_ID)
.handleIntent(want.parameters, this);
}
}
| 架构层级 | 系统分享 | 支付宝分享 |
|---|---|---|
| 应用层 | 调用controller.show() |
调用api.sendReq() |
| 框架层 | Share Kit处理 | SDK处理 |
| 通信层 | 分布式软总线 | HTTPS + Scheme |
| 目标应用 | 通过Want拉起 | 通过SDK协议通信 |
本质区别:
- 系统分享:系统作为中介,协调宿主和目标应用。其底层依赖鸿蒙的IPC(进程间通信)机制,通过Binder-like驱动实现跨进程调用。
- 支付宝分享:支付宝SDK直接和支付宝App通信,系统只负责Scheme路由
这就是为什么上篇中两种分享的实现方式差异那么大------它们在架构层面就完全不同。
3.2 从支付宝SDK对接看Share Kit的设计思想
回顾上篇的半接模式实现:
应用层(我们的自定义面板)
├── 系统分享入口 → 交给Share Kit处理
└── 支付宝入口 → 交给支付宝SDK处理
这种设计的背后,是Share Kit的分层思想:
- 内容层:宿主应用负责提供分享内容(图片、文本、链接)
- 推荐层:意图框架负责推荐联系人
- 应用层:包管理服务负责发现目标应用
- 操作层:系统提供通用操作(复制、保存)
每层独立演化,互不干扰。
Share Kit不关心"用户想分享到哪个应用",只关心"用户分享的是什么类型的内容"。这种设计:
- 解耦了宿主和目标应用:双方只需遵循UTD规范
- 生态友好:新应用加入即可被自动发现
- 未来兼容:新内容类型出现时,只需定义新的UTD
上篇中,我们分享图片时设置utd: general.image,系统就能自动找到所有支持图片的应用。
Share Kit的设计也体现了华为对生态的思考:
| 层面 | 开放程度 | 说明 |
|---|---|---|
| 内容类型 | 开放 | 任何应用可定义自己的UTD |
| 应用发现 | 开放 | 任何应用可注册接收分享 |
| 推荐数据 | 封闭 | 应用只能捐献,不能读取 |
| UI定制 | 半开放 | 半接模式允许定制,全接模式统一 |
这种平衡既保证了生态的活力(开放),又保护了用户隐私(封闭)。
半接模式,正是利用了这个"半开放"的特性------我们定制了面板,但系统分享部分仍然遵循系统规则。
四:选型决策与最佳实践
4.1 基础选型决策树
是
否
是
否
分享需求
是否需要三方SDK
实现业务闭环?
半接模式
是否有UI定制需求?
半接模式
(定制UI)
全接模式
(直接用系统)
半接模式
| 模式 | 适用场景 | 典型案例 |
|---|---|---|
| 全接模式 | 通用分享、快速实现、无商业诉求 | 工具类App、MVP产品 |
| 半接模式 | 业务闭环、商业推广、高频操作 | 出行App(AA收款)、电商App |
上篇的行程海报案例属于典型的半接模式应用场景------因为需要支付宝AA收款的业务闭环。
如果您选择半接模式,需要注意以下几点:
- UI规范 :系统分享入口的图标应使用HarmonyOS系统资源
$r('sys.symbol.share'),文本使用"系统分享" - 职责分离:系统分享部分交给Share Kit,三方SDK部分交给对应SDK
- 生命周期管理:确保在页面销毁时取消所有监听
4.2 设备能力带来的选型扩展
前面的基础决策树主要考虑了"是否需要三方SDK"和"是否需要UI定制"。但如果你的App需要覆盖更多场景,还可以引入华为的特色分享能力:
是
否
是
否
分享需求
是否需要线下快速传输?
(无需网络、面对面)
叠加碰一碰分享
是否需要手势交互?
(演示场景、大屏)
叠加隔空传送
维持基础选型结果
这些特色能力与基础选型是叠加关系,而不是替代关系。你可以根据业务场景,在选定的模式上增加这些能力:
| 能力组合 | 适用场景 | 示例 |
|---|---|---|
| 半接模式 + 碰一碰分享 | 线上线下全覆盖 | 行程海报既可分享到微信/支付宝,朋友在身旁时碰一碰手机就能直接接收 |
| 半接模式 + 隔空传送 | 演示场景+业务闭环 | 在会议上演示行程规划时,隔空传送给同事,同时保留AA收款能力 |
| 全接模式 + 碰一碰分享 | 快速传输工具 | 简单的文件分享工具,既支持系统面板,也支持碰一碰 |
对于上篇的行程海报App:
- 基础选型已经是半接模式(因为需要支付宝AA收款)
- 如果增加碰一碰分享能力,用户聚会结束碰一下手机就能AA收款,体验会更流畅
- 如果增加隔空传送能力,在朋友面前演示行程时可以直接隔空传送,交互更自然
如果您决定引入这些特色能力,以下是核心API的快速参考:
| 能力 | 核心API | 关键参数 |
|---|---|---|
| 碰一碰分享 | harmonyShare.on('knockShare', callback) |
支持正常分享、拒绝分享、延迟更新等模式 |
| 隔空传送 | harmonyShare.on('gesturesShare', callback) |
需要传递windowId,支持纯净/沉浸式/白底模式 |
完整的使用示例和注意事项,可以参考官方示例文档。
常见问题
Q1:半接模式下,系统分享部分还能收到结果回调吗?
可以。上篇中我们用了:
typescript
controller.on('shareCompleted', (result) => {
console.info(`分享完成,目标应用: ${result.targetAbilityInfo.name}`);
});
这个回调仍然有效,但只能知道分享给了哪个应用,不知道具体给谁(隐私保护)。
Q2:意图框架的推荐数据能清空吗?
可以。用户在"设置 → 隐私 → 意图框架"中可以:
- 查看所有捐献的数据
- 清空特定应用的数据
- 一键清空所有数据
这也是隐私保护的一部分。
Q3:如果我的App需要同时支持微信朋友圈和支付宝AA,该怎么设计?
这正是半接模式的用武之地:
- 微信朋友圈:集成微信SDK(因为系统分享不支持朋友圈)
- 支付宝AA:集成支付宝SDK(因为需要支付闭环)
- 其他通用分享:用系统分享(省事)
自定义面板上放三个按钮,各司其职。
Q4:分享过程中,临时文件的生命周期如何管理?
根据Share Kit的最佳实践,临时文件应在分享完成后删除:
typescript
// 创建临时文件
const tempDir = getContext().cacheDir;
const filePath = `${tempDir}/share_temp_${Date.now()}.jpg`;
// 分享完成后清理
controller.on('shareCompleted', () => {
fs.unlink(filePath); // 清理临时文件
});
总结
从上篇的半接模式案例出发,我们看到了Share Kit的完整图景:
| 层面 | 机制 | 上篇中的体现 |
|---|---|---|
| 类型系统 | UTD匹配 | utd: general.image |
| 应用发现 | 包管理服务 | 应用列表动态生成 |
| 推荐系统 | 意图框架 | "最近联系"推荐 |
| UI组装 | 面板四区域 | 内容区+应用区 |
| 回调机制 | 事件监听 | on('shareCompleted') |
| 传输层 | 分布式软总线 | 跨应用数据传输 |
现在回头看上篇的代码,每一行都有了新的理解:
typescript
// 原来只是"设置分享内容"
// 现在知道:这是在定义UTD类型,影响哪些应用能接收
let shareData = new systemShare.SharedData({
utd: utd.UniformDataType.IMAGE, // 只有支持图片的应用才能出现
uri: fileUri.getUriFromPath(filePath),
});
// 原来只是"拉起面板"
// 现在知道:背后经历了查询应用、查询推荐、组装面板等复杂流程
controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE,
previewMode: systemShare.SharePreviewMode.DETAIL,
});
// 原来只是"监听结果"
// 现在知道:这是在接收包管理服务返回的目标应用信息
controller.on('shareCompleted', (result) => {
console.info(`分享完成,目标应用: ${result.targetAbilityInfo.name}`);
});
这就是Share Kit的设计哲学:基础能力开放共享,深度业务各自精彩。它给了开发者选择的权利,让每个应用都能找到最适合自己的分享方案。
从半接模式这个小切口,我们看到了整个Share Kit的设计思想。希望这篇文章能帮你从"会用"进阶到"懂它",在HarmonyOS生态中走得更远。