/**
* 请先读以下 * M1 写卡采用NFC MifareClassic技术 *
* 流程
* 首先设备要支持NFC权限开启的前提下 不论哪种方式,都是先刷卡,等待系统分发响应的Activity 拿到Tag或者 前台Activity捕获到TAG 。然后根据这个标签支持的技术去解析数据。 *
* M1卡解析
* 不论是NFC还是读卡模块读,解析流程都是先寻卡,然后验证扇区的密码,取扇区的数据,比如已知要读的数据在2扇区,那么寻卡后验证时把要验证的扇区号、扇区的密码,和扇区的验证密码类型A/B传过去验证通过后,就可以读取数据了 *
* 扇区
* 一般16个扇区 每个区 有4块,总共64块
* 第一扇区的第一块一般用于制造商占用块
* 0-15个扇区:一个扇区对应4个块,所以总共有64个块,序号分别为0-63,第一个扇区对应:0-3块,第二个扇区对应:4-7块...
* 每个扇区的最后一个块用来存放密码或控制位,其余为数据块,一个块占用16个字节,keyA占用6字节,控制位占用4字节,keyB占用6字节 *
* import android.nfc.tech.MifareClassic;
* MifareClassic类的常用方法
* get():根据Tag对象来获得MifareClassic对象;
* Connect():允许对MifareClassic标签进行IO操作;
* getType():获得MifareClassic标签的具体类型:TYPE_CLASSIC,TYPE_PLUA,TYPE_PRO,TYPE_UNKNOWN
* getSectorCount():获得标签总共有的扇区数量;
* getBlockCount():获得标签总共有的的块数量;
* getSize():获得标签的容量:SIZE_1K,SIZE_2K,SIZE_4K,SIZE_MINI
* authenticateSectorWithKeyA(int SectorIndex,byte[] Key):验证当前扇区的KeyA密码,返回值为ture或false。
* authenticateSectorWithKeyB(int SectorIndex,byte[] Key):验证当前扇区的KeyB密码,返回值为ture或false。
* getBlockCountInSector(int):获得当前扇区的所包含块的数量 * sectorToBlock(int):当前扇区的第1块的块号;
* writeBlock(int,data):将数据data写入当前块;注意:data必须刚好是16Byte,末尾不能用0填充,应该用空格
* readBlock(int):读取当前块的数据。 * close():禁止对标签的IO操作,释放资源。 *
* MifareClassic标签的读写流程
* 1,获得Adapter对象
* 2,获得Tag对象
* 3,获得MifareClassic对象
* 4,读取数据块的数据,连接 Connect(),读readBlock(),关闭close()
* 5,将数据块写入标签,连接 Connect(),读writeBlock(),关闭 close()
*/
一,获取nfc适配器,判断设备是否支持NFC功能
// nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
// shotToast("当前设备不支持NFC功能");
} else if (!nfcAdapter.isEnabled()) {
// shotToast("NFC功能未打开,请先开启后重试!");
}
//允许扫描的标签类型
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED); ndef.addCategory("*/*"); // 允许扫描的标签类型 mWriteTagFilters = new IntentFilter[]{ndef}; mTechLists = new String[][]{ new String[]{ MifareClassic.class.getName() }, new String[]{ NfcA.class.getName() } };// 允许扫描的标签类型
//开启前台调度系统
nfcAdapter.enableForegroundDispatch(this, pendingIntent, mWriteTagFilters, mTechLists);
二,获取卡ID
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//通过Tag.getId()方法,获得标签的唯一ID标识String CardId = ConvertUtil.byteArrayToHexStr(tagFromIntent.getId());
三,获取密钥
四,获取M1卡对象类
mfc = MifareClassic.get(tag);
五,链接
mfc.connect();
六,验证密钥
// 扇区验证是否成功boolean isAuthenticated = false//sectorIndex:区,hexPs:密钥
if (mfc.authenticateSectorWithKeyA(sectorIndex, hexPsw) ) {
isAuthenticated = true;
} else if(mfc.authenticateSectorWithKeyB(sectorIndex, hexPsw) ){
isAuthenticated = true;
} else {
Log.d("读取扇区"+sectorIndex+"验证失败",pswStr);
mfc.close();
}
七,读写NFC
//当前扇区的第1块的块号
int block = mfc.sectorToBlock(sectorIndex);
读
byte[] blockByte = mfc.readBlock(i);
写
//blockIndex 写第几块,0-63
//hexText 写的数据mfc.writeBlock(blockIndex,hexText);