导航菜单
首页 » 问答 » 正文

uni-app NFC读取卡Id 扇门块的16进制数组 数据解析

uni-app NFC读取功能大纲

这里的功能只是安卓APP的,后续可能更新多微信小程序之类的,目前 IOS系统的可能不太考虑做

网上NFC的资料是真的少之又少,基本上10个9个一模一样的都是使用

.nfc.extra.

直接读取其中的数据,并没有实际的读取 扇区和扇区块中的byte数组信息,只能自己摸索

虽然都是东拼西凑出来的,但是起码解决了想读取扇区信息的需求------ 目前没解决如何读取密码块的密码

下面是我需要想要的效果

读取扇区的js文件

.js

class NFCServices {
	readyWriteData = false; //开启写
	readyRead = false; //开启读
	noNFC = false;
	callBack = null;
	readyData = ''; //准备写入的数据
	static techListsArray = [
		['android.nfc.tech.IsoDep'],
		['android.nfc.tech.NfcA'],
		['android.nfc.tech.NfcB'],
		['android.nfc.tech.NfcF'],
		['android.nfc.tech.Nfcf'],
		['android.nfc.tech.NfcV'],
		['android.nfc.tech.NdefFormatable'],
		['android.nfc.tech.MifareClassic'],
		['android.nfc.tech.MifareUltralight']
	];
	// 要写入的数据
	static package_TECH_DISCOVERED = 'android.nfc.action.TECH_DISCOVERED';
	static READ_SUCCESS = '1' //读取成功
	static READ_FAIL = '2' //读取失败
	static READING = '3' //正在读取
	static WRITING = '4' //正在写入
	static WRITE_SUCCESS = '5' //写入成功
	static WRITE_FAIL = '6' //写入失败
	static DEVICE_NO_NFC = '7' //设备不支持NFC
	static DEVICE_NFC_NOT_ENABLE = '8' //设备未开启NFC
	static DEVICE_NFC_NOT_ENABLE = '9' //设备未开启NFC
	static INIT = '10' //初始化NFC
	static INIT_ERROR = '11' //初始化NFC失败
	constructor(callBack, continuousRead) {
		//是否连续读取NFC数据
		this.isContinuousRead = continuousRead !== undefined ? continuousRead : true
		this.callBack = callBack
		this.RuntimeMainActivity = plus.android.runtimeMainActivity();
		this.Intent = plus.android.importClass('android.content.Intent');
		this.PendingIntent = plus.android.importClass('android.app.PendingIntent');
		this.IntentFilter = plus.android.importClass('android.content.IntentFilter');
		this.NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');
		this.NdefRecord = plus.android.importClass("android.nfc.NdefRecord");
		this.NdefMessage = plus.android.importClass("android.nfc.NdefMessage");
		this.Ndef = plus.android.importClass('android.nfc.tech.Ndef');
		this.NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');
		this.MifareClassic = plus.android.importClass('android.nfc.tech.MifareClassic');
		this.nfcA = plus.android.importClass('android.nfc.tech.NfcA')
		// this.Parcelable = plus.android.importClass("android.os.Parcelable");
	}
	listenNFCStatus() {
		if (uni.getSystemInfoSync().platform !== "android") {
			return
		}
		this.callBack(NFCServices.INIT, '监听NFC状态!')
		try {
			let nfcAdapter = this.NfcAdapter.getDefaultAdapter(this.RuntimeMainActivity);
			if (nfcAdapter == null) {
				this.callBack(NFCServices.DEVICE_NO_NFC, '设备不支持NFC!')
				this.noNFC = true;
				return;
			}
			if (!nfcAdapter.isEnabled()) {
				this.callBack(NFCServices.DEVICE_NFC_NOT_ENABLE, '请在系统设置中先启用NFC功能!')
				this.noNFC = true;
				return;
			} else {
				this.noNFC = false;
			}
			let intent = new this.Intent(this.RuntimeMainActivity, this.RuntimeMainActivity.getClass());
			intent.addFlags(this.Intent.FLAG_ACTIVITY_SINGLE_TOP);
			let pendingIntent = this.PendingIntent.getActivity(this.RuntimeMainActivity, 0, intent, 0);
			let ndef = new this.IntentFilter("android.nfc.action.TECH_DISCOVERED");
			ndef.addDataType("*/*");
			let intentFiltersArray = [ndef];
			const that = this
			plus.globalEvent.addEventListener('newintent', () => {
				console.log('newintent running');
				// 轮询调用 NFC
				that.nfcRuning()
				// setTimeout(, 1000);
			});
			plus.globalEvent.addEventListener('pause', (e) => {
				console.log('pause running');
				if (nfcAdapter) {
					//关闭前台调度系统 恢复默认状态
					nfcAdapter.disableForegroundDispatch(this.RuntimeMainActivity);
				}
			});
			plus.globalEvent.addEventListener('resume', (e) => {
				if (nfcAdapter) {
					//开启前台调度系统 优于所有其他NFC
					nfcAdapter.enableForegroundDispatch(this.RuntimeMainActivity, pendingIntent,
						intentFiltersArray,
						NFCServices.techListsArray);
				}
			});
			nfcAdapter.enableForegroundDispatch(this.RuntimeMainActivity, pendingIntent, intentFiltersArray,
				NFCServices.techListsArray);
		} catch (e) {
			this.callBack(NFCServices.INIT_ERROR, '初始化NFC失败!', e)
		}
	}
	nfcRuning() { //
		let intent = this.RuntimeMainActivity.getIntent();
		if (NFCServices.package_TECH_DISCOVERED == intent.getAction()) {
			if (this.readyWriteData) {
				this.write(intent);
				this.readyWriteData = false;
			} else if (this.isContinuousRead || this.readyRead) {
				this.read(intent);
				this.readyRead = false;
			}
		}
	}
	write(intent) { //写代码
		try {
			this.callBack(NFCServices.WRITING, '请勿移开标签 正在写入...')
			let textBytes = plus.android.invoke(this.readyData, "getBytes");
			// image/jpeg text/plain  
			let textRecord = new this.NdefRecord(this.NdefRecord.TNF_MIME_MEDIA,
				plus.android.invoke("text/plain", "getBytes"),
				plus.android.invoke("", "getBytes"), textBytes);
			let message = new this.NdefMessage([textRecord]);
			let tag = intent.getParcelableExtra(this.NfcAdapter.EXTRA_TAG);
			let ndef = this.Ndef.get(tag);
			if (ndef != null) {
				// 待写入的数据长度
				let size = message.toByteArray().length;
				ndef.connect();
				if (!ndef.isWritable()) {
					this.callBack(NFCServices.WRITE_FAIL, 'tag不允许写入!')
					return;
				}
				if (ndef.getMaxSize() < size) {
					this.callBack(NFCServices.WRITE_FAIL, '文件大小超出容量!')
					return;
				}
				ndef.writeNdefMessage(message); //写入数据
				this.callBack(NFCServices.WRITE_SUCCESS, '写入数据成功!', this.readyData)
				return;
			} else {
				let format = this.NdefFormatable.get(tag);
				if (format != null) {
					try {
						format.connect();
						format.format(message);
						this.callBack(NFCServices.WRITE_SUCCESS, '格式化tag并且写入数据成功!', this.readyData)
						return;
					} catch (e) {
						this.callBack(NFCServices.WRITE_FAIL, '格式化tag失败!')
						return;
					}
				} else {
					this.callBack(NFCServices.WRITE_FAIL, 'Tag不支持NDEF!')
					return;
				}
			}
		} catch (e) {
			this.callBack(NFCServices.WRITE_FAIL, '写入失败!', e)
		}
	}
	read(intent) { // 读代码
		this.callBack(NFCServices.READING, '请勿移开标签正在读取数据!')
		// NFC id
		let bytesId = intent.getByteArrayExtra(this.NfcAdapter.EXTRA_ID);
		let nfc_id = this.byteArrayToHexString(bytesId);
		console.log('nfc_id:', nfc_id);
		
		// 读取扇区
		let tag = intent.getParcelableExtra(this.NfcAdapter.EXTRA_TAG);
		
		// let fa = this.nfcA.get(tag)
		// 	console.log('实例获取---',fa)
		// fa.connect()
		let miclass = this.MifareClassic.get(tag)
		miclass.connect()
		let count = miclass.getSectorCount()
		console.log('====:',count,this.HexStringToByteArray('FFFFFFFFFFFF'))
		let shanQ = []
		let num = 0
		for (let i=0; i<count; i++) {
			if (miclass.authenticateSectorWithKeyA(i,this.HexStringToByteArray('FFFFFFFFFFFF'))) {
				console.log(11111)
			}
			if (miclass.authenticateSectorWithKeyB(i,this.HexStringToByteArray('FFFFFFFFFFFF'))) {
				console.log(222222)
			}
			let arr=[]
			for (let o = 0; o < 4; o++) {
				num = num + 1
			    let content = miclass.readBlock(num-1)
			    console.log(`当前${i}扇区---第${num-1}`+content)
			    arr.push(this.Bytes2Str(content))
			}
			console.log('数据体---',arr)
			shanQ.push(arr)
		}
		console.log('转换好的数据',shanQ)
		// let blockCount = miclass.getBlockCountInSector()
		// for (let i=0; i
		//     // 获取要读取的块号
		//     let blockIndex = miclass.sectorToBlock(i)
		//     // 读取块数据
		// 	let data = miclass.readBlock(blockIndex);
		// 	console.log('循环扇区获取的:----'+blockIndex+'扇区:',data)
		// }
		
		// 卡内信息
		let rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES");
		//let rawmsgs = intent.getParcelableArrayExtra();
		console.log("数据" + rawmsgs)
		if (rawmsgs != null && rawmsgs.length > 0) {
			let records = rawmsgs[0].getRecords();
			console.log("数据22222" + records)
			let result = records[0].getPayload();
			console.log("数据33333" + result)
			let data = plus.android.newObject("java.lang.String", result);
			this.callBack(NFCServices.READ_SUCCESS, '读取数据成功!', data)
		} else {
			this.callBack(NFCServices.READ_FAIL, '没有读取到数据!')
		}
	}
	//Key处理函数
	
	HexStringToByteArray (instr) {
	    var hexA = new Array();
	    var pos = 0;
	    var len = instr.length/2;
	    for(var i=0; i<len; i++)
	    {
	        var s = instr.substr(pos, 2);
	        var v = parseInt(s, 16);
	        if(v>=128)
	            v=v-256;
	        hexA.push(v);
	        pos += 2;
	    }
	    return hexA;
	}
	
	// 格式化 byte[]数组 如[117,-117,65....] 这类的byte数组转换成  16进制[75,84,A3....]这类型的数据
	Bytes2Str(arrBytes){
		var str = "";
		for (var i = 0; i < arrBytes.length; i++) {
			var tmp;
			var num = arrBytes[i];
			if (num < 0) {
				//此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理
				tmp = (255 + num + 1).toString(16);
			} else {
				tmp = num.toString(16);
			}
			if (tmp.length == 1) {
				tmp = "0" + tmp;
			}
			if(i>0){
				str += ""+tmp; // 可以修改 : 成你需要的间隔符号,如果不需要间隔符号那就空着
			}else{
				str += tmp;
			}
		}
		return str.toLocaleUpperCase();
	}
	str2UTF8(str){
		var bytes = new Array(); 
		var len,c;
		len = str.length;
		for(var i = 0; i < len; i++){
			c = str.charCodeAt(i);
			if(c >= 0x010000 && c <= 0x10FFFF){
				bytes.push(((c >> 18) & 0x07) | 0xF0);
				bytes.push(((c >> 12) & 0x3F) | 0x80);
				bytes.push(((c >> 6) & 0x3F) | 0x80);
				bytes.push((c & 0x3F) | 0x80);
			}else if(c >= 0x000800 && c <= 0x00FFFF){
				bytes.push(((c >> 12) & 0x0F) | 0xE0);
				bytes.push(((c >> 6) & 0x3F) | 0x80);
				bytes.push((c & 0x3F) | 0x80);
			}else if(c >= 0x000080 && c <= 0x0007FF){
				bytes.push(((c >> 6) & 0x1F) | 0xC0);
				bytes.push((c & 0x3F) | 0x80);
			}else{
				bytes.push(c & 0xFF);
			}
		}
		return bytes;
	}
	// 将字节数组转换为字符串  
	byteArrayToHexString(inarray) {
		let i, j, inn;
		let hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
		let out = "";
		for (j = 0; j < inarray.length; ++j) {
			inn = inarray[j] & 0xff;
			i = (inn >>> 4) & 0x0f;
			out += hex[i];
			i = inn & 0x0f;
			out += hex[i];
		}
		return out;
	}
	// 更改写状态
	writeData(data) {
		if (this.noNFC) {
			this.callBack(NFCServices.WRITE_FAIL, '请检查设备是否支持并开启 NFC 功能!')
			return;
		}
		this.readyData = data
		// 轮询条件
		this.readyWriteData = true;
		this.callBack(NFCServices.WRITING, '请将NFC标签靠近!')
	}
	readData() { // 更改读状态
		if (this.noNFC) {
			this.callBack(NFCServices.READ_FAIL, '请检查设备是否支持并开启 NFC 功能!')
			return;
		}
		// 轮询条件
		this.readyRead = true;
		this.callBack(NFCServices.READING, '请将NFC标签靠近!')
	}
	// 设置数据
	destroy() {
		plus.globalEvent.removeEventListener('newintent', false);
		plus.globalEvent.removeEventListener('pause', false);
		plus.globalEvent.removeEventListener('resume', false);
	}
}
export default NFCServices

nfc.vue

<template>
	<view class="nfc">
		<textarea class="txtarea" disabled :value="readData" placeholder="这是读取到的nfc的数据" />
		<button class="btn" @tap="read()">读取NFC</button>
		<textarea class="txtarea" v-model="writeTxt" maxlength="124" placeholder="这是输入写入的nfc的数据" />
		<button class="btn" @tap="write()">写入NFC</button>
	</view>
</template>
<script>
	// nfc 输入最大数字长度为124位,文字为41位
	import NFCServices from '@/nfc/nfcServices.js'
	let nfcServices;
	export default {
		onLoad() {
			nfcServices = new NFCServices(this.NFCServicesCallBack)
			nfcServices.listenNFCStatus()
		},
		onShow() {
		},
		onUnload() {
			nfcServices.destroy()
		},
		data() {
			return {
				writeTxt: '',
				readData: ''
			}
		},
		methods: {
			NFCServicesCallBack(status, tip, data) {
				switch (status) {
					case NFCServices.READ_SUCCESS:
						this.readData = data
						break;
					default:
						break;
				}
				console.log(tip, data);
				uni.showToast({
				    title: tip,
				    icon: 'none'
				});
			},
			read() {
				// 调用 js 文件里面的方法
				nfcServices.readData()
			},
			write() {
				// 调用 js 文件里面的方法
				nfcServices.writeData(this.writeTxt)
			},
		}
	}
</script>
<style lang="scss">
	.nfc {
		padding: 20rpx;
		.txt {
			height: 240rpx;
			line-height: 50rpx;
			font-size: 32rpx;
		}
		.txtarea {
			width: 100%;
			min-height: 240rpx;
			border: 1px solid #f0f0f0;
		}
		.btn {
			border: none;
			background-color: #1b85e9;
			color: #fff;
			margin: 20rpx 0;
		}
	}
</style>

最后得出的

打包时候记得把这个给勾上噢

评论(0)

二维码