从指令魔方 APP 出发,分享鸿蒙 Share Kit 的升级版——碰一碰
大家好,我是陈杨,8 年前端老兵转型鸿蒙开发,也是一名鸿蒙极客。从前端到鸿蒙,我靠的是 “三天上手 ArkTS” 的技术嗅觉,以及 “居安思危” 的转型魄力。这三年,我不玩虚的,封装了开源组件库「莓创图表」,拿过创新赛大奖,更带着团队上架了 11 款自研 APP,涵盖工具、效率、创意等多个领域。想体验我的作品?欢迎搜索体验:指令魔方、JLPT、REFLEX PRO、国潮纸刻、Wss 直连、Zeni
大家好,我是陈杨,8 年前端老兵转型鸿蒙开发,也是一名鸿蒙极客。从前端到鸿蒙,我靠的是 “三天上手 ArkTS” 的技术嗅觉,以及 “居安思危” 的转型魄力。这三年,我不玩虚的,封装了开源组件库「莓创图表」,拿过创新赛大奖,更带着团队上架了 11 款自研 APP,涵盖工具、效率、创意等多个领域。想体验我的作品?欢迎搜索体验:指令魔方、JLPT、REFLEX PRO、国潮纸刻、Wss 直连、ZenithDocs Pro、圣诞相册、CSS 特效。
我们前面讲了最传统的分享知识,用户的操作往往需要经历“打开应用→选择文件→搜索设备→确认传输”的繁琐流程,甚至要打断当前操作(如暂停视频、退出游戏)。而HarmonyOS的Share Kit推出的“碰一碰分享”能力,通过“设备轻触”这一直观交互,将跨端分享简化为“一碰即传”,支持图片、文件、Wi-Fi、组队邀请等多场景,彻底重构了跨设备交互体验。我们将结合指令魔方与官方开发文档,从手机间分享、手机与PC/2in1协同两大场景,详解开发流程、核心代码与避坑要点。
一、碰一碰分享核心基础:环境与核心概念
在开始开发前,需先明确功能依赖的环境要求与核心逻辑,避免因版本不兼容导致功能失效。
1.1 环境要求(必看!)
不同设备间的碰一碰分享,对系统版本和开发工具的要求不同,具体如下:
| 分享场景 | 设备系统要求 | 集成开发环境 |
|---|---|---|
| 手机与手机 | 双端均为HarmonyOS NEXT Release及以上(推荐5.0+) | DevEco Studio NEXT Beta1+ |
| 手机与PC/2in1 | 手机:同上方;PC/2in1:HarmonyOS 6.0.0 Beta1+ | DevEco Studio 6.0.0 Beta1+ |
关键检查:通过canIUse判断设备是否支持碰一碰能力,避免在不支持的设备上触发无效逻辑:
// 检查设备是否支持碰一碰分享
if (canIUse('SystemCapability.Collaboration.HarmonyShare')) {
console.log("设备支持碰一碰分享,可初始化相关逻辑");
// 后续注册碰一碰事件...
} else {
console.log("设备不支持碰一碰分享,需隐藏相关引导");
}
1.2 核心业务流程
无论哪种场景,碰一碰分享的核心流程都遵循“注册→触发→传输→解除”四步,以手机与手机为例:
- 注册事件:宿主应用进入可分享界面(如选中图片、打开Wi-Fi详情)时,注册碰一碰分享监听;
- 触发交互:双端设备亮屏、解锁且开启华为分享(关闭则弹窗提示开启),顶端轻碰;
- 数据传输:源端构造分享数据(如图片URI、链接)并发送,目标端接收并拉起对应应用;
- 解除监听:离开可分享界面(如关闭图片、退出页面)时,解除碰一碰监听,避免内存泄漏。
二、手机与手机碰一碰开发:从预览到异常处理
手机间碰一碰是最基础的场景,需重点关注预览体验、数据传输方式、安全策略与异常兜底,以下分模块详解。
2.1 第一步:引导用户触发——注册碰一碰事件
用户可能不清楚“何时可碰”,需在可分享界面添加引导(文本+动图),提升交互感知。
2.1.1 引导资源集成
华为提供统一的碰一碰引导动图,需:
- 下载资源包:碰一碰引导资源(完整下载
knock_share_guide目录); - 放置路径:将资源放入应用
entry/src/main/resources/rawfile目录; - 界面引导:在可分享界面(如图片预览页)显示文本提示+动图,示例文案:
- “可碰一碰分享至HarmonyOS 5及以上版本手机”
- “对方需在控制中心开启‘华为分享’”
2.1.2 注册监听事件
在页面aboutToAppear生命周期中注册碰一碰事件,aboutToDisappear中解除,确保资源释放:
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { systemShare, harmonyShare } from '@kit.ShareKit';
import { fileUri } from '@kit.CoreFileKit';
import { UIContext, Context } from '@kit.ArkUI';
@Component
export default struct ImageSharePage {
// 页面进入时注册碰一碰监听
aboutToAppear(): void {
this.registerKnockShare();
}
// 页面销毁时解除监听
aboutToDisappear(): void {
this.unregisterKnockShare();
}
// 注册碰一碰分享事件
private registerKnockShare() {
// 配置监听参数(windowId需替换为实际页面的窗口ID,不可用示例值)
const capabilityRegistry: harmonyShare.SendCapabilityRegistry = {
windowId: 1001, // 实际开发中通过UIContext获取真实windowId
};
// 监听碰一碰事件,触发时构造并发送数据
harmonyShare.on('knockShare', capabilityRegistry, (sharableTarget: harmonyShare.SharableTarget) => {
this.buildShareData(sharableTarget);
});
}
// 解除碰一碰分享监听
private unregisterKnockShare() {
const capabilityRegistry: harmonyShare.SendCapabilityRegistry = {
windowId: 1001, // 与注册时的windowId一致
};
harmonyShare.off('knockShare', capabilityRegistry);
}
// 构造分享数据(核心逻辑)
private buildShareData(sharableTarget: harmonyShare.SharableTarget) {
// 1. 获取预览图URI(示例:本地图片路径,实际需替换为业务图片路径)
const uiContext: UIContext = this.getUIContext();
const context: Context = uiContext.getHostContext() as Context;
const imagePath = context.filesDir + '/shared_image.jpg';
const thumbnailUri = fileUri.getUriFromPath(imagePath);
// 2. 构造分享数据(utd类型根据内容调整,图片可设为IMAGE,链接设为HYPERLINK)
const shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.IMAGE, // 图片类型
content: thumbnailUri, // 图片URI
title: '旅行照片', // 卡片标题(可选,根据模板决定)
description: '2025年夏日旅行', // 卡片描述(可选)
thumbnailUri: thumbnailUri, // 预览图URI
});
// 3. 发起分享(必须在3秒内调用,否则超时失败)
sharableTarget.share(shareData);
}
build() {
// 页面布局(省略,需包含图片预览+碰一碰引导动图)
}
}
2.2 第二步:优化视觉体验——设置分享预览
分享卡片的预览效果直接影响用户接受度,Share Kit提供3种卡片模板,需根据分享内容类型选择:
| 模板类型 | 适用场景 | 配置要求 | 布局约束 |
|---|---|---|---|
| 纯图片布局 | 文件、图片(无需文字说明) | 仅传递thumbnailUri |
预览图宽高比≥1:4,超出部分裁剪 |
| 沉浸式大卡布局 | 链接(需展示文字) | 同时传递title+description+thumbnailUri,且预览图宽高比<1:1 |
标题最多2行(超出省略),描述1行,显应用图标 |
| 白卡上下布局 | 链接(需展示文字) | 同时传递title+description+thumbnailUri,且预览图宽高比>1:1 |
同上,预览图仅占卡片上方,不铺满 |
2.2.1 预览图最佳实践
预览图分辨率影响加载速度与清晰度,推荐按以下标准设置(文档2):
| 预览图来源 | 推荐比例 | 推荐分辨率(px) |
|---|---|---|
| 应用海报 | 3:4 | 最小600_800,最大3000_4000 |
| 用户上传图片 | 无限制 | 最大3000*4000(避免过大) |
2.2.2 预览图延迟更新(解决云端图片问题)
若预览图存储在云端(如OSS),碰一碰触发时可能未下载完成,导致卡片空白。可先发送核心数据,待图片下载后更新预览:
private buildShareData(sharableTarget: harmonyShare.SharableTarget) {
// 1. 先发送无预览图的核心数据(用系统默认图占位)
const shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.HYPERLINK,
content: 'https://example.com/travel', // 分享链接
title: '旅行攻略',
description: '超全景点指南',
});
sharableTarget.share(shareData);
// 2. 模拟云端图片下载(实际项目中替换为真实下载回调)
setTimeout(async () => {
const uiContext: UIContext = this.getUIContext();
const context: Context = uiContext.getHostContext() as Context;
// 假设下载完成,获取本地路径
const downloadedImagePath = context.filesDir + '/downloaded_poster.jpg';
const newThumbnailUri = fileUri.getUriFromPath(downloadedImagePath);
// 3. 更新预览图
sharableTarget.updateShareData({
thumbnailUri: newThumbnailUri,
});
}, 3000); // 实际不建议用固定延迟,应监听下载完成事件
}
2.3 第三步:选择数据传输方式——App Linking vs Deep Linking
若分享内容为“链接”(如商品页、文章页),需通过以下两种方式实现应用跳转,核心区别在于“未安装应用时的处理逻辑”。
2.3.1 App Linking(推荐)
优势:无论目标端是否安装应用,均能直达内容——
- 已安装:直接拉起应用并打开链接;
- 未安装:跳转应用市场(需集成App Linking Kit);
- 支持延迟链接:应用下载后仍能获取之前的分享链接。
示例代码:
private buildShareData(sharableTarget: harmonyShare.SharableTarget) {
const shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.HYPERLINK, // 必须设为HYPERLINK
content: 'https://sharekitdemo.drcn.agconnect.link/ZB3p', // App Linking链接
title: '华为商城新品',
description: 'nova 14系列限时优惠',
thumbnailUri: 'file:///data/storage/.../poster.jpg', // 预览图URI
});
sharableTarget.share(shareData);
}
2.3.2 Deep Linking(简单但有局限)
局限:仅在目标端已安装应用时生效,未安装则弹窗提示“暂无可用打开方式”。
示例代码:
// 与App Linking代码类似,仅content替换为Deep Linking链接
content: 'myapp://product/detail?id=123', // 自定义Deep Linking协议
2.4 第四步:保障安全与体验——安全策略与异常处理
2.4.1 安全策略:明确设备/账号身份
为避免用户接收陌生设备的分享,Share Kit会显示发送端/接收端的身份信息(需HarmonyOS NEXT 5.0.0.123 SP16及以上版本):
| 角色 | 对端已登录华为账号 | 对端未登录华为账号 |
|---|---|---|
| 发送端 | 显示接收端账号昵称+头像 | 显示接收端设备名(如“Mate 70”) |
| 接收端 | 显示发送端账号昵称+头像 | 显示发送端设备名 |
注意:SP16之前的版本不显示任何身份信息,开发时需考虑版本兼容。
2.4.2 异常场景处理
当无法发起分享时,需主动提示用户,避免用户等待。
场景1:当前界面无可分享内容
harmonyShare.on('knockShare', (sharableTarget: harmonyShare.SharableTarget) => {
// 调用clarifyNonShare终止分享,并提示用户
sharableTarget.clarifyNonShare({
message: '当前界面不支持碰一碰,请在图片预览或文件详情页尝试'
});
});
效果:系统弹窗提示用户,引导至可分享界面。
场景2:分享内容下载失败(如云端图片下载超时)
harmonyShare.on('knockShare', (sharableTarget: harmonyShare.SharableTarget) => {
// 模拟下载失败
const downloadFailed = true;
if (downloadFailed) {
// 调用reject终止分享,指定错误码
sharableTarget.reject(harmonyShare.SharableErrorCode.DOWNLOAD_ERROR);
}
});
效果:系统提示“分享内容下载失败,请稍后重试”。
三、手机与PC/2in1碰一碰开发:跨端协同新体验
手机与PC/2in1的碰一碰进一步拓展场景(如手机传图到PC编辑、PC传文档到手机),需关注双向分享限制与沙箱接收特性。
3.1 核心约束与环境
- 账号要求:手机与PC/2in1必须登录相同华为账号;
- 设备形态:仅支持手机直板态/折叠手机直板态,不支持折叠态;
- 角度约束(触发成功率关键):
- 手机与PC屏幕俯视夹角≤5°(尽量平行);
- 侧视夹角>35°(避免过度倾斜);
- 正视夹角≤25°(正对屏幕);
- 保护壳:仅支持官方轻薄保护壳,过厚壳会影响感应。
3.2 双向分享限制(避坑要点)
从HarmonyOS 6.0.0 Beta5开始,手机与PC/2in1不支持“双向同时分享”,遵循以下优先级:
- 若手机前台有可分享内容(如打开图片),则手机为发送端,PC为接收端;
- 若手机前台无内容,但PC前台有可分享内容(如打开文档),则PC为发送端,手机为接收端;
- 若两者均无内容,触发“无内容分享”提示。
注意:Beta5之前的版本支持双向分享(双方同时发送接收),开发时需根据版本适配逻辑。
3.3 分享内容直达应用:沙箱接收
PC/2in1支持“沙箱接收”,即手机碰PC后,文件直接传入PC应用的沙箱目录,无需用户选择保存路径,实现“直达编辑”(如手机传图到PC版PS,直接打开编辑)。
3.3.1 沙箱接收开发步骤
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { systemShare, harmonyShare } from '@kit.ShareKit';
import { common } from '@kit.AbilityKit';
@Component
export default struct PCImageEditorPage {
aboutToAppear(): void {
this.registerSandboxReceive();
}
aboutToDisappear(): void {
this.unregisterSandboxReceive();
}
// 注册沙箱接收事件(仅支持文件类型)
private registerSandboxReceive() {
const capabilityRegistry: harmonyShare.RecvCapabilityRegistry = {
windowId: 2001, // PC应用窗口ID
capabilities: [
{
utd: utd.UniformDataType.IMAGE, // 仅接收图片类型
maxSupportedCount: 5 // 最多接收5张图片
}
]
};
// 监听数据接收事件
harmonyShare.on('dataReceive', capabilityRegistry, (receivableTarget: harmonyShare.ReceivableTarget) => {
const uiContext = this.getUIContext();
const context = uiContext.getHostContext() as common.UIAbilityContext;
// 指定文件保存路径(应用沙箱目录)
const savePath = context.filesDir + '/received_images/';
// 接收文件
receivableTarget.receive(savePath, {
// 每接收一个文件触发
onDataReceived: (sharedData: systemShare.SharedData) => {
const records = sharedData.getRecords();
records.forEach(record => {
console.log(`接收文件:${record.uri}`);
// 触发应用编辑逻辑(如打开图片编辑界面)
this.openImageEditor(record.uri);
});
},
// 接收完成/失败触发
onResult: (resultCode: harmonyShare.ShareResultCode) => {
if (resultCode === harmonyShare.ShareResultCode.SHARE_SUCCESS) {
console.log("所有文件接收完成");
} else {
console.log(`接收失败,错误码:${resultCode}`);
}
}
});
});
}
// 解除沙箱接收监听
private unregisterSandboxReceive() {
const capabilityRegistry: harmonyShare.RecvCapabilityRegistry = {
windowId: 2001,
capabilities: [{ utd: utd.UniformDataType.IMAGE, maxSupportedCount: 5 }]
};
harmonyShare.off('dataReceive', capabilityRegistry);
}
// 打开图片编辑界面
private openImageEditor(imageUri: string) {
// 业务逻辑:跳转编辑页并加载图片
}
build() {
// PC应用界面(省略)
}
}
3.3.2 拒绝沙箱接收
若应用当前无法接收(如编辑中),可调用reject拒绝:
harmonyShare.on('dataReceive', (receivableTarget: harmonyShare.ReceivableTarget) => {
// 业务判断:当前正在编辑,拒绝接收
if (this.isEditing) {
receivableTarget.reject(harmonyShare.ReceivableErrorCode.NO_RECEIVABLE_ERROR);
}
});
四、特殊场景:组队邀请开发
在游戏、运动类应用中,可通过碰一碰发起“组队邀请”,需避免“双方同时邀请”导致的冲突,此时需使用单向分享能力。
4.1 核心代码:注册单向分享
aboutToAppear(): void {
const capabilityRegistry: harmonyShare.SendCapabilityRegistry = {
windowId: 3001,
sendOnly: true // 申明“仅发送邀请,不接收邀请”
};
harmonyShare.on('knockShare', capabilityRegistry, (sharableTarget) => {
// 构造组队链接(含房间ID、邀请者信息)
const teamLink = `mygame://team/join?id=12345&inviter=user1`;
const shareData = new systemShare.SharedData({
utd: utd.UniformDataType.HYPERLINK,
content: teamLink,
title: '邀请加入游戏战队',
description: '点击立即组队开黑',
thumbnailUri: 'file:///.../team_poster.jpg'
});
sharableTarget.share(shareData);
});
}
4.2 冲突处理
- 若双方均设置
sendOnly: true:系统终止分享,提示“请任意一方退出当前应用后再试”; - 若仅一方设置:分享成功,目标端拉起应用并通过
onNewWant获取组队链接。
获取组队链接:
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class GameAbility extends UIAbility {
// 应用首次启动时获取链接
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (want.uri) {
console.log(`收到组队邀请:${want.uri}`);
this.joinTeam(want.uri); // 解析链接并加入队伍
}
}
// 应用已启动时获取链接
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (want.uri) {
this.joinTeam(want.uri);
}
}
private joinTeam(teamUri: string) {
// 解析URI中的房间ID、邀请者信息,发起加入请求
}
}
五、开发最佳实践总结
- 环境检查优先:通过
canIUse判断设备能力,避免无效逻辑; - 资源及时释放:在
aboutToDisappear中解除碰一碰监听,防止内存泄漏; - 预览图适配:按推荐分辨率设置预览图,云端图片用延迟更新兜底;
- 异常全面覆盖:处理“无内容”“下载失败”等场景,避免用户无反馈;
- 跨端版本适配:手机与PC的系统版本要求不同,双向分享限制需区分版本;
- 用户引导清晰:在可分享界面添加文本+动图引导,降低使用门槛。
希望你们可以通过以上开发指南,可快速实现HarmonyOS碰一碰分享功能,为用户提供“一碰即传”的跨端体验。随着鸿蒙生态的扩展,未来碰一碰还将支持更多设备(如平板、智慧屏),进一步丰富全场景交互。
更多推荐



所有评论(0)