在开发微信小程序的时候遇到个读取nfc数据进行跳转的问题,通过查看wx的官方文档,发现有两个方法可以使用,一个是wx.startHCE(),一个是wx.getNFCAdapter()。通过尝试和查询,最后发现wx.startHCE()只适用于支付类卡,还必须传入AID值,不适用读取nfc标签数据的需求,而wx.getNFCAdapter()可以实现这个需求,但是微信小程序读取出的值会返回一个ArrayBuffer的数据类型,正常用console.log()输入会出现一个“空对象”的情况,下面我将会讲wx.getNFCAdapter()的使用方法,以及如何处理读取到的数据。

注:此方法只适用于安卓用户,苹果用户暂不支持。

一、使用wx.getNFCAdapter()开启nfc监听。

1.开启监听

	// 实例化
    const nfcAdapter = ref(null)
    // 是否开启
	const isReading = ref(false)
    // 错误信息
    const errorMessage = ref('')
    // 初始化NFC
	const initNfc = () => {
		// 确保在微信小程序环境
		// #ifdef MP-WEIXIN
		if (!wx.getNFCAdapter) {
			errorMessage.value = '当前微信版本不支持NFC'
			return
		}
		nfcAdapter.value = wx.getNFCAdapter()
		startDiscovery()
		// #endif
	}

	// 开始发现NFC标签
	const startDiscovery = () => {
		if (!nfcAdapter.value || isReading.value) return
		nfcAdapter.value.startDiscovery({
			techTypes: ['android.nfc.tech.Ndef'], // 明确指定NDEF格式
			success: () => {
				showToast('nfc监听启动成功')
				isReading.value = true
				setupListeners()
			},
			fail: (err) => {
				errorMessage.value = `NFC启动失败: ${err.errMsg}`
				console.error('NFC错误:', err)
			}
		})
	}

    // 处理读取到的nfc数据
	const setupListeners = () => {
		nfcAdapter.value.onDiscovered((res) => {
			console.log('读取到的nfc数据',res);
		});
	};

 2.释放资源

启动监听之后,每次离开页面释放资源,以免出现重复进入页面nfc报错。

	// 释放资源
	const releaseNfc = () => {
		if (nfcAdapter.value && isReading.value) {
			nfcAdapter.value.stopDiscovery()
			nfcAdapter.value.offDiscovered?.()
			isReading.value = false
		}
	}

 二、处理返回后的数据

一般标签的返回数据是

	{
		"messages": [{
			"records": [{
				"tnf": 1,
				"type": {},
				"id": {},
				"payload": {}
			}]
		}],
		"techs": ["NFC-4", "NDEF"]
	}

一般数据就存储在payload里面,只不过由于微信小程序返回的数据是个buffer,所以看不到他的完整信息,也无法使用,这个时候就需要将需要的数据转换一下。

我这边使用的方法是先将buffer转为十六进制,再将十六进制转为字符串

1.buffer转为十六进制

    // 转换为十六进制字符串
    function arrayBufferToHex(buffer) {
	    return Array.from(new Uint8Array(buffer))
		    .map(byte => byte.toString(16).padStart(2, '0'))
		    .join('')
    }

2.十六进制手动转为字符串

 这里选择的是手动转为字符串,在查资料的时候是发现有TextDecoder()和Buffer()的方法完成数据转换的,不过可能是环境不支持吧,方法无法使用,最后还是手动转为字符串。

	// 十六进制手动转为字符串
    function hexToString(hex) {
		// 1. 移除非法字符(如空格、冒号)
		const cleanHex = hex.replace(/[^0-9a-fA-F]/g, '');

		// 2. 每 2 个字符解析为一个 Unicode 码点
		let str = '';
		for (let i = 0; i < cleanHex.length; i += 2) {
			const byte = cleanHex.substr(i, 2);
			str += String.fromCharCode(parseInt(byte, 16));
		}

		// 3. 处理中文(UTF-8 编码)
		try {
			return decodeURIComponent(escape(str));
		} catch (e) {
			return str; // 如果解码失败(如非 UTF-8 数据),返回原始字符串
		}
	}

在数据转为字符串之后,就可以正常的使用了。

以下是完整代码:

	
	// 初始化
	onMounted(() => {
		initNfc()
	})
    // 释放资源
	onUnmounted(() => {
		releaseNfc()
	})
    // 实例化
    const nfcAdapter = ref(null)
    // 是否开启
	const isReading = ref(false)
    // 错误信息
    const errorMessage = ref('')
    // 初始化NFC
	const initNfc = () => {
		// 确保在微信小程序环境
		// #ifdef MP-WEIXIN
		if (!wx.getNFCAdapter) {
			errorMessage.value = '当前微信版本不支持NFC'
			return
		}
		nfcAdapter.value = wx.getNFCAdapter()
		startDiscovery()
		// #endif
	}

	// 开始发现NFC标签
	const startDiscovery = () => {
		if (!nfcAdapter.value || isReading.value) return
		nfcAdapter.value.startDiscovery({
			techTypes: ['android.nfc.tech.Ndef'], // 明确指定NDEF格式
			success: () => {
				showToast('nfc监听启动成功')
				isReading.value = true
				setupListeners()
			},
			fail: (err) => {
				errorMessage.value = `NFC启动失败: ${err.errMsg}`
				console.error('NFC错误:', err)
			}
		})
	}

    // 处理读取到的nfc数据
	const setupListeners = () => {
		nfcAdapter.value.onDiscovered((res) => {
			console.log('读取到的nfc数据',res);
				// 转化字符串后的nfc数据,具体内部传入的数据根据自身nfc返回的数据传入
				let nfcData = hexToString(arrayBufferToHex(res.messages[0].records[0].payload))
		});
	};

	// 释放资源
	const releaseNfc = () => {
		if (nfcAdapter.value && isReading.value) {
			nfcAdapter.value.stopDiscovery()
			nfcAdapter.value.offDiscovered?.()
			isReading.value = false
		}
	}

    // 转换为十六进制字符串
	function arrayBufferToHex(buffer) {
		return Array.from(new Uint8Array(buffer))
			.map(byte => byte.toString(16).padStart(2, '0'))
			.join('')
	}

	// 十六进制手动转为字符串
	function hexToString(hex) {
		// 1. 移除非法字符(如空格、冒号)
		const cleanHex = hex.replace(/[^0-9a-fA-F]/g, '');

		// 2. 每 2 个字符解析为一个 Unicode 码点
		let str = '';
		for (let i = 0; i < cleanHex.length; i += 2) {
			const byte = cleanHex.substr(i, 2);
			str += String.fromCharCode(parseInt(byte, 16));
		}

		// 3. 处理中文(UTF-8 编码)
		try {
			return decodeURIComponent(escape(str));
		} catch (e) {
			return str; // 如果解码失败(如非 UTF-8 数据),返回原始字符串
		}
	}

如有错误的地方,欢迎联系俺来纠正。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐