当前位置:   article > 正文

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

nfc-a技术读取扇区数据

uni-app NFC读取功能大纲

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

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

android.nfc.extra.NDEF_MESSAGES

直接读取其中的数据,并没有实际的读取 扇区和扇区块中的byte数组信息,只能自己摸索
虽然都是东拼西凑出来的,但是起码解决了想读取扇区信息的需求------ 目前没解决如何读取密码块的密码
下面是我需要想要的效果
在这里插入图片描述

读取扇区的js文件

nfcServices.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<blockCount; 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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353

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>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

最后得出的
在这里插入图片描述

打包时候记得把这个给勾上噢
在这里插入图片描述

// ============= 2024-2-21 更新 区块编辑(就差卡模拟了) ====================//

最近又需要做一个手机发卡的功能(仅限于安卓),如果是按照上面读写方法是完全没办法做到针对某一个块进行修改的,所以我苦心专研找到了这方面的方法,也实现了对卡的扇区块做数据编辑的方法了。(如果是学过安卓原生实际上很简单)。

相关的代码就不无偿分享了 ๑乛◡乛๑
在这里插入图片描述

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读