微信小程序NFC功能模块封装

简介

对微信小程序中,进场通信(NFC)能力读写功能模块进行类封装。

适用于:NDEF数据传输格式的芯片

优势

1、类的封装方式能够很好地避免全局变量的污染

2、能够让开发者方便调用其读写等方法,提高开发效率

设计实现

useNfc.ts -- ts版本

/*
 * @Autor: Niki.Y
 * @Description: nfc类封装
 * @Date: 2023-04-20 17:47:54
 * @LastEditTime: 2023-04-23 15:49:01
 */
import { byteToString, string2ArrayBuffer, ab2hex } from "./nfcDataFormate";

class useNFC {
  // NFC实例
  public NFCAdapter;
  //Ndef实例
  public NDEF;
  //当前nfc的id
  public NFCID;
  //当前nfc携带的信息
  public NFCINFO: {};
  //构造函数
  constructor() {}
  public handler?: (params: any) => void;

  // 创建nfc监听
  createNfcAdaptor(read?: string) {
    return new Promise((resolve, reject) => {
      this.NFCAdapter = wx.getNFCAdapter();
      this.NFCAdapter.startDiscovery({
        success: (res: any) => {
          // title.value = "请将设备放入识别区NFC";
          this.NFCAdapter.onDiscovered(async (callback: any) => {
            console.log("onDiscovered callback=>", callback);
            let aid = parseInt(ab2hex(callback.id), 16);
            if (aid === this.NFCID) {
              // 处理返回多余的空对象payload
              resolve(this.NFCINFO);
              return;
            }
            this.NFCID = aid;
            let obj = {
              payload: "",
              id: "",
              type: "",
            };
            console.log(aid);
            if (callback.messages) {
              let cordsArray = callback.messages[0].records;
              cordsArray.find((item: any) => {
                obj.payload = byteToString(new Uint8Array(item.payload));
                obj.id = byteToString(new Uint8Array(item.id));
                obj.type = byteToString(new Uint8Array(item.type));
              });
              console.log("读取的records:", obj);
              // readData.value = obj.payload;
              this.NFCINFO = obj;
              resolve(obj);
            }else{
              obj.id = this.NFCID;
              this.NFCINFO = obj;
              resolve(obj);
            }
              
            if (callback.techs.length == 0) reject("无效设备");
          });
          console.log(res);
        },
        fail: (error: any) => {
          if (
            error.errMsg ==
            "startDiscovery:fail current platform is not supported"
          ) {
            if (!read) {
              uni.showToast({
                title: "当前系统不支持NFC读写功能",
                icon: "none",
                duration: 24 * 60 * 60 * 1000,
              });
            }
          }
          reject("连接NFC失败,请检查NFC功能是否打开");
        },
      });
    });
  }
  // 连接ndef写入数据
  connectNdefWriteData(records: any) {
    return new Promise((resolve, reject) => {
      this.NDEF = this.NFCAdapter.getNdef();
      this.NDEF.connect({
        success: (res: any) => {
          console.log(res);
          //   写入数据
          this.NDEF.writeNdefMessage({
            records: records,
            success: (res: any) => {
              resolve("数据写入成功");
              console.log(res);
            },
            fail: (error: any) => {
              reject("数据写入失败");
              console.error(error);
            },
          });
        },
        fail: (error: any) => {
          reject("连接设备失败");
          console.error(error);
        },
      });
    });
  }
  //   断开ndef连接
  closeNDEF() {
    this.NDEF.close({
      success: () => {
        console.log("断开ndef成功");
      },
      fail: () => {
        console.log("断开ndef失败");
      },
    });
  }
  //   取消监听nfc
  closeNFC() {
    this.NFCAdapter.offDiscovered();
    this.NFCAdapter.stopDiscovery({
      success: () => {
        console.log("断开连接成功");
      },
      fail: () => {
        console.log("断开连接失败");
      },
    });
    this.NFCAdapter = null;
    this.NDEF = null;
    this.NFCID = null;
    this.NFCINFO = {};
  }
}

export default new useNFC();

使用方法

1、需求:只需读nfc芯片内容:

直接调用useNfc的createNfcAdaptor方法,方法中已经包含初始化adapter实例,开始监听,监听回调等步骤:

import useNfc from "@/utils/useNfc";

  function connectNfc() {
    useNfc
      .createNfcAdaptor()
      .then(async (data: any) => {
        title.value = "标签识别成功,正在读取数据...";
        readData.value = data.id;
        console.log("读取到的数据:", readData.value);
        // 读取到nfc中的url后,需要拿到id,查询接口
        if (readData.value) {
          getWifiInfo(readData.value).catch(() => {
            setTimeout(() => {
              uni.redirectTo({
                url: "/pages/nfcPage/failed",
              });
            }, 800);
          });
        } else {
          title.value = "无效标签,请返回重试..";
        }
      })
      .catch((err) => {
        title.value = err;
        if (err == "无效设备") {
          uni.redirectTo({
            url: "/pages/nfcPage/failed",
          });
        }
      });
  }  

2、需求:在nfc芯片中写入数据:先创建nfc监听;再连接设备写入数据(依次调用createNfcAdaptor(),connectNdefWriteData(records))

 import {
    string2ArrayBuffer,
    payloadFormate,
  } from "../../utils/nfcDataFormate";
   
import useNfc from "@/utils/useNfc";

   function connectNfc() {
    // 建立
    useNfc.createNfcAdaptor().then(async (data: any) => {
      title.value = "标签识别成功,请贴紧标签,不要移动..";
      // 判断是否为空标签;
      if (data.id) {
        uni.showToast({
          title: "标签不可重复写入数据",
          icon: "none",
          duration: 4000,
        });
        title.value = "写入失败,请重换标签";
        return;
      }
      // 调接口获取urlScheme
      const NFCID = useNfc.NFCID;
      if (!openlink) {
        openlink = await getUrlSchame(NFCID);
      }
      if (typeof openlink !== "string") {
        title.value = "操作错误";
        return;
      }
      // 连接设备写入数据
      const records = [
        {
          id: string2ArrayBuffer(""),
          payload: payloadFormate(openlink),
          type: string2ArrayBuffer("U"),
          tnf: 0x01,
        },
        {
          id: string2ArrayBuffer(ID),
          payload: string2ArrayBuffer("com.tencent.mm"),
          type: string2ArrayBuffer("android.com:pkg"),
          tnf: 0x04,
        },
      ];
      useNfc
        .connectNdefWriteData(records)
        .then((wres) => {
          title.value = wres;
          openMsgDialog("success");
        })
        .catch((error) => {
          title.value = error;
          openMsgDialog("fail");
        });
    });
  }  

引入数据格式转换方法

在nfc中写入读取的数据,均是buffer字节格式,所以无论读取展示,还是写入数据都需要进行数据格式转换:这里引入了nfcDataFormate.ts文件;文件源码:

/**
 * 字节对象转字符串
 * @param {Object} arr
 */
export function byteToString(arr: any) {
  if (typeof arr === "string") {
    return arr;
  }
  var str = "",
    _arr = arr;

  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
      v = one.match(/^1+?(?=0)/);

    if (v && one.length == 8) {
      var bytesLength = v[0].length;

      var store = _arr[i].toString(2).slice(7 - bytesLength);

      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2);
      }

      str += String.fromCharCode(parseInt(store, 2));

      i += bytesLength - 1;
    } else {
      str += String.fromCharCode(_arr[i]);
    }
  }
  return str;
}

/**
 * 字符串转字节
 * @param {Object} str
 */
export function string2ArrayBuffer(str: any) {
  var array = new Uint8Array(str.length);
  for (var i = 0; i < str.length; i++) {
    array[i] = str.charCodeAt(i);
  }
  return array.buffer;
}
/**
 * 格式化得到aid值
 * @param {Object} buffer
 */
export function ab2hex(buffer: any) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),

    function (bit) {
      return ("00" + bit.toString(16)).slice(-2);
    }
  );
  return hexArr.join("");
}
/*
 * 强制加[00],解决微信打开小程序的问题
 */

export function payloadFormate(openlink) {
  const arrayBuffer = string2ArrayBuffer(openlink);
  const zeroArrayBuffer = new Uint8Array([0]).buffer;
  const resultArrayBuffer = new Uint8Array(
    zeroArrayBuffer.byteLength + arrayBuffer.byteLength
  );
  resultArrayBuffer.set(new Uint8Array(zeroArrayBuffer), 0);
  resultArrayBuffer.set(new Uint8Array(arrayBuffer), 1);
  const payload = resultArrayBuffer.buffer;
  return payload;
}

备注

在离开nfc功能页面时记得关闭nfc,取消监听nfc

  onUnmounted(() => {
    useNfc.closeNFC();
  });

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值