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)