鸿蒙精准碰一碰实战:我用两台真机踩完了这些坑【鸿蒙心迹】
·
一、前言
精准碰一碰是鸿蒙 Share Kit 提供的系统级近场交互能力,区别于传统 NFC 标签碰一碰,它依托鸿蒙分布式软总线,两台鸿蒙设备靠近触碰即可触发应用自定义交互,支持链接、文件、结构化数据的跨设备传递,在资料互传、协同办公、设备联动场景非常好用,也是官方扶持推荐方向。
很多新手在接入时会遇到:碰了没反应、3s 超时失败、接收端无法拉起应用、预览图模糊、冷启动参数丢失等问题。
二、能力原理
精准碰一碰(knockShare)整体流程:
- 发送端注册监听:当前页面向系统注册knockShare能力,绑定当前窗口ID,告诉系统:本应用支持碰一碰交换;
- 设备触发触碰:两台鸿蒙设备NFC开启,靠近触碰,系统触发回调;
- 回调内组装分享数据:在回调函数中构造沉浸式分享卡片、UTD数据,调用share()发起分享;
- 接收端接收数据:接收端通过want、onNewWant回调解析传递的数据,完成页面跳转/数据加载;
- 异常处理:支持reject()主动拒绝本次碰一碰,给用户友好提示;
对比普通NFC:精准碰一碰不需要实体标签,依靠鸿蒙分布式能力,支持沉浸式大卡片预览,体验更强,适配手机、平板、PC多形态设备协作协同。
三、开发前置准备
- DevEco Studio 5.0+,SDK API21
- 两台支持 NFC 的鸿蒙设备(真机调试,模拟器无法测试碰一碰)
- AGC 后台创建应用,配置 App Linking(如果需要跨应用拉起)
- module.json5 配置权限、skills
- 依赖:
@kit.ShareKit
3.1 module.json5配置
{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{
"name": "ohos.permission.READ_USER_STORAGE",
"reason": "读取相册文件用于碰一碰分享",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
],
"skills": [
{
"entities": ["entity.system.default"],
"actions": ["ohos.want.action.sendData"],
"uris": [
{
"scheme": "myapp",
"host": "noteshare",
"path": "*"
}
]
}
]
}
}
module.json5配置讲解:
ohos.want.action.sendData是碰一碰数据接收必须注册的 action;- uris 配置自定义协议,接收端可以通过该协议被拉起;
- 存储权限为动态危险权限,代码里还需要动态申请,仅静态声明无效分享图片功能实现解决方案。
四、发送端完整代码(核心ArkTS)
功能:注册碰一碰监听,触碰后分享笔记连接+预览卡片
import { harmonyShare } from '@kit.ShareKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { UIContext } from '@ohos/ui';
import { Want } from '@kit.AbilityKit';
const TAG = 'KnockShareDemo';
@Component
struct KnockSharePage {
@State uiContext: UIContext | null = null;
// 监听注册标识,页面销毁时取消监听,防止内存泄漏
private knockShareOff: (() => void) | null = null;
aboutToAppear() {
this.uiContext = this.getUIContext();
if (!this.uiContext) return;
const windowId = this.uiContext.getWindowId();
// 注册精准碰一碰能力
const registry: harmonyShare.SendCapabilityRegistry = {
windowId: windowId
};
this.knockShareOff = harmonyShare.on('knockShare', registry, async (sharableTarget: harmonyShare.SharableTarget) => {
hilog.info(0x0000, TAG, '检测到碰一碰事件');
try {
// 【重点】提前组装数据,不要在回调里做耗时网络请求!避免3s超时
const shareData: harmonyShare.ShareData = {
title: "我的学习笔记",
description: "鸿蒙精准碰一碰开发笔记",
thumbnailUri: "file:///data/storage/el2/base/haps/entry/files/preview.jpg", // 沙箱内预览图
utd: {
type: "com.myapp.note",
content: JSON.stringify({
noteId: 10086,
title: "精准碰一碰开发",
link: "myapp://noteshare/detail?noteId=10086"
})
}
};
// 发起分享
await sharableTarget.share(shareData);
hilog.info(0x0000, TAG, '分享发起成功');
} catch (err) {
hilog.error(0x0000, TAG, '分享失败 %{public}s', JSON.stringify(err));
// 主动拒绝本次碰一碰,给系统反馈
sharableTarget.reject("数据准备失败");
}
})
}
// 页面销毁,取消监听,非常重要
aboutToDisappear() {
if (this.knockShareOff) {
this.knockShareOff();
this.knockShareOff = null;
}
}
build() {
Column() {
Text("精准碰一碰发送端")
.fontSize(22)
.margin({ bottom: 10 })
Text("打开本页面,两台鸿蒙手机触碰,即可分享笔记")
.fontSize(14)
.fontColor("#666")
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
代码讲解:
harmonyShare.on('knockShare')注册碰一碰回调,返回的函数用于注销监听,页面销毁必须调用,否则多次进入页面会重复注册;thumbnailUri优先使用沙箱文件 URI;不要直接传 PixelMap,旧参数 thumbnail 有 32KB 大小限制,图片会模糊,这是高频坑----(碰一碰视频链接分享开发实践解析);- 禁止在回调内部做网络请求、大文件读取这类耗时操作,很容易触发 3 秒超时,数据提前预加载;
sharableTarget.reject()用于异常场景终止本次碰一碰交互,提升用户体验。
五、接收端代码:解析碰一碰传递的数据
接收端分两种场景:应用冷启动、应用已经在后台运行(onNewWant)
// EntryAbility.ets
import { UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
export default class EntryAbility extends UIAbility {
onNewWant(want: Want) {
// 应用后台运行,碰一碰拉起触发这里
hilog.info(0x0000, 'Receiver', 'onNewWant, want: %{public}s', JSON.stringify(want));
this.parseKnockWant(want);
}
onCreate() {
hilog.info(0x0000, 'Receiver', 'Ability onCreate');
}
onWant(want: Want) {
// 应用冷启动,碰一碰拉起
this.parseKnockWant(want);
}
private parseKnockWant(want: Want) {
const uri = want.uri;
if (!uri) return;
// 解析自定义协议 myapp://noteshare/detail?noteId=10086
hilog.info(0x0000, 'Receiver', '收到碰一碰传递链接:%{public}s', uri);
// 路由跳转笔记详情页
this.context.router.pushUrl({ url: `pages/NoteDetail?uri=${uri}` })
}
}
代码讲解:
onNewWant是后台驻留时的入口,很多开发者只写 onCreate,后台碰一碰无法响应;- 解析 uri 参数后,使用 router 跳转对应业务页面;
- 如果接收方没有安装 App,可以在 AGC 配置 App Linking,跳转应用市场。
六、核心隐蔽代码坑
这部分属于多次踩坑!
坑 1:碰一碰回调触发,但是 share 报错,提示超时
- 现象:设备碰了,日志打印进入回调,但是分享失败。
- 原因:回调内同步 / 异步耗时过长,超过 3s 时限。
- 方案:所有分享数据、缩略图提前预加载,回调内只调用 share (),不做 IO、网络操作。
坑 2:预览卡片图片模糊
- 现象:分享卡片缩略图很糊。
- 原因:使用了
thumbnail(二进制缩略图字段,上限 32KB) - 方案:改用
thumbnailUri,把图片保存到应用沙箱,传入文件 URI。
坑 3:接收端碰一碰无法拉起应用
排查顺序:
- module.json5 skills 是否配置
ohos.want.action.sendData; - 签名:不能使用自动调试签名,必须手动签名;
- 协议 uri 是否匹配,大小写严格一致;
- 测试设备是否登录华为账号、NFC 开关打开。
坑 4:多次进入页面,碰一碰多次回调
- 原因:页面重复注册监听,离开页面没有调用注销函数。
- 方案:aboutToDisappear 执行 off 注销。
坑 5:模拟器无法测试碰一碰
说明:精准碰一碰依赖 NFC 硬件和分布式能力,必须两台鸿蒙真机(说明:一部华为pura80(新),一部华为Mate70(旧))。
七、测试流程
- 两台鸿蒙真机,都开启 NFC;
- 两台设备安装同一个应用;
- 发送端打开 KnockSharePage 页面;
- 两台手机 NFC 区域互相触碰;
- 系统弹出沉浸式分享卡片,接收端自动拉起,跳转笔记详情页;
- 验证异常场景:网络差、文件不存在,reject 提示正常。
碰一碰测试流程总览:
流程图说明:
- 预加载是核心:数据、缩略图提前准备,回调中只做分享调用,规避官方 3s 超时限制;
- 生命周期成对管理:页面出现注册监听,页面销毁注销监听,防止重复回调;
- 接收端双分支:区分冷启动
onWant和后台唤起onNewWant,很多开发者只处理其中一个,导致 bug; - 异常分支独立:文件缺失、数据异常时调用
reject主动拒绝碰一碰,给系统明确反馈,体验更好。
八、扩展方向
准碰一碰能力还可以延伸这些玩法:
- 平板 + PC 协同:碰一碰,在文档光标位置插入图片(26.0.0 版本支持获取触碰坐标)鸿蒙系统“碰一碰”功能详解与开发适配指南;
- 学习类 App:碰一碰交换学习卡片、作业、思维导图;
- 折叠屏适配:在折叠态 / 展开态下,修改碰一碰分享卡片布局;
- 结合文搜图、图像超分:碰一碰传递图片后,接收端自动超分。
九、结语
- 精准碰一碰是鸿蒙分布式协同非常有特色的能力,上手门槛不高,但约束细节很多,3 秒时限、监听生命周期、签名配置、缩略图字段,都是新手最容易踩的卡点。
- 本文 Demo 基于 API21 原生 Share Kit,没有引入第三方框架,可以直接把代码集成到自己的学习、办公类鸿蒙项目中,快速实现跨设备一碰协同。
更多推荐

所有评论(0)