引言

HarmonyOS 6.0增强了碰一碰分享能力,支持组队场景的单向发送能力和云预览图延迟个更新,正好开发的“智能带办”应用有线下快捷分享的强诉求,碰一碰分享很满足这个诉求,立马动手进行接入。
在这里插入图片描述

项目介绍

“智能带办”应用是干什么的呢?相信每个人都有这样的瞬间:

  • 飞到目的地才发现没带充电头?
  • 去海边露营结果忘了带驱蚊水?
  • 每次出差前都要花半小时在脑子里“过电影”列清单,却还是百密一疏?

智能带办 就是为了解决这些“出门焦虑”而生的。它不是一个普通的待办清单,而是一个深耕于 “出门要带什么” 场景的智能助手。项目的核心亮点是把脑力活交给 AI:

  • 输入“要做的事”,秒出“要带的物”: 只需对这输入框 说一句:“我要去哈尔滨看冰雕,待三天”,后台接入的 DeepSeek AI 就会基于气候、时长和活动,自动为你生成一份精准的“带办清单”——从保暖内衣到暖宝宝,从身份证到充电宝,一应俱全。
  • 智能场景化推荐: 项目内置了多种典型场景(如:商务出差、户外露营、带娃旅行、极限运动等)。系统会根据你的习惯和高频场景,主动推荐你可能需要的物品,让你清单整理从“白手起家”变成“一键确认”。
    AutoTodo,让你每一次出发,都底气十足。

在智能助手页面输入要做的事情,自动生成需要带的物品清单:
在这里插入图片描述

点击保存后进入具体事情详情页,可以操作所带物品清单:
在这里插入图片描述

也可以从推荐场景中具体的事情进入详情页:
在这里插入图片描述

整理带办物品清单时可能是线下和周围的人,比如家人,同事一起处理,生成一份清单多人互相准备、勾选会极大的提高效率。在其他端最常用的分享方式是通过微信分享链接,对方收到后打开,在微信收到的连接一般都不允许直接打开应用,还需要先跳转到浏览器再操作特别繁琐,有了碰一碰分享功能可以很便捷的共享清单给周围人。

碰一碰分享原理介绍

碰一碰是华为Share Kit推出的一种分享方式,支持用户通过碰一碰发起跨端分享,可实现传输图片、共享Wi-Fi等。碰一碰分享的主要流程如下:

  1. 宿主应用注册碰一碰分享事件,并与亮屏且解锁的对端设备碰一碰。
  2. 宿主应用发现设备,调用碰一碰分享事件回调,在回调事件中构造分享数据并发送。
  3. 目标设备接收并处理分享数据。
  4. 宿主应用解除注册碰一碰分享事件。

整体处理流程图如下:
在这里插入图片描述

总结下来就是再提供分享能力的页面注册碰一碰监听事件,再监听到有两个设备碰一碰行为回调后根据业务逻辑构造分享数据,触发分享后被分享方处理分享内容或数据。
注意:手机应用发起碰一碰分享时,双端设备必须满足三个条件:双方均已开启华为分享服务、亮屏、解锁

碰一碰分享实现
1、准备碰一碰分享物料

在进入支持碰一碰分享的页面时,给出适当的引导和提示,可有效提升用户分享意愿,可以通过文本或者动图提示用户进行碰一碰分享,HarmonyOS官方提供了统一的动图资源文件以方便应用接入。下载https://gitcode.com/HarmonyOS_Samples/share-kit_-sample-code_-clientdemo_-arkts/tree/master/entry/src/main/resources/rawfile后,将完整knock_share_guide目录所有文件,并放置于应用entry/src/main/resources/rawfile目录下。“智能带办中”引导效果如图:
在这里插入图片描述

2、构建分享内容

接入碰一碰分享时,需根据不同的分享数据类型,适配相应的卡片模板,Share Kit支持三种卡片模板供手机发起碰一碰分享时选择:

  • 纯图片布局:纯图片布局只包括预览图,当分享数据为文件、图片等无需添加标题及描述的场景,推荐使用此卡片模板。
    • 使用方法:构造分享数据时,仅传递预览图(thumbnailUri)字段,即可生成此卡片模板。
    • 布局要求:预览图支持最小宽高比1:4,超出部分将被裁剪。
  • 沉浸式大卡布局:沉浸式大卡布局包括预览图、标题、描述、应用图标。当分享数据为链接类型时,需要向用户传递链接的内容,推荐使用此卡片模板。
    • 使用方法,需同时满足以下2个条件
      • 构造分享数据时,需同时传入标题(title)、描述(description)字段和预览图(thumbnailUri)字段。
      • 预览图宽高比小于1:1
    • 布局要求
      1. 预览图:支持最小宽高比1:4,超出部分将被裁剪。
      2. 标题:最大可显示2行,当文本超过2行时,未能正常在屏幕显示的文本用省略号代替。如果标题末尾有重要信息显示,需应用自行控制字数约20个中文左右。
      3. 描述:仅可显示1行,文本超过1行时,未能正常在屏幕上显示的文本用省略号代替。
      4. 应用图标:无需配置,系统将默认获取应用图标用于显示在卡片底部。
  • 白卡上下布局:白卡上下布局包括预览图、标题、描述、应用图标。当分享数据为链接类型时,需要向用户传递链接的内容,推荐使用此卡片模板。
    • 使用方法,需同时满足以下2个条件:
      1. 构造分享数据时,需同时传入标题(title)、描述(description)字段和预览图(thumbnailUri)字段。
      2. 预览图宽高比大于1:1
    • 布局要求
      1. 预览图:仅显示在卡片上方,不会铺满整个卡片。
      2. 标题:最大可显示2行,当文本超过2行时,未能正常在屏幕显示的文本用省略号代替。如果标题末尾有重要信息显示,需应用自行控制字数约20个中文左右。
      3. 描述:仅可显示1行,文本超过1行时,未能正常在屏幕上显示的文本用省略号代替。
      4. 应用图标:无需配置,系统将默认获取应用图标用于显示在卡片底部。

以链接分享为例,在页面出现aboutToAppear生命周期方法中,注册碰一碰事件回调:

aboutToAppear(): void {  
  if (this.isNoListening()) {  
    this.tipsListening();  
  }  
  const uiContext: UIContext = this.getUIContext();  
  const context: Context = uiContext.getHostContext() as Context; 
  //注册页面切换到前台事件监听 
  context.eventHub.on('onFocus', () => {  
    if (this.isNoListening()) {  
      this.tipsListening();  
    }  
  });  
  //注册也卖弄切换到后台事件监听
  context.eventHub.on('onBackGround', () => {  
    this.onBackGround();  
  });  
}

在页面关闭生命周期方法aboutToDisappear注销事件监听:

aboutToDisappear(): void {  
  Logger.i(TAG, 'aboutToDisappear invoked.');  
  this.disablingAllListening();  
  const uiContext: UIContext = this.getUIContext();  
  const context: Context = uiContext.getHostContext() as Context;  
  context.eventHub.off('onFocus');  
  context.eventHub.off('onBackGround');  
}

接下来在tipsListening方法中注册监听,构造分享数据:

private sendOnlyCallback = (sharableTarget: harmonyShare.SharableTarget) => {  
  const uiContext: UIContext = this.getUIContext();  
  const contextFaker: Context = uiContext.getHostContext() as Context;  
  let filePath = contextFaker.filesDir + '/knock_share_bg.jpg'; //封面图,采用固定图片
  let shareData: systemShare.SharedData = new systemShare.SharedData({  
    utd: utd.UniformDataType.HYPERLINK,  
    content: 'https://todo.xxxxxx.com/tododetail?topic=3xdsdv',  //分享链接地址
    title: this.title, //带办事情名称 
    description: this.mTodoGroupBean.description,  //带办事情描述
    thumbnailUri: fileUri.getUriFromPath(filePath), //分享封面图 
  });  
  sharableTarget.share(shareData)  
}  
  
private tipsListening() {  
  if (!this.tipsStatus) {  
    harmonyShare.on('knockShare', this.sendOnlyCallback);  
    this.tipsStatus = true;  
  } else {  
    try {  
      const uiContext: UIContext = this.getUIContext();  
      uiContext.getPromptAction().showToast({ message: $r('app.string.knock_close_other') });  
    } catch (error) {  
      Logger.e(TAG, `showToast error. Code: ${error?.code}, message: ${error?.message}`);  
    }  
  }}

分享的参数topic是服务端生成的用于加入某个带办组的标识,进入页面时请求服务端生成。

3、接收分享内容

要让应用允许被拉起,需要在工程的module.json5中EntryAbility的exported配置为true,并且skills要包含entity.system.browsable和ohos.want.action.home:

"abilities": [  
  {  
    "name": "EntryAbility",  
    "srcEntry": "./ets/entryability/EntryAbility.ets",  
    "description": "$string:EntryAbility_desc",  
    "icon": "$media:layered_image",  
    "label": "$string:EntryAbility_label",  
    "startWindowIcon": "$media:startIcon",  
    "startWindowBackground": "$color:start_window_background",  
    "exported": true,  
    "skills": [  
      {  
        "entities": [  
          "entity.system.home"  
        ],  
        "actions": [  
          "ohos.want.action.home"  
        ]  
      },  
      {  
        "entities": [  
          // entities必须包含"entity.system.browsable"  
          "entity.system.browsable"  
        ],  
        "actions": [  
          // actions必须包含"ohos.want.action.viewData"  
          "ohos.want.action.viewData"  
        ],  
        "uris": [  
          {  
            // scheme须配置为https  
            "scheme": "https",  
            // host须配置为关联的域名  
            "host": "todo.xxxxxx.com",  
            // path可选,表示域名服务器上的目录或文件路径,例如www.example.com/path1中的path1  
            // 如果应用只能处理部分特定的path,则此处应该配置应用所支持的path,避免出现应用不能处理的path链接也被引流到应用中的问题  
            "path": "tododetail"  
          }  
        ],  
        // domainVerify须设置为true  
        "domainVerify": true,  
      }  
    ]  
  }  
],

4、跳转落地页

在EntryAbility的onCreate声明周期方法中解析want,判断是上面分享的url,则执行对应逻辑:

async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {  
  // 从want中获取传入的链接信息。  
  // 如传入的url为:https://todo.xxxxxx.com/tododetail?topic=3dfd3  
  let uri = want?.uri;  
  if (uri) {  
    // 从链接中解析query参数,拿到参数后,根据自己的业务需求进行后续的处理。 
    try {  
      let urlObject = url.URL.parseURL(want?.uri);  
      let action = urlObject.params.get('topic');  
      // 例如,当topic为不为空时时,跳转到带办事情详情页。  
      
    } catch (error) {  
      hilog.error(0x0000, 'testTag', `Failed to parse url.`);  
    }  
  }}

携带topic对应value打开对应详情页请求服务端加入分享,即可开始共同编辑带办组了。

踩坑记:链接分享无法打开应用

按照上面步骤开发完成后发现碰一碰分享后,被分享方无法打开具体应用,而是跳转到浏览器。
因为分享链接时utd类型需配置为"general.hyperlink",采用的是App Linking分享,使用该方式时,当应用已安装时,App Linking可直接拉起应用;当应用未安装时,App Linking的默认行为是通过系统浏览器打开链接对应的网页。通过App Linking Kit的直达应用市场能力,可以实现在应用未安装时直接跳转应用市场。

要使用App Linking需要在App AppGallery Connect开通App Link服务,并配置聚合链接地址:
在这里插入图片描述

配置完成后还需要给APP使用正式签名才可以正常使用分享跳转。而且这里注意申请聚合链接时需要一个https的服务,该服务必须可访问,并且把如下的applinking.json文件配置到服务域名的.well-know下(比如填写域名为todo.xxxxxx.com,则文件的访问地址为https://todo.xxxxxx.com/well-know/applinking.json:

{
 "applinking": {
   "apps": [
     {
       "appIdentifier": "1234567"//创建应用时生成的APP ID
     }
   ]
 }
}

应用链接发布完成后,如果距离上次更新超过24小时,系统会去域名服务器上重新获取配置文件进行交集校验。

如果遇到系统尚未完成域名校验问题,可以先在设备上安装应用,等待至少20秒,以确保系统完成域名校验的流程;系统进行域名校验时,如存在断网、弱网等情况,可能导致域名校验失败,域名校验失败后,系统将在24小时内重新进行域名校验。

如果需要查看应用域名验证结果,可以在DevEco Studio中打开终端,并使用以下命令查询验证结果:

hdc shell hidumper -s AppDomainVerifyManager

输入效果如下说明验证成功:
在这里插入图片描述

总结

通过接入 HarmonyOS 6 的“碰一碰”分享,我们在“智能带办”中补齐了线下多人协同的关键一环:同处一室的家人、同事只需轻触手机,即可把“要带的物”一键共享到同一待办组,现场勾选、补充、确认,显著减少口头沟通与重复整理的成本。整套方案以系统级 Share Kit​ 为底座,遵循“注册监听 → 构造分享数据 → 触发分享 → 被拉起落地”的标准链路,稳定且低门槛;结合 App Linking​ 直达应用指定页,实现“已装直达、未装引导下载”的闭环体验,兼顾体验与转化。

在工程落地上,我们按“引导提示 → 卡片模板选择 → 生命周期管理 → 接收与路由”的顺序实施:在支持分享的页面展示官方动图提示,按内容类型选用纯图片、沉浸式大卡或白卡上下布局,页面前后台正确注册/注销监听避免误触与泄漏;被分享端在 module.json5​ 正确声明 exported、skills、uris、domainVerify​ 等能力,并在 EntryAbility​ 解析 want.uri​ 后携带参数(如 topic)跳转至对应详情页,完成组队加入与协同编辑。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐