本文讲NFC各种标签的解析实现,本文从Tag讲起,如何拿到Tag请看Android NFC之读卡器模式
import android.nfc.Tag;
import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public abstract class CardReader {
public static String getId(Tag tag) {
return ByteArrayToHexString(tag.getId());
}
public static final String readTag(Tag tag) {
CardReader reader = with(tag);
if (reader == null) {
return "暂不支持此卡类型";
}
return reader.parse(tag);
}
public static final CardReader with(Tag tag) {
List techs = Arrays.asList(tag.getTechList());
if (techs.contains("android.nfc.tech.IsoDep")) {
return new CustomIsoDepReader();
}
if (techs.contains("android.nfc.tech.NfcBarcode")) {
return new NfcBarcodeReader();
}
if (techs.contains("android.nfc.tech.MifareClassic")) {
return new MifareClassicReader();
}
if (techs.contains("android.nfc.tech.MifareUltralight")) {
return new MifareUltralightReader();
}
if (techs.contains("android.nfc.tech.Ndef")) {
return new NdefReader();
}
if (techs.contains("android.nfc.tech.NfcA")) {
return new NfcAReader();
}
if (techs.contains("android.nfc.tech.NfcB")) {
return new NfcBReader();
}
if (techs.contains("android.nfc.tech.NfcV")) {
return new NfcVReader();
}
if (techs.contains("android.nfc.tech.NfcF")) {
return new NfcFReader();
}
if (techs.contains("android.nfc.tech.NdefFormatable")) {
}
return null;
}
public abstract String parse(Tag tag);
protected static String ByteArrayToHexString(byte[] inarray) {
int i, j, in;
String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
String out = "";
for (j = 0; j < inarray.length; ++j) {
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
return out;
}
protected static byte[] HexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
protected void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
closeable = null;
}
}
}
1.Ndef
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
public class NdefReader extends CardReader {
@Override
public String parse(Tag tag) {
Ndef ndef = Ndef.get(tag);
try {
ndef.connect();
NdefMessage ndefMessage = ndef.getNdefMessage();
NdefRecord[] records = ndefMessage.getRecords();
if (records == null || records.length <= 0) {
return "getRecords() is null";
}
StringBuffer buffer = new StringBuffer();
for (NdefRecord record : records) {
buffer.append("nNdefRecord:").append(record.toString());
}
return buffer.toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(ndef);
}
}
}
2.MifareClassic
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Log;
import java.io.IOException;
public class MifareClassicReader extends CardReader {
private static final String TAG = "MifareClassicReader";
@Override
public String parse(Tag tag) {
MifareClassic mifareClassic = MifareClassic.get(tag);
try {
mifareClassic.connect();
int type = mifareClassic.getType();//获取TAG的类型
int sectorCount = mifareClassic.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;
}
StringBuffer buffer = new StringBuffer();
buffer.append("n卡片类型:").append(typeS);
buffer.append("n共").append(sectorCount).append("个扇区");
buffer.append("n共").append(mifareClassic.getBlockCount()).append("个块");
buffer.append("n存储空间:").append(mifareClassic.getSize()).append("B");
boolean auth = false;
for (int j = 0; j < sectorCount; j++) {
//Authenticate a sector with key A.
buffer.append("nSector").append(j);
auth = mifareClassic.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT);
int bCount;
int bIndex;
if (auth) {
buffer.append("验证成功");
// 读取扇区中的块
bCount = mifareClassic.getBlockCountInSector(j);
bIndex = mifareClassic.sectorToBlock(j);
for (int i = 0; i < bCount; i++) {
byte[] data = mifareClassic.readBlock(bIndex);
buffer.append("nBlock " + bIndex + " : " + ByteArrayToHexString(data) + "");
bIndex++;
}
} else {
buffer.append("验证失败");
}
}
return buffer.toString();
} catch (IOException e) {
Log.d(TAG, "parse", e);
return e.getMessage();
} finally {
close(mifareClassic);
}
}
}
3.MifareUltralight
import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import java.io.IOException;
public class MifareUltralightReader extends CardReader {
@Override
public String parse(Tag tag) {
MifareUltralight mifareUltralight = MifareUltralight.get(tag);
try {
mifareUltralight.connect();
StringBuffer buffer = new StringBuffer();
int type = mifareUltralight.getType();
switch (type) {
case MifareUltralight.TYPE_ULTRALIGHT:
buffer.append("TYPE_ULTRALIGHT");
break;
case MifareUltralight.TYPE_ULTRALIGHT_C:
buffer.append("TYPE_ULTRALIGHT_C");
break;
case MifareUltralight.TYPE_UNKNOWN:
buffer.append("TYPE_UNKNOWN");
break;
}
byte[] payload = mifareUltralight.readPages(0);
byte[] payload1 = mifareUltralight.readPages(4);
byte[] payload2 = mifareUltralight.readPages(8);
byte[] payload3 = mifareUltralight.readPages(12);
buffer.append("nPage0-3:").append(ByteArrayToHexString(payload));
buffer.append("npage4-7:").append(ByteArrayToHexString(payload1));
buffer.append("npage8-11:").append(ByteArrayToHexString(payload2));
buffer.append("npage12-15:").append(ByteArrayToHexString(payload3));
return buffer.toString();
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(mifareUltralight);
}
}
}
4.IsoDep
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.util.Log;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class IsoDepReader extends CardReader {
private static final String TAG = "IsoDepReader";
protected final static byte TRANS_CSU = 6; // 如果等于0x06或者0x09,表示刷卡;否则是充值
protected final static byte TRANS_CSU_CPX = 9; // 如果等于0x06或者0x09,表示刷卡;否则是充值
@Override
public String parse(Tag tag) {
IsoDep isoDep = IsoDep.get(tag);
try {
isoDep.connect();
StringBuffer buffer = new StringBuffer();
if (isoDep.isConnected()) {
Log.d("h_bl", "isoDep.isConnected"); // 判断是否连接上
// 1.select PSF (1PAY.SYS.DDF01)
// 选择支付系统文件,它的名字是1PAY.SYS.DDF01。
byte[] DFN_PSE = {(byte) '1', (byte) 'P', (byte) 'A', (byte) 'Y', (byte) '.', (byte) 'S', (byte) 'Y', (byte) 'S', (byte) '.', (byte) 'D', (byte) 'D', (byte) 'F', (byte) '0', (byte) '1',};
isoDep.transceive(getSelectCommand(DFN_PSE));
// 2.选择公交卡应用的名称
byte[] DFN_SRV = {(byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x86, (byte) 0x98, (byte) 0x07, (byte) 0x01,};
isoDep.transceive(getSelectCommand(DFN_SRV));
// 3.读取余额
byte[] ReadMoney = {(byte) 0x80, // CLA Class
(byte) 0x5C, // INS Instruction
(byte) 0x00, // P1 Parameter 1
(byte) 0x02, // P2 Parameter 2
(byte) 0x04, // Le
};
byte[] Money = isoDep.transceive(ReadMoney);
if (Money != null && Money.length > 4) {
int cash = byteToInt(Money, 4);
float ba = cash / 100.0f;
buffer.append("余额:" + ba);
}
// 4.读取所有交易记录
byte[] ReadRecord = {(byte) 0x00, // CLA Class
(byte) 0xB2, // INS Instruction
(byte) 0x01, // P1 Parameter 1
(byte) 0xC5, // P2 Parameter 2
(byte) 0x00, // Le
};
byte[] Records = isoDep.transceive(ReadRecord);
// 处理Record
Log.d("h_bl", "总消费记录" + Records);
ArrayList ret = parseRecords(Records);
List retList = parseRecordsToStrings(ret);
buffer.append("n" + "消费记录如下:");
for (String string : retList) {
Log.d("h_bl", "消费记录" + string);
buffer.append("n" + string);
}
} else {
buffer.append("not connected");
}
return buffer.toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(isoDep);
}
}
private byte[] getSelectCommand(byte[] aid) {
final ByteBuffer cmd_pse = ByteBuffer.allocate(aid.length + 6);
cmd_pse.put((byte) 0x00) // CLA Class
.put((byte) 0xA4) // INS Instruction
.put((byte) 0x04) // P1 Parameter 1
.put((byte) 0x00) // P2 Parameter 2
.put((byte) aid.length) // Lc
.put(aid).put((byte) 0x00); // Le
return cmd_pse.array();
}
private ArrayList parseRecords(byte[] Records) {
int max = Records.length / 23;
Log.d("h_bl", "消费记录有" + max + "条");
ArrayList ret = new ArrayList();
for (int i = 0; i < max; i++) {
byte[] aRecord = new byte[23];
for (int j = 23 * i, k = 0; j < 23 * (i + 1); j++, k++) {
aRecord[k] = Records[j];
}
ret.add(aRecord);
}
for (byte[] bs : ret) {
Log.d("h_bl", "消费记录有byte[]" + bs); // 有数据。解析正确。
}
return ret;
}
private List parseRecordsToStrings(ArrayList... Records) {
List recordsList = new ArrayList();
for (ArrayList record : Records) {
if (record == null)
continue;
for (byte[] v : record) {
// StringBuilder r = new StringBuilder();
// int cash = Util.toInt(v, 5, 4);
// char t = (v[9] == TRANS_CSU || v[9] == TRANS_CSU_CPX) ? '-' : '+';
// r.append(String.format("%02X%02X.%02X.%02X %02X:%02X ", v[16], v[17], v[18], v[19], v[20], v[21], v[22]));
// r.append(" " + t).append(Util.toAmountString(cash / 100.0f));
// String aLog = r.toString();
// recordsList.add(aLog);
}
}
return recordsList;
}
// byteArray转化为int
private int byteToInt(byte[] b, int n) {
int ret = 0;
for (int i = 0; i < n; i++) {
ret = ret << 8;
ret |= b[i] & 0x00FF;
}
if (ret > 100000 || ret < -100000)
ret -= 0x80000000;
return ret;
}
}
5.NfcA
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import java.nio.charset.Charset;
public class NfcAReader extends CardReader {
@Override
public String parse(Tag tag) {
NfcA nfca = NfcA.get(tag);
try {
nfca.connect();
if (nfca.isConnected()) {//NTAG216的芯片
byte[] SELECT = {
(byte) 0x30,
(byte) 5 & 0x0ff,//0x05
};
byte[] response = nfca.transceive(SELECT);
nfca.close();
if (response != null) {
return new String(response, Charset.forName("utf-8"));
} else {
return "response is null";
}
} else {
return "not connected";
}
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}finally {
close(nfca);
}
}
}
6.NfcB
import android.nfc.Tag;
import android.nfc.tech.NfcB;
import android.widget.Toast;
import com.socsi.tools.nfccardreader.MainActivity;
import java.io.IOException;
public class NfcBReader extends CardReader {
@Override
public String parse(Tag tag) {
NfcB nfcb = NfcB.get(tag);
try {
nfcb.connect();
StringBuffer buffer = new StringBuffer();
if (nfcb.isConnected()) {//身份证已连接
System.out.println("已连接");
byte[] applicationData = nfcb.getApplicationData();
byte[] protocolInfo = nfcb.getProtocolInfo();
buffer.append("Applicationdata:").append(ByteArrayToHexString(applicationData));
buffer.append("nProtocolInfo:").append(ByteArrayToHexString(protocolInfo));
} else {
buffer.append("not connected");
}
return buffer.toString();
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(nfcb);
}
}
}
7.Felica
import android.nfc.Tag;
import android.nfc.tech.NfcF;
import android.util.Log;
public class NfcFReader extends CardReader {
@Override
public String parse(Tag tag) {
NfcF nfcf = NfcF.get(tag);
try {
nfcf.connect();
byte[] felicaIDm = new byte[]{0};
byte[] req = readWithoutEncryption(felicaIDm, 10);
byte[] res = nfcf.transceive(req);
return ByteArrayToHexString(res);
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}finally {
close(nfcf);
}
}
}
8.NfcV
import android.nfc.Tag;
import android.nfc.tech.NfcV;
import java.io.IOException;
import java.nio.charset.Charset;
public class NfcVReader extends CardReader {
@Override
public String parse(Tag tag) {
NfcV nfcV = NfcV.get(tag);
try {
nfcV.connect();
byte[] tagUid = tag.getId();
int blockAddress = 0;
int blocknum = 4;
byte[] cmd = new byte[]{
(byte) 0x22, // FLAGS
(byte) 0x23, // 20-READ_SINGLE_BLOCK,23-所有块
0, 0, 0, 0, 0, 0, 0, 0,
(byte) (blockAddress & 0x0ff), (byte) (blocknum - 1 & 0x0ff)
};
System.arraycopy(tagUid, 0, cmd, 2, tagUid.length);
byte[] response = nfcV.transceive(cmd);
if (response != null) {
return new String(response, Charset.forName("utf-8"));
} else {
return "respones is null";
}
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(nfcV);
}
}
}
9.NfcBarcode
import android.nfc.Tag;
import android.nfc.tech.NfcBarcode;
public class NfcBarcodeReader extends CardReader {
@Override
public String parse(Tag tag) {
NfcBarcode barcode = NfcBarcode.get(tag);
try {
barcode.connect();
byte[] bytes = barcode.getBarcode();
return ByteArrayToHexString(bytes);
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
} finally {
close(barcode);
}
}
}
主要的NFC类就这些,代码仅测试使用,如有错误请指正,谢谢!



