跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
TypeScript大前端

鸿蒙碰一碰分享实战:从触发到沙箱接收的全流程记录

基于HarmonyOS Share Kit实现的碰一碰分享,覆盖手机间及手机与PC/2in1场景,详述环境配置、核心事件注册、预览卡片优化、App Linking与Deep Linking选型、安全策略、异常处理、沙箱接收及组队邀请开发,并总结了开发中的关键避坑点。

战神发布于 2026/6/10更新于 2026/10/2179 浏览

HarmonyOS 的'一碰分享'用了几次之后,感觉确实比传统配对快得多。但要把这个能力接入自己的应用,光看文档可能还会漏掉一些细节——尤其是手机和 PC 协同时的角度约束、沙箱接收的用法,以及云端图片的预览兜底。下面是我从零开始接入碰一碰分享的过程记录,顺便把官方示例里容易踩坑的地方标了出来。

环境先跑通

首先,版本不满足一切都白搭。两个场景的要求不一样:

分享场景设备系统要求开发环境
手机 ↔ 手机双端 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 检查一下能力,避免在不支持的设备上把引导 UI 都画出来。代码很简单:

if (canIUse('SystemCapability.Collaboration.HarmonyShare')) {
    // 注册事件
} else {
    // 隐藏入口
}

整个分享的流程就四步:注册监听 → 亮屏碰一碰 → 构造并发送数据 → 离开界面时注销。手机和 PC 的差异主要在注册的事件名和配置上,但整体骨架一样。

手机之间的碰一碰

引导用户触发

用户不知道什么时候可以碰,所以需要在可分享的页面放一个官方动图和提示文字。动图资源从华为开发者网站下载(碰一碰引导资源),放到 entry/src/main/resources/rawfile 目录。我一般会在图片预览页的角落加一句'可碰一碰分享至 HarmonyOS 5 及以上手机',同时提醒对方要开启华为分享。

注册事件的核心就是在 aboutToAppear 里调 harmonyShare.on('knockShare', ...),在 aboutToDisappear 里 off 掉。代码里注意 windowId 要拿真实 UIContext 的,别随手写个 1001。

import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { systemShare, harmonyShare } from '@kit.ShareKit';
import { fileUri } from '@kit.CoreFileKit';
import { UIContext, Context } from ;


  struct  {
    ():  {
        .();
    }

    ():  {
        .();
    }

     () {
         : harmonyShare. = {
            : , 
        };

        harmonyShare.(, capabilityRegistry,  {
            .(sharableTarget);
        });
    }

     () {
         : harmonyShare. = {
            : ,
        };
        harmonyShare.(, capabilityRegistry);
    }

     () {
         :  = .();
         :  = uiContext.()  ;
         imagePath = context. + ;
         thumbnailUri = fileUri.(imagePath);

         : systemShare. =  systemShare.({
            : utd..,
            : thumbnailUri,
            : ,
            : ,
            : thumbnailUri,
        });

        sharableTarget.(shareData);
    }

    () {
        
    }
}
'@kit.ArkUI'
@Component
export
default
ImageSharePage
aboutToAppear
void
this
registerKnockShare
aboutToDisappear
void
this
unregisterKnockShare
private
registerKnockShare
const
capabilityRegistry
SendCapabilityRegistry
windowId
1001
// 实际用 UIContext 获取
on
'knockShare'
(sharableTarget: harmonyShare.SharableTarget) =>
this
buildShareData
private
unregisterKnockShare
const
capabilityRegistry
SendCapabilityRegistry
windowId
1001
off
'knockShare'
private
buildShareData
sharableTarget: harmonyShare.SharableTarget
const
uiContext
UIContext
this
getUIContext
const
context
Context
getHostContext
as
Context
const
filesDir
'/shared_image.jpg'
const
getUriFromPath
const
shareData
SharedData
new
SharedData
utd
UniformDataType
IMAGE
content
title
'旅行照片'
description
'2025 年夏日旅行'
thumbnailUri
share
build
// 页面布局

预览卡片:别让裁剪毁了第一印象

预览卡片有三种布局:纯图片、沉浸式大卡、白卡上下布局。选错了布局,预览图可能被裁得很难看。规则不复杂:

模板类型适用场景配置要求布局约束
纯图片布局图片、文件仅传 thumbnailUri预览图宽高比≥1:4,超出裁剪
沉浸式大卡布局链接(需要文字)传 title+description+thumbnailUri,且预览图宽高比<1:1标题最多2行,描述1行,显示应用图标
白卡上下布局链接(需要文字)同上,但预览图宽高比>1:1标题2行,描述1行,图片只在卡片上方显示

分辨率推荐:海报图用 3:4 比例,最小 600×800,最大 3000×4000;用户上传的图片不超过 3000×4000 就行。

图片在云端时,碰一下还没下载下来,卡片就会空白。可以先发不带图的数据,下载完再补上。

private buildShareData(sharableTarget: harmonyShare.SharableTarget) {
    const shareData: systemShare.SharedData = new systemShare.SharedData({
        utd: utd.UniformDataType.HYPERLINK,
        content: 'https://example.com/travel',
        title: '旅行攻略',
        description: '超全景点指南',
    });
    sharableTarget.share(shareData);

    // 模拟下载完成,实际监听下载回调
    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);
        sharableTarget.updateShareData({
            thumbnailUri: newThumbnailUri,
        });
    }, 3000); // 不要学我用固定延迟,监听下载事件
}

数据传输选 App Linking 还是 Deep Linking

分享链接时,选 App Linking 省心:已安装应用直接拉起,没装就弹应用市场。Deep Linking 只在已安装时有效,未安装会提示'暂无可用打开方式'。代码上只是 content 字段不一样。

App Linking 示例:

content: 'https://sharekitdemo.drcn.agconnect.link/ZB3p', // App Linking 链接

Deep Linking 示例:

content: 'myapp://product/detail?id=123', // Deep Linking scheme

安全和异常,别让用户蒙在鼓里

Share Kit 会显示对方身份信息(登录了账号就是昵称+头像,没登录是设备名),但注意这功能 HarmonyOS NEXT 5.0.0.123 SP16 才开始支持,老版本是空白的。

异常情况要主动告诉用户发生了什么:

  • 当前界面没得分享:调 clarifyNonShare,系统会提示。
  • 下载失败了:调 reject(DOWNLOAD_ERROR),系统提示'下载失败,稍后重试'。
// 无内容
sharableTarget.clarifyNonShare({ message: '当前界面不支持碰一碰,请在图片预览或文件详情页尝试' });

// 下载错误
sharableTarget.reject(harmonyShare.SharableErrorCode.DOWNLOAD_ERROR);

手机 ↔ PC/2in1 的碰一碰——角度是硬门槛

这部分有几个硬性约束:

  • 同一个华为账号
  • 手机必须是直板态
  • 角度要求:俯视夹角≤5°(基本平行),侧视夹角>35°,正视夹角≤25°
  • 官方轻薄保护壳,厚的会影响

从 Beta5 版本开始,不支持双向同时分享。规则简单:谁前台有可分享内容谁就发送,如果双方都有或都没有,按优先级来。老版本(<Beta5)还是双向的,适配时得分情况。

沙箱接收:直达应用的体验

手机碰 PC,文件能直接存进 PC 应用的沙箱目录,不用用户选路径。开发时用 dataReceive 事件,配置接收的文件类型和数量上限。接收完后在 onDataReceived 回调里处理文件。

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,
            capabilities: [
                {
                    utd: utd.UniformDataType.IMAGE,
                    maxSupportedCount: 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() {
        // UI
    }
}

如果 PC 应用正在编辑不想接收,调 reject 就行:

receivableTarget.reject(harmonyShare.ReceivableErrorCode.NO_RECEIVABLE_ERROR);

组队邀请——别让双方同时邀请

游戏组队邀请容易撞车,双方都发邀请会失败。解决办法:一方在注册时设 sendOnly: true,表示只发送不接收。这样碰一碰时只有发送端构造数据。

const capabilityRegistry: harmonyShare.SendCapabilityRegistry = {
    windowId: 3001,
    sendOnly: true,
};
harmonyShare.on('knockShare', capabilityRegistry, (sharableTarget) => {
    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);
});

接收端通过 onNewWant 获取链接并解析房间信息:

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';

export default class GameAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        if (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 并加入
    }
}

最后再啰嗦几点

开发时容易忘的东西,列在这里:

  • canIUse 检查,不支持就别显示入口。
  • 注册事件后一定要在合适的时机注销。
  • 预览图不要过大,云端图片必须处理延迟更新。
  • 异常提示做全,别让用户干等。
  • 手机和 PC 版本要求不同,双向分享逻辑按版本区分。
  • 引导动图和文字必不可少,否则用户不知道能碰。

希望这些记录能让你的碰一碰分享开发少踩坑,一碰即传体验顺滑。

目录

  1. 环境先跑通
  2. 手机之间的碰一碰
  3. 引导用户触发
  4. 预览卡片:别让裁剪毁了第一印象
  5. 数据传输选 App Linking 还是 Deep Linking
  6. 安全和异常,别让用户蒙在鼓里
  7. 手机 ↔ PC/2in1 的碰一碰——角度是硬门槛
  8. 沙箱接收:直达应用的体验
  9. 组队邀请——别让双方同时邀请
  10. 最后再啰嗦几点

更多推荐文章

查看全部
  • CCF-GESP 2025 年 6 月二级 C++ T2 幂和数
  • LoRA 训练助手:快速生成 Stable Diffusion 专业训练标签
  • GLM-4.6V-Flash-WEB 本地部署与云端 API 成本性能对比
  • 35 岁失业建议尝试的 9 个行业方向
  • Python 文件读写操作详解
  • IntelliJ IDEA 项目配置与 Web 部署完全指南
  • 基于 VoxCPM-1.5-TTS 的软件操作语音指引实践
  • JDK 21 下载、安装与环境变量配置
  • C++ 高并发内存池:ObjectPool 构造与实现
  • Flutter 底部导航与 TabBar 多页切换及鸿蒙适配
  • ERNIE-4.5 系列模型单卡部署与心理健康机器人实战
  • FF 宣布 FX Super One 二季度交付,目标成美国头部 AI 机器人公司
  • 2025 年 AIGC 六大核心趋势与技术落地分析
  • FPGA 任意角度图像旋转原理与实现
  • Python pytest 框架使用指南:自动化测试入门
  • 二叉树 DFS 递归解题套路
  • OpenClaw 本地部署与飞书机器人接入指南
  • 解决 VS Code 远程连接时 GitHub Copilot 无法使用的问题
  • JavaScript 进阶:Fetch 请求中断与 Headers 对象详解
  • Verilog 语法详解:从入门到精通

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online