简介
对微信小程序中,进场通信(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();
});