鸿蒙学习实战之路-Share Kit系列(14/17)-手机间碰一碰分享实战

最近好多朋友问我:“西兰花啊,我想实现手机碰一碰分享功能,但不知道代码怎么写?” 害,这问题可问对人了!

今天这篇,我就手把手带你实现手机间碰一碰分享功能,从零到一,全程不超过 10 分钟(不含调试时间)~


碰一碰分享是啥?

碰一碰分享就是两台手机靠近后,自动弹出分享面板。比如:

  • 你和朋友在一起,想分享一张照片,只需要把两台手机靠近,就能快速分享
  • 你和家人在一起,想分享一个链接,只需要把两台手机靠近,就能快速分享

这就像前端的蓝牙分享,只不过 Share Kit 是系统级别的服务,体验更统一。


需要申请权限吗?

是的,碰一碰分享需要申请 ohos.permission.NFC_TAG 权限。

配置权限

module.json5 中声明权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.NFC_TAG"
      }
    ]
  }
}

🥦 西兰花警告
我有个朋友忘记申请权限,结果碰一碰分享一直不触发,debug 了两小时才发现是权限问题!血泪教训啊朋友们!


完整实现步骤

实现手机间碰一碰分享,就三步:

  1. 申请权限:在 module.json5 中声明权限
  2. 监听碰一碰事件:使用 NFC 模块监听碰一碰事件
  3. 触发分享:在碰一碰事件中触发分享

步骤 1:申请权限

module.json5 中声明 ohos.permission.NFC_TAG 权限。

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.NFC_TAG"
      }
    ]
  }
}

步骤 2:监听碰一碰事件

使用 NFC 模块监听碰一碰事件。

import { nfc } from '@kit.ConnectivityKit';

// 监听碰一碰事件
nfc.on('nfcTagDiscovered', (tagInfo: nfc.TagInfo) => {
  console.log(`检测到NFC标签:${tagInfo}`);
});

步骤 3:触发分享

在碰一碰事件中触发分享。

import { common } from '@kit.AbilityKit';
import { systemShare } from '@kit.ShareKit';

// 触发分享
function onNfcTagDiscovered(tagInfo: nfc.TagInfo) {
  // 构造分享数据
  let shareData: systemShare.SharedData = new systemShare.SharedData({
    utd: 'general.text',
    uri: 'file://.../xxx.txt',
    title: '碰一碰分享',
    description: '这是一段碰一碰分享文本'
  });

  // 构建分享控制器
  let controller: systemShare.ShareController = new systemShare.ShareController(shareData);

  // 显示分享面板
  let uiContext: UIContext = this.getUIContext();
  let context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;

  controller.show(context, {
    previewMode: systemShare.SharePreviewMode.DEFAULT,
    selectionMode: systemShare.SelectionMode.SINGLE
  });
}

完整代码示例

把上面的步骤整合起来,就是一个完整的手机间碰一碰分享的实现:

import { common } from '@kit.AbilityKit';
import { systemShare } from '@kit.ShareKit';
import { nfc } from '@kit.ConnectivityKit';

@Entry
@Component
struct NfcSharePage {
  // 分享文本
  shareText: string = '这是一段碰一碰分享文本';

  aboutToAppear() {
    // 监听碰一碰事件
    nfc.on('nfcTagDiscovered', (tagInfo: nfc.TagInfo) => {
      console.log(`检测到NFC标签:${tagInfo}`);
      // 触发分享
      this.onNfcTagDiscovered(tagInfo);
    });
  }

  aboutToDisappear() {
    // 取消监听碰一碰事件
    nfc.off('nfcTagDiscovered');
  }

  // 触发分享
  onNfcTagDiscovered(tagInfo: nfc.TagInfo) {
    // 构造分享数据
    let shareData: systemShare.SharedData = new systemShare.SharedData({
      utd: 'general.text',
      uri: 'file://.../xxx.txt',
      title: '碰一碰分享',
      description: this.shareText
    });

    // 构建分享控制器
    let controller: systemShare.ShareController = new systemShare.ShareController(shareData);

    // 显示分享面板
    let uiContext: UIContext = this.getUIContext();
    let context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;

    controller.show(context, {
      previewMode: systemShare.SharePreviewMode.DEFAULT,
      selectionMode: systemShare.SelectionMode.SINGLE
    });
  }

  build() {
    Column() {
      Text('碰一碰分享示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin(20)
        .fontColor(Color.Black);

      Text(this.shareText)
        .fontSize(16)
        .margin({ left: 20, right: 20, bottom: 20 })
        .fontColor(Color.Gray);

      Text('将两台手机靠近,即可触发碰一碰分享')
        .fontSize(16)
        .margin(20)
        .fontColor(Color.Gray);
    }
    .width('100%')
    .height('100%');
  }
}

在实际项目中怎么用?

上面的代码是基础实现,但在实际项目中,你可能会这样用:

示例:碰一碰分享图片

import { common } from '@kit.AbilityKit';
import { systemShare } from '@kit.ShareKit';
import { nfc } from '@kit.ConnectivityKit';

@Entry
@Component
struct NfcImageSharePage {
  // 分享图片
  shareImage: string = 'file://.../xxx.jpg';

  aboutToAppear() {
    // 监听碰一碰事件
    nfc.on('nfcTagDiscovered', (tagInfo: nfc.TagInfo) => {
      console.log(`检测到NFC标签:${tagInfo}`);
      // 触发分享
      this.onNfcTagDiscovered(tagInfo);
    });
  }

  aboutToDisappear() {
    // 取消监听碰一碰事件
    nfc.off('nfcTagDiscovered');
  }

  // 触发分享
  onNfcTagDiscovered(tagInfo: nfc.TagInfo) {
    // 构造分享数据
    let shareData: systemShare.SharedData = new systemShare.SharedData({
      utd: 'general.image',
      uri: this.shareImage,
      title: '碰一碰分享图片',
      preview: this.shareImage,
      description: '这是一张碰一碰分享的图片'
    });

    // 构建分享控制器
    let controller: systemShare.ShareController = new systemShare.ShareController(shareData);

    // 显示分享面板
    let uiContext: UIContext = this.getUIContext();
    let context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;

    controller.show(context, {
      previewMode: systemShare.SharePreviewMode.DEFAULT,
      selectionMode: systemShare.SelectionMode.SINGLE
    });
  }

  build() {
    Column() {
      Text('碰一碰分享图片示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin(20)
        .fontColor(Color.Black);

      Image(this.shareImage)
        .width(200)
        .height(200)
        .margin(20);

      Text('将两台手机靠近,即可触发碰一碰分享')
        .fontSize(16)
        .margin(20)
        .fontColor(Color.Gray);
    }
    .width('100%')
    .height('100%');
  }
}

示例:碰一碰分享链接

import { common } from '@kit.AbilityKit';
import { systemShare } from '@kit.ShareKit';
import { nfc } from '@kit.ConnectivityKit';
import { appLinking } from '@kit.AppLinkingKit';

@Entry
@Component
struct NfcLinkSharePage {
  // 分享链接
  shareLink: string = 'https://www.example.com';

  aboutToAppear() {
    // 监听碰一碰事件
    nfc.on('nfcTagDiscovered', (tagInfo: nfc.TagInfo) => {
      console.log(`检测到NFC标签:${tagInfo}`);
      // 触发分享
      this.onNfcTagDiscovered(tagInfo);
    });
  }

  aboutToDisappear() {
    // 取消监听碰一碰事件
    nfc.off('nfcTagDiscovered');
  }

  // 触发分享
  onNfcTagDiscovered(tagInfo: nfc.TagInfo) {
    // 构造App Linking
    let appLinking: appLinking.AppLinking = appLinking.createAppLinking({
      packageName: 'com.example.app',
      path: '/pages/detail',
      parameters: {
        id: '123'
      }
    });

    // 构造分享数据
    let shareData: systemShare.SharedData = new systemShare.SharedData({
      utd: 'general.link',
      uri: this.shareLink,
      title: '碰一碰分享链接',
      preview: appLinking.toUri(),
      description: '这是一个碰一碰分享的链接'
    });

    // 构建分享控制器
    let controller: systemShare.ShareController = new systemShare.ShareController(shareData);

    // 显示分享面板
    let uiContext: UIContext = this.getUIContext();
    let context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;

    controller.show(context, {
      previewMode: systemShare.SharePreviewMode.DEFAULT,
      selectionMode: systemShare.SelectionMode.SINGLE
    });
  }

  build() {
    Column() {
      Text('碰一碰分享链接示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin(20)
        .fontColor(Color.Black);

      Text(this.shareLink)
        .fontSize(16)
        .margin({ left: 20, right: 20, bottom: 20 })
        .fontColor(Color.Gray);

      Text('将两台手机靠近,即可触发碰一碰分享')
        .fontSize(16)
        .margin(20)
        .fontColor(Color.Gray);
    }
    .width('100%')
    .height('100%');
  }
}

常见问题

Q1:碰一碰分享不触发怎么办?

检查以下几点:

  1. 是否申请了权限

    • 确认是否在 module.json5 中声明了 ohos.permission.NFC_TAG 权限
    • 确认用户是否授权了该权限
  2. 是否正确监听了碰一碰事件

    • 确认是否在 aboutToAppear 中监听了碰一碰事件
    • 确认是否在 aboutToDisappear 中取消了监听
  3. NFC 功能是否开启

    • 确认手机的 NFC 功能是否开启
    • 确认两台手机是否支持 NFC 功能

Q2:如何取消监听碰一碰事件?

aboutToDisappear 中调用 nfc.off 方法取消监听:

aboutToDisappear() {
  // 取消监听碰一碰事件
  nfc.off('nfcTagDiscovered');
}

Q3:碰一碰分享的距离是多少?

碰一碰分享的距离一般在 10 厘米以内,建议两台手机靠近到 5 厘米以内,以确保碰一碰分享能够触发。


下一步学什么?

看完这篇,你应该已经能实现手机间碰一碰分享了。接下来可以深入学习:

  1. 手机与PC/2in1设备间分享:跨设备分享的实现
  2. 隔空传送与可信任设备:隔空传送的实现
  3. 常见问题:分享失败、数据类型不支持等问题的解决方案

推荐资料

📚 官方文档


我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦

Logo

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

更多推荐