在鸿蒙全场景生态中,手机与 PC/2in1 的碰一碰分享已从基础文件传输升级为 “沉浸式交互 + 精准跳转 + 安全可控” 的核心能力。本文基于华为开发者联盟官方技术规范,聚焦分享体验优化、卡片样式适配、安全策略落地及异常场景处理,提供一套兼顾美观性与实用性的跨端碰一碰分享开发方案,助力开发者打造符合鸿蒙生态标准的优质交互体验。

一、核心体验升级:从 “能分享” 到 “好分享”

1.1 交互引导设计:降低用户认知成本

碰一碰分享的核心优势在于 “极简操作”,但需通过清晰的引导提示让用户快速感知功能可用性。根据官方规范,需在支持分享的界面添加两类引导:

  • 文本提示:在界面顶部或底部添加 “可碰一碰分享至 HarmonyOS 5.0 及以上手机 / PC 6.0 及以上” 的文案,明确适配版本要求。
  • 动图引导:集成官方提供的碰一碰引导动图(下载地址:碰一碰引导资源),放置于界面显著位置(如右下角悬浮图标),动图需标注 “对方需开启华为分享” 的补充说明。

引导资源集成步骤:

  1. 下载knock_share_guide目录下所有文件,放置于应用entry/src/main/resources/rawfile目录。
  2. 通过Image组件加载动图,设置循环播放与自适应大小:
// 动图引导组件示例
@Component
struct KnockShareGuide {
  build() {
    Image($r('app.media.knock_share_guide'))
      .width(60)
      .height(60)
      .objectFit(ImageFit.Contain)
      .animation({ loop: AnimationStatus.Infinite }) // 循环播放
    Text('可碰一碰分享至鸿蒙设备')
      .fontSize(12)
      .marginTop(4)
  }
}

1.2 分享卡片适配:三类模板精准匹配场景

Share Kit 提供三种标准化卡片模板,需根据分享内容类型选择适配,确保接收端直观感知分享内容。卡片样式决定用户接收意愿,需严格遵循布局规范:

卡片类型 适用场景 配置要求 布局规范
纯图片布局 图片、视频、普通文件等无需文字说明的内容 仅传递thumbnailUri(预览图路径) 预览图宽高比最小 1:4,超出部分裁剪;无文字区域,聚焦视觉呈现
沉浸式大卡布局 链接、文章、视频内容等需传递核心信息的场景 同时配置title(标题)、description(描述)、thumbnailUri(预览图),且预览图宽高比<1:1 预览图铺满卡片顶部;标题最多 2 行(约 20 个中文),超出省略;描述 1 行,超出省略;底部默认显示应用图标
白卡上下布局 宽屏图片、长图搭配文字说明的场景 同时配置titledescriptionthumbnailUri,且预览图宽高比>1:1 预览图仅显示于卡片上方,不铺满;文字区域位于下方,格式要求同沉浸式大卡

卡片配置示例代码(沉浸式大卡布局,分享视频链接):

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

// 构建沉浸式大卡分享数据
function buildImmersiveShareData(videoUrl: string, coverPath: string) {
  return new systemShare.SharedData({
    utd: utd.UniformDataType.HYPERLINK, // 链接类型
    content: videoUrl, // 分享核心内容(视频链接)
    title: '海岸风光·天气晴朗', // 标题(≤20字)
    description: 'HarmonyShare·220.8万播放', // 描述(≤1行)
    thumbnailUri: fileUri.getUriFromPath(coverPath) // 预览图路径(宽高比<1:1)
  });
}

1.3 预览图优化:平衡加载速度与显示效果

预览图是分享卡片的视觉核心,需避免因尺寸不当导致的模糊或加载缓慢问题,推荐配置如下:

预览图来源 推荐比例 分辨率范围(px) 优化建议
应用创作海报 3:4 最小 600×800,最大 3000×4000 提前压缩至 200KB 以内,采用 WebP 格式
用户上传图片 无限制 最大 3000×4000 自动裁剪为卡片适配比例,保留核心内容

针对云端预览图下载延迟问题,可使用 Share Kit 的预览图更新能力,先建立连接再补充预览图:

// 预览图延迟更新示例
harmonyShare.on('knockShare', (sharableTarget: harmonyShare.SharableTarget) => {
  // 1. 先发送核心数据,使用系统默认预览图
  const shareData = new systemShare.SharedData({
    utd: utd.UniformDataType.HYPERLINK,
    content: 'https://sharekitdemo.drcn.agconnect.link/ZB3p',
    title: '碰一碰分享卡片标题',
    description: '碰一碰分享卡片描述'
  });
  sharableTarget.share(shareData);

  // 2. 异步下载云端预览图,完成后更新
  downloadCloudImage('https://example.com/cover.jpg').then((localPath) => {
    sharableTarget.updateShareData({
      thumbnailUri: fileUri.getUriFromPath(localPath)
    });
  });
});

// 模拟云端图片下载
async function downloadCloudImage(url: string): Promise<string> {
  // 省略下载逻辑,返回本地文件路径
  const uiContext = getUIContext();
  const context = uiContext.getHostContext() as Context;
  return `${context.filesDir}/downloaded_cover.jpg`;
}

二、安全与跳转:构建可信的跨端连接

2.1 安全策略落地:身份可视化与权限控制

为保障分享双方信息安全,鸿蒙 OS 在 5.0.0.123 SP16 及以上版本新增身份标识展示功能,开发者无需额外开发,只需确保应用适配该版本即可实现:

设备角色 对端已登录华为账号 对端未登录华为账号
发送端(手机 / PC) 接收端展示发送端账号昵称 + 头像 接收端展示发送端设备名称(如 “Mate 70”)
接收端(手机 / PC) 发送端展示接收端账号昵称 + 头像 发送端展示接收端设备名称(如 “MateBook X Pro”)

注意:若发送端为旧版本系统(低于 5.0.0.123 SP16),接收端不会展示任何身份信息,需在引导文案中提示用户升级系统以获得更安全的体验。

2.2 链接跳转方案:App Linking vs Deep Linking

分享链接类内容时,需选择合适的跳转方案,确保接收端能精准打开对应内容,两种核心方案对比及实现:

2.2.1 App Linking:全场景覆盖(推荐)

无论接收端是否安装目标应用,均可实现流畅跳转,未安装时可直达应用市场,提升转化效率:

  • 已安装应用:直接拉起应用并跳转到对应页面。
  • 未安装应用:跳转至应用市场下载页,下载完成后可通过 “延迟链接” 能力恢复分享内容。

实现代码示例:

// App Linking跳转配置
function buildAppLinkShareData() {
  // 结合App Linking Kit生成的链接(含应用市场跳转逻辑)
  const appLink = 'https://sharekitdemo.drcn.agconnect.link/ZB3p';
  return new systemShare.SharedData({
    utd: utd.UniformDataType.HYPERLINK, // 必须配置为链接类型
    content: appLink,
    title: '鸿蒙开发实战教程',
    description: '从入门到进阶的全场景开发指南',
    thumbnailUri: fileUri.getUriFromPath(`${getContext().filesDir}/guide_cover.jpg`)
  });
}
2.2.2 Deep Linking:本地应用精准跳转

仅适用于接收端已安装目标应用的场景,跳转速度更快,但未安装时会提示 “暂无可用打开方式”,适合闭环生态场景:

// Deep Linking跳转配置(需提前在应用中注册Schema)
function buildDeepLinkShareData() {
  const deepLink = 'harmonydev://guide/detail?id=123'; // 应用自定义Schema
  return new systemShare.SharedData({
    utd: utd.UniformDataType.HYPERLINK,
    content: deepLink,
    title: '鸿蒙开发实战教程',
    description: '从入门到进阶的全场景开发指南',
    thumbnailUri: fileUri.getUriFromPath(`${getContext().filesDir}/guide_cover.jpg`)
  });
}

三、异常场景处理:避免用户体验断层

碰一碰分享过程中可能出现 “无可用内容”“下载失败” 等异常,需通过官方提供的 API 及时终止分享并给出明确提示,避免用户长时间等待。

3.1 场景 1:当前界面无可分享内容

当用户在不支持分享的界面触发碰一碰时,调用clarifyNonShare()终止分享并引导用户前往正确界面:

// 无可分享内容处理
harmonyShare.on('knockShare', (sharableTarget: harmonyShare.SharableTarget) => {
  // 终止分享并显示引导文案
  sharableTarget.clarifyNonShare({
    message: '当前界面不支持碰一碰分享,请在图库、文件管理等界面尝试'
  });
});

效果:接收端会显示 “当前界面不支持碰一碰 请在支持碰一碰分享的界面再试” 的提示,同时提供 “更多可碰场景了解详情” 的跳转入口。

3.2 场景 2:分享内容下载失败(如云端图片 / 文件下载超时)

因网络或业务原因导致分享内容无法获取时,调用reject()终止分享并标注错误类型:

// 分享内容下载失败处理
harmonyShare.on('knockShare', async (sharableTarget: harmonyShare.SharableTarget) => {
  try {
    const coverPath = await downloadCloudImage('https://example.com/cover.jpg');
    // 下载成功,发起分享
    const shareData = buildImmersiveShareData('https://example.com/video', coverPath);
    sharableTarget.share(shareData);
  } catch (err) {
    // 下载失败,终止分享
    sharableTarget.reject(harmonyShare.SharableErrorCode.DOWNLOAD_ERROR);
  }
});

效果:接收端会显示 “分享失败:内容下载异常” 的提示,帮助用户快速定位问题。

3.3 场景 3:应用退至后台

当应用退至后台后,需解除碰一碰分享监听,避免后台状态下误触发分享:

// 应用生命周期管理:后台解除监听
@Component
export struct SharePage {
  aboutToAppear(): void {
    // 页面显示时注册监听
    harmonyShare.on('knockShare', this.shareCallback);
  }

  aboutToDisappear(): void {
    // 页面销毁时解除监听
    harmonyShare.off('knockShare', this.shareCallback);
  }

  onPageHide(): void {
    // 页面退至后台时解除监听
    harmonyShare.off('knockShare', this.shareCallback);
  }

  private shareCallback = (sharableTarget: harmonyShare.SharableTarget) => {
    // 分享逻辑
  };

  build() { /* 页面布局 */ }
}

四、实战落地:手机与 PC/2in1 双向分享流程

以 “手机向 PC 分享文章链接” 为例,整合上述优化点,实现完整的沉浸式分享流程:

4.1 手机端(发送端)核心代码

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

@Component
export struct ArticleSharePage {
  private articleUrl = 'https://sharekitdemo.drcn.agconnect.link/ZB3p';
  private articleTitle = '鸿蒙跨端碰一碰分享最佳实践';
  private articleDesc = '一文掌握卡片适配、安全策略与异常处理';
  private coverPath = '';

  async aboutToAppear() {
    // 1. 申请必要权限
    await this.requestPermissions();
    // 2. 预下载预览图(本地缓存)
    this.coverPath = await this.preloadCoverImage();
    // 3. 注册碰一碰分享监听
    harmonyShare.on('knockShare', this.handleKnockShare);
  }

  aboutToDisappear() {
    // 解除监听
    harmonyShare.off('knockShare', this.handleKnockShare);
  }

  // 权限申请(文件访问+NFC)
  private async requestPermissions() {
    const atManager = abilityAccessCtrl.createAtManager();
    const permissions = [
      'ohos.permission.READ_USER_STORAGE',
      'ohos.permission.NFC'
    ];
    const statusList = await atManager.checkAccessPermissions(
      abilityAccessCtrl.createAccessTokenID(), permissions
    );
    if (statusList.some(status => status !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)) {
      await atManager.requestPermissionsFromUser(getContext(), permissions);
    }
  }

  // 预下载预览图
  private async preloadCoverImage(): Promise<string> {
    try {
      const context = getContext() as Context;
      const localPath = `${context.filesDir}/article_cover.jpg`;
      // 模拟下载云端图片
      await downloadCloudImage('https://example.com/article_cover.jpg', localPath);
      return localPath;
    } catch (err) {
      console.error('预览图预下载失败:', err);
      return '';
    }
  }

  // 碰一碰分享回调处理
  private handleKnockShare = (sharableTarget: harmonyShare.SharableTarget) => {
    // 检查预览图是否可用
    if (!this.coverPath) {
      // 预览图下载失败,终止分享
      sharableTarget.reject(harmonyShare.SharableErrorCode.DOWNLOAD_ERROR);
      return;
    }

    // 构建沉浸式大卡分享数据(预览图宽高比<1:1)
    const shareData = new systemShare.SharedData({
      utd: utd.UniformDataType.HYPERLINK,
      content: this.articleUrl,
      title: this.articleTitle,
      description: this.articleDesc,
      thumbnailUri: fileUri.getUriFromPath(this.coverPath)
    });

    // 发起分享
    sharableTarget.share(shareData);
  };

  build() {
    Column {
      // 文章内容区域
      Text(this.articleTitle).fontSize(20).fontWeight(FontWeight.Bold)
      Text(this.articleDesc).fontSize(14).marginTop(8)
      // 碰一碰引导组件
      KnockShareGuide().marginTop(20).alignSelf(ItemAlign.End)
    }.padding(16)
  }
}

4.2 PC 端(接收端)核心适配

PC 端需适配鸿蒙 6.0 及以上版本,重点处理以下两点:

  1. 卡片显示适配:因 PC 屏幕尺寸更大,需确保分享卡片按比例放大,文字清晰可辨,避免拉伸变形。
  2. 链接跳转处理:接收链接后,优先唤起 PC 端对应应用,无应用时打开默认浏览器访问链接内容。

PC 端接收回调示例:

// PC端接收碰一碰分享
harmonyShare.on('knockReceive', (receiveData: harmonyShare.ReceiveData) => {
  const { content, title, utd } = receiveData;
  // 链接类型内容处理
  if (utd === utd.UniformDataType.HYPERLINK) {
    // 尝试唤起PC端应用,失败则打开浏览器
    try {
      // 调用PC端应用跳转API
      app.openUrl(content);
    } catch (err) {
      // 打开默认浏览器
      browser.openUrl(content);
    }
    // 显示接收成功通知
    notification.showToast({
      message: `已接收分享:${title}`,
      duration: 3000
    });
  }
});

五、开发注意事项与最佳实践

  1. 版本兼容性:手机端需适配 HarmonyOS 5.0 及以上,PC 端需适配 6.0 及以上,低版本设备需隐藏碰一碰引导或提示用户升级。
  2. 资源规范:引导动图、卡片预览图需使用官方推荐格式与尺寸,避免自定义样式导致的兼容性问题。
  3. 性能优化:避免在分享回调中执行耗时操作(如大文件下载),需提前预加载资源,确保碰一碰触发后能快速响应。
  4. 测试覆盖:需测试 “已登录 / 未登录华为账号”“应用已安装 / 未安装”“网络正常 / 异常” 等多场景,确保全流程体验一致。

六、总结

手机与 PC/2in1 的碰一碰分享开发,核心在于 “体验标准化 + 场景精准化 + 安全可控化”。通过遵循官方卡片模板规范、优化预览图与引导设计、完善异常处理机制,可打造符合鸿蒙生态用户预期的交互体验。随着鸿蒙 OS 的持续迭代,碰一碰分享将支持更多内容类型与协同场景,开发者需持续关注官方 API 更新,将跨端分享能力与应用核心场景深度融合,充分发挥鸿蒙全场景生态的协同优势。

Logo

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

更多推荐