vite-uni-dev-tool
Version:
vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试
551 lines (496 loc) • 12.6 kB
text/typescript
import { ref } from 'vue';
import { onLoad, onUnload } from '@dcloudio/uni-app';
import {
getReadWriteStandard,
getSakHex,
getSakType,
parseAtqa,
transformArrayBuffer,
} from './utils';
export default function useNFCMpWeiXin(
listener: (data: NFC.Result) => void,
options: { timeout?: number; checkConnectedDelay?: number } = {
timeout: 0,
checkConnectedDelay: 500,
},
) {
/** 是否支持 nfc */
const isSupportNFC = ref<boolean | undefined>(false);
/** 是否监听中 */
const isListening = ref<boolean>(false);
/**
* 是否已连接
* 需要手动维护,调用connect()后连接 调用close()后断开 ,实际nfc 断开之后是无法监听到的, isConnected 已经被废弃掉了
*/
const isConnected = ref<boolean>(false);
/** nfc 数据 */
const data = ref<NFC.Result>({
id: new ArrayBuffer(0),
techs: [],
byteArray: [],
hexArray: [],
hexNumberArray: [],
hexString: '',
});
/** nfc 适配器 */
let nfcAdapter: NFC.Adapter;
/** nfc 实例 */
let nfcInstance: NFC.Instance | undefined;
/** ndef 写入方式比较特殊,需要特殊处理 */
let isNdef = ref(false);
/**
* 初始化 nfc adapter
*
* @return {*}
*/
async function initNfcAdapter() {
await checkHCEState();
if (!isSupportNFC.value) return;
nfcAdapter = wx.getNFCAdapter();
nfcAdapter.onDiscovered(innerListener);
}
function getAtqa(nfcInstance: NFC.Instance): Promise<NFC.Atqa> {
return new Promise((resolve, reject) => {
if (!nfcInstance.getAtqa) {
reject({ errMsg: '不支持获取 atqa' });
}
nfcInstance?.getAtqa?.({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
function getMaxTransceiveLength(
nfcInstance: NFC.Instance,
): Promise<NFC.MaxTransceiveLength> {
return new Promise((resolve, reject) => {
if (!nfcInstance.getMaxTransceiveLength) {
reject({ errMsg: '不支持获取 maxTransceiveLength' });
}
nfcInstance?.getMaxTransceiveLength?.({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
function getSak(nfcInstance: NFC.Instance): Promise<NFC.Sak> {
return new Promise((resolve, reject) => {
if (!nfcInstance.getMaxTransceiveLength) {
reject({ errMsg: '不支持获取 sak' });
}
nfcInstance?.getSak?.({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
/**
* 检查HCE状态
*
* @return {*}
*/
function checkHCEState() {
// uni.showToast({ title: '初始化 NFC' });
return new Promise((resolve, reject) => {
wx.getHCEState({
success: (res: any) => {
isSupportNFC.value = true;
resolve(res);
},
fail: (err: any) => {
isSupportNFC.value = false;
reject(err);
},
});
});
}
/**
* 启用HCE
*
* @return {*}
*/
function startHCE() {
if (!isSupportNFC.value) {
uni.showToast({
title: '设备不支持 NFC',
icon: 'none',
});
return;
}
// 前置校验
if (!nfcAdapter) {
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
return false;
}
if (isListening.value) {
uni.showToast({ title: 'NFC 监听已开启,无需重复操作', icon: 'none' });
return true;
}
nfcAdapter.startDiscovery();
isListening.value = true;
uni.showToast({
title: '开始监听NFC',
icon: 'none',
});
}
/**
* 停用HCE
*
* @return {*}
*/
function stopHCE() {
// 前置校验
if (!isSupportNFC.value) {
uni.showToast({
title: '设备不支持 NFC',
icon: 'none',
});
return;
}
// 前置校验
if (!nfcAdapter) {
uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
return false;
}
if (!isListening.value) {
uni.showToast({ title: 'NFC 监听已关闭,无需重复操作', icon: 'none' });
return true;
}
nfcAdapter.stopDiscovery();
isListening.value = false;
uni.showToast({
title: '停止监听NFC',
icon: 'none',
});
}
/**
* 读取监听
*
* @param {*} res
*/
async function innerListener(res: NFC.Data) {
const transform = transformArrayBuffer(res?.id);
/**
* 获取标签类型
* 默认取第一个
*/
const type = res.techs[0];
switch (type) {
case 'NFC-A':
nfcInstance = nfcAdapter.getNfcA();
break;
case 'NFC-B':
nfcInstance = nfcAdapter.getNfcB();
break;
case 'NFC-F':
nfcInstance = nfcAdapter.getNfcF();
break;
case 'NFC-V':
nfcInstance = nfcAdapter.getNfcV();
break;
case 'MIFARE Classic':
nfcInstance = nfcAdapter.getMifareClassic();
break;
case 'MIFARE Ultralight':
nfcInstance = nfcAdapter.getMifareUltralight();
break;
case 'Ndef':
isNdef.value = true;
nfcInstance = nfcAdapter.getNdef();
break;
case 'ISO-DEP':
nfcInstance = nfcAdapter.getIsoDep();
break;
default:
nfcInstance = undefined;
break;
}
if (res.techs.includes('NFC-A')) {
const nfcA = nfcAdapter.getNfcA();
try {
const atqa = await getAtqa(nfcA);
const atqaInfo = parseAtqa(atqa.atqa);
data.value.atqa = atqa.atqa;
data.value.uidType = atqaInfo?.uidType;
data.value.storageSize = atqaInfo?.storageSize;
data.value.manufacturer = atqaInfo?.manufacturer;
data.value.cardFeatures = atqaInfo?.cardFeatures;
data.value.reserved = atqaInfo?.reserved;
} catch (error) {}
try {
const sak = await getSak(nfcA);
const sakType = getSakType(sak.sak);
const sakHex = getSakHex(sak.sak);
data.value.sak = sak.sak;
data.value.sakType = sakType;
data.value.sakHex = sakHex;
} catch (error) {}
}
if (nfcInstance) {
const maxTransceive = await getMaxTransceiveLength(nfcInstance);
data.value.maxTransceiveLength = maxTransceive.length;
data.value.readWriteStandard = getReadWriteStandard(res.techs);
if (options?.timeout && options.timeout > 0) {
nfcInstance?.setTimeout?.({
timeout: options.timeout,
});
}
data.value = {
...data.value,
...res,
...transform,
};
isConnected.value = true;
listener?.(data.value);
// 可将改行去除
uni?.__dev_tool_nfc_collection__?.(data.value);
}
}
/**
* 移除监听读取消息
*
* @return {*}
*/
function offHCEMessage() {
if (!isSupportNFC.value) {
uni.showToast({ title: '设备不支持 NFC,无需移除监听', icon: 'none' });
return { errMsg: 'success' };
}
isConnected.value = false;
nfcAdapter.offDiscovered(innerListener);
uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
return { errMsg: 'success' };
}
/**
* 连接 nfc
*
* @return {*}
*/
function connect() {
return new Promise((resolve, reject) => {
if (!isSupportNFC.value) {
uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
reject({
errMsg: '设备不支持 NFC',
});
return;
}
if (!isListening.value) {
uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
reject({
errMsg: '请先开启前台调度监听',
});
return;
}
if (!nfcInstance) {
uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
reject({
errMsg: '请先靠近 NFC 标签',
});
return;
}
nfcInstance?.connect?.({
success: (res) => {
console.log('res: ', res);
resolve(res);
isConnected.value = true;
uni.showToast({
title: 'NFC 连接成功',
icon: 'none',
});
},
fail: (err) => {
if (err.errMsg === 'connect:fail:Tech already connected') {
resolve(err);
isConnected.value = true;
} else {
reject(err);
isConnected.value = false;
uni.showToast({
title: 'NFC 连接失败',
icon: 'none',
});
}
},
});
});
}
/**
* 断开 nfc
*
* @return {*}
*/
function close() {
return new Promise((resolve, reject) => {
if (!isSupportNFC.value) {
reject({
errMsg: '不支持NFC',
});
return;
}
if (!nfcInstance) {
reject({
errMsg: '未读取到NFC卡',
});
return;
}
nfcInstance?.close?.({
success: (res) => {
isConnected.value = false;
nfcInstance = undefined;
resolve(res);
uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
},
fail: (err) => {
reject(err);
uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
},
});
});
}
async function transceive(data: ArrayBuffer) {
return new Promise((resolve, reject) => {
if (!isSupportNFC.value) {
reject({
errMsg: '不支持NFC',
});
return;
}
if (!nfcInstance) {
reject({
errMsg: '未读取到NFC卡',
});
return;
}
nfcInstance?.transceive?.({
data,
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
async function writeNdefMessage(data: NFC.NdefData) {
return new Promise((resolve, reject) => {
if (!isSupportNFC.value) {
reject({
errMsg: '不支持NFC',
});
return;
}
if (!nfcInstance) {
reject({
errMsg: '未读取到NFC卡',
});
return;
}
nfcInstance?.writeNdefMessage?.({
...data,
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
}
/**
* 写入数据
*
* 支持以以下类型
* ISO-DEP
* MIFARE Classic
* MIFARE Ultralight
* NFC-A
* NFC-B
* NFC-F
* NFC-V
*
* @param {*} data
* @return {*}
*/
async function write(data: ArrayBuffer) {
try {
// 连接 nfc
await connect();
uni.showToast({
title: '开始写入数据, 请勿断开连接',
icon: 'none',
});
// 写入数据
await transceive(data);
uni.showToast({
title: '写入成功',
icon: 'none',
});
// 断开 nfc
// await close();
} catch (error) {
throw error;
}
}
/**
* 写入数据
* 支持以以下类型
* Ndef
*
* @param {NFC.NdefData} data
*/
async function writeNdf(data: NFC.NdefData) {
try {
// 连接 nfc
await connect();
uni.showToast({
title: '开始写入数据, 请勿断开连接',
icon: 'none',
});
// 写入数据
await writeNdefMessage(data);
uni.showToast({
title: '写入成功',
icon: 'none',
});
// 断开 nfc
await close();
} catch (error) {
throw error;
}
}
onLoad(() => {
initNfcAdapter();
});
onUnload(() => {
stopHCE();
offHCEMessage();
});
return {
data,
isNdef,
isSupportNFC,
isListening,
isConnected,
nfcInstance,
startHCE,
stopHCE,
connect,
close,
write,
writeNdf,
};
}