Android NFC M1卡读写&芯片卡读写(CPU卡读写)(RFID读写)
NFC 读写分几种,本文主要讲M1卡扇区读写和芯片卡读写权限初始化1 onCreate( initNFC() )2 onResume( )3 onPause()4 NFC设备刷卡时触发 onNewIntent(Intent)
1,标签读写2,扇区读写3 CPU卡读写 重头戏
NFC 读写分几种,本文主要讲M1卡扇区读写和芯片卡读写
NFC 标签读写 NFC 扇区读写 NFC 文件读写
权限
初始化
在Activity#onCreate()注册,在Activity#onResume()开启前台调度系统,在Activity#onPause退出前台调度。
1 onCreate( initNFC() )
private void initNFC() {
// 获取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()}};// 允许扫描的标签类型
}
2 onResume( )
@Override
protected void onResume() {
super.onResume();
//开启前台调度系统
nfcAdapter.enableForegroundDispatch(this, pendingIntent, mWriteTagFilters, mTechLists);
}
3 onPause()
@Override
protected void onPause() {
super.onPause();
nfcAdapter.disableForegroundDispatch(this);
}
4 NFC设备刷卡时触发 onNewIntent(Intent)
给伪代码,详细见下面3点分解
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//当该Activity接收到NFC标签时,运行该方法
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
1,标签读写
Ndef ndef = Ndef.get(tag);//如果ndef为空表示不支持该格式
//可进行格式 如果格式化失败则不能只能换个方式
2,M1 扇区读写
MifareClassic mfc = MifareClassic.get(tag);//CPU卡时 mfc将为空
3,CPU卡 读写
NfcCpuUtilsnfc = new NfcCpuUtils(IsoDep.get(tag));
}
}
1,标签读写
/**
* 写标签
* @param ndef
* @param tag
* @param ndefMessage
* @return
* @throws IOException
* @throws FormatException
*/
private boolean writeMsg(Ndef ndef, Tag tag, NdefMessage ndefMessage) throws IOException, FormatException {
try {
if (ndef == null) {
shotToast("格式化数据开始");
//Ndef格式类
NdefFormatable format = NdefFormatable.get(tag);
format.connect();
format.format(ndefMessage);
} else {
shotToast("写入数据开始");
//数据的写入过程一定要有连接操作
ndef.connect();
ndef.writeNdefMessage(ndefMessage);
}
return true;
} catch (IOException e) {
e.printStackTrace();
shotToast("IO异常,读写失败");
} catch (FormatException e) {
e.printStackTrace();
shotToast("格式化异常,读写失败");
} catch (NullPointerException e) {
shotToast("格NullPointerException异常,读写失败");
}catch (IllegalStateException e){
shotToast("Close other technology first!");
}
return false;
}
/**
* 读取NFC标签文本数据
*/
private void readNfcTag(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())||
NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msgs[] = null;
int contentSize = 0;
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
contentSize += msgs[i].toByteArray().length;
}
}
try {
if (msgs != null) {
print(msgs.length+" 长度");
NdefRecord record = msgs[0].getRecords()[0];
String textRecord = parseTextRecord(record);
mTagText += textRecord + "\n\ntext\n" + contentSize + " bytes";
print(mTagText);
}
} catch (Exception e) {
}
}
}
2,扇区读写
M1扇区默认是没有密码的,但有部分人闲不住要把密码改了,因此认证过程要加密码,一般认证KeyA就行。普通卡16个扇区64块,第一个扇区等闲不能操作。每个扇区4块,从0数起,第二扇区第一块索引就是8,每个扇区前3块存数据最后一块一般存密码。实例代码读的是2扇区8块。
/**
* 扇区写
* @param tag
* @param sectorIndex 扇区索引 一般16个扇区 64块
* @return
*/
public boolean writeTAG(Tag tag,int sectorIndex) {
MifareClassic mfc = MifareClassic.get(tag);
try {
mfc.connect();
if (mfc.authenticateSectorWithKeyA(sectorIndex, new byte[]{0x42,0x53,0x4B, (byte) sectorIndex,0x4C,0x53})) { //已知密码认证 r
// the last block of the sector is used for KeyA and KeyB cannot be overwritted
int block = mfc.sectorToBlock(sectorIndex);
mfc.writeBlock(block, "sgn-old000000000".getBytes());
mfc.close();
shotToast("旧卡 写入成功");
return true;
}else if(mfc.authenticateSectorWithKeyA(sectorIndex, MifareClassic.KEY_NFC_FORUM)){ //新卡 未设密码认证 r
int block = mfc.sectorToBlock(sectorIndex);
mfc.writeBlock(block, "SGN-new000000000".getBytes());
mfc.close();
shotToast("新卡 写入成功");
} else{
shotToast("未认证");
}
} catch (IOException e) {
e.printStackTrace();
shotToast("扇区连接异常");
try {
mfc.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
return false;
}
/**
* 读扇区
* @return
*/
private String readTag(Tag tag,MifareClassic mfc,int sectorIndex){
for (String tech : tag.getTechList()) {
System.out.println("------------"+tech);
}
//读取TAG
try {
String metaInfo = "";
//Enable I/O operations to the tag from this TagTechnology object.
mfc.connect();
int type = mfc.getType();//获取TAG的类型
int sectorCount = mfc.getSectorCount();//获取TAG中包含的扇区数
String typeS = "";
switch (type) {
case MifareClassic.TYPE_CLASSIC:
typeS = "TYPE_CLASSIC";
break;
case MifareClassic.TYPE_PLUS:
typeS = "TYPE_PLUS";
break;
case MifareClassic.TYPE_PRO:
typeS = "TYPE_PRO";
break;
case MifareClassic.TYPE_UNKNOWN:
typeS = "TYPE_UNKNOWN";
break;
}
metaInfo += "卡片类型:" + typeS + "\n共" + sectorCount + "个扇区\n共" + mfc.getBlockCount() + "个块\n存储空间: " + mfc.getSize() + "B\n";
int blockIndex;
if (mfc.authenticateSectorWithKeyA(sectorIndex, new byte[]{0x42,0x53,0x4B, (byte) sectorIndex,0x4C,0x53}) ) {
blockIndex = mfc.sectorToBlock(sectorIndex);
byte[] data = mfc.readBlock(blockIndex);
metaInfo += "旧卡 Block " + blockIndex + " : " + new String(data) + "\n";
}else if( mfc.authenticateSectorWithKeyA(sectorIndex, MifareClassic.KEY_NFC_FORUM)){
blockIndex = mfc.sectorToBlock(sectorIndex);
byte[] data = mfc.readBlock(blockIndex);
metaInfo += "新卡 Block " + blockIndex + " : " + new String(data) + "\n";
}else {
metaInfo += "Sector " + sectorIndex + ":验证失败\n";
}
return metaInfo;
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();
} finally {
if (mfc != null) {
try {
mfc.close();
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG)
.show();
}
}
}
return null;
}
3 CPU卡读写 重头戏
先直接上代码,看完代码在说吧,搞这个有点心力疲惫。 下面是一个写的完全流程,if的嵌套我承认有点low,但有助于流程理解。 这里要说下外部认证过程: devices -----获取4字节随机数---------------------> cpu 卡 devices cpu 卡 devices 8) {
byte[] respondKey = {0x00, (byte) 0x82, 0x00, 0x00, 0x08, desKey[0], desKey[1], desKey[2], desKey[3], desKey[4], desKey[5], desKey[6], desKey[7]};
print("4 生产加密后的随机码命令");
printByte(respondKey);
resp = tag.transceive(respondKey); //5 将加密后的随机码发送,注意此处第四字节表示密码标识符00,
}
if (checkRs(resp)) {
print("5 外部认证成功");
resp = tag.transceive(CMD_DEL);
if (checkRs(resp)) {
print("6 删除目录成功");
resp = tag.transceive(CMD_CREATE_DIR);
if (checkRs(resp)) {
print("7 选择目录");
resp = tag.transceive(CMD_CREATE_KEY);
if (checkRs(resp)) {
print("8 建立目录");
resp = tag.transceive(CMD_CREATE_OUT_KEY);
if (checkRs(resp)) {
print("9 创建外部认证密钥成功");
resp = tag.transceive(CMD_ACCESS);
if (checkRs(resp)) {
print("10 建立访问自定义文件的密钥文件成功");
resp = tag.transceive(CMD_ACCESS_INTO); //11 填充密钥123456
if (checkRs(resp)) {
print("11 填充密钥123456成功");
resp = tag.transceive(CMD_ACCESS_FILE); //12 创建自定义文件,标识为005
if (checkRs(resp)) {
print("12 创建自定义文件,标识为005成功");
resp = tag.transceive(CMD_ACCESS_FILE_CHOOICE); // 13 选中该文件0005
if (checkRs(resp)) {
print(" 13 选中该文件0005成功");
resp = tag.transceive(CMD_ACCESS_FILE_WRITE); //14 写数据“112233445566”到该文件
if (checkRs(resp)) { //15 应该有关闭连接
print("14 写数据“112233445566”到该文件成功");
return "01".getBytes();
}
}
}
}
}
}
}
}
}
}
}
}
return null;
}
private boolean checkRs(byte[] resp) {
String r = printByte(resp);
Log.i("---------", "response " + r);
int status = ((0xff & resp[resp.length - 2]) |