我正在使用 Galaxy A5、Android 5.0.2、SDK 21 和 Android Studio 1.1.0
Android 作为 PCD,Mifare DESFire 作为 PICC。本机 DESFire APDU 帧不起作用,但 ISO 7816-4 起作用。
示例:
MIFARE DESFire SelectApplication,AID 等于
000000h
(PICC 级别)
90 5a 00 00 03 00 00 00 00
。91 00
.68 00
。
文档参考:AN11004.pdf(第33页)
void SelectApp() {
_isoDep.connect();
byte[] reqSelectApp = new byte[]{(byte) 0x90, (byte) 0x5A, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
byte[] resSelectApp = _isoDep.transceive(reqSelectApp);
_responseTextView.append(String.format("reqSelectApp: %s length:%d\n", BytesToHexStr(reqSelectApp), reqSelectApp.length));
_responseTextView.append(String.format("resSelectApp: %s length:%d\n", BytesToHexStr(resSelectApp), resSelectApp.length));
}
String BytesToHexStr(byte[] items) {
StringBuilder builder = new StringBuilder();
for (byte item : items) {
builder.append(String.format("%02X", item));
}
return builder.toString();
}
信息
NDEF
额外
科技
兼容 ISO/IEC 14443-2(A 型)
Android技术信息: 标签说明:
Android 中不存在 MIFARE Classic 支持
详细协议信息:
虽然 ATQA/SAK 看起来好像该卡是 DESFire(这就是为什么我的 NFC TagInfo 应用程序检测到它,但应该给您一个读取错误或指示 DESFire 主应用程序的可用性),其余参数(特别是历史字节)清楚地表明这不是 DESFire 卡。
因此,不要期望卡响应 DESFire 命令(本机或包装本机)。这也与卡的行为相匹配,因为它响应
68 00
(这表明不支持 CLA 字节的编码(在您的情况下为 0x90
)。
我找到了解决办法。所以,如果有人遇到类似的问题 代码是这样的。顺便说一句,关键在于
setTransceive
方法!?!?!!!
MyApp.TapLinx.getCustomModules().setTransceive(new MyCardApduHandler(new MyCardReader(terminal)));
desFire = DESFireFactory.getInstance().getDESFireEV2(MyApp.TapLinx.getCustomModules());
desFire.getReader().connect();
// Read UID.
byte[] uid = desFire.getUID();
// To do anything further, and unlike Android , you have to set Command Set to ISO.
desFire.setCommandSet(IDESFireEV1.CommandSet.ISO);
// Select ID app...
desFire.selectApplication(0);
// ...and so on
MyCardApduHandler
是准系统:
public class MyCardApduHandler implements IApduHandler {
IReader reader;
public SCardApduHandler(IReader reader) {
this.reader = reader;
}
@Override
public byte[] apduExchange(byte[] bytes) {
return reader.transceive(bytes);
}
@Override
public IReader getReader() {
return reader;
}
}
MyCardReader
如下:
public class MyCardReader implements IReader {
CardTerminal mTerminal;
CardChannel mKanal;
Card mJavaCard;
ProtocolDetails mProtokol;
boolean isConnected = false;
public SCardReader(CardTerminal terminal) {
mTerminal = terminal;
}
@Override
public byte[] transceive(byte[] bytes) {
ResponseAPDU res;
try {
res = mKanal.transmit(new CommandAPDU(bytes));
} catch (CardException e) {
throw new NxpNfcLibException(e, e.getMessage());
}
return res.getBytes();
}
@Override
public void connect() {
if (!isConnected) {
try {
mTerminal.waitForCardPresent(0);
mJavaCard = mTerminal.connect("*");
mKanal = mJavaCard.getBasicChannel();
mProtokol = new ProtocolDetails();
mProtokol.uid = Commands.uid(mKanal);
// TODO: Other components of the protocol.
isConnected = true;
} catch (CardException e) {
throw new NxpNfcLibException(e, e.getMessage());
}
}
}
@Override
public void close() {
if (isConnected) {
try {
if (mKanal.getChannelNumber() != 0) mKanal.close();
mJavaCard.disconnect(false);
isConnected = false;
} catch (Exception e) {
throw new NxpNfcLibException(e, e.getMessage());
}
}
}
@Override
public boolean isConnected() {
return isConnected;
}
@Override
public void setTimeout(long l) {
throw new NotSupportedException("SCardReader: metoda setTimeout nije podržana. ");
}
@Override
public long getTimeout() {
throw new NotSupportedException("SCardReader: metoda getTimeout nije podržana. ");
}
@Override
public ProtocolDetails getProtocolDetails() {
return mProtokol;
}
}
而且,
Commands.uid(mKanal)
是通过原始APDU实现的:
public static byte[] uid(CardChannel kanal) throws CardException, RuntimeException {
CommandAPDU cmd = new CommandAPDU(new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 });
ResponseAPDU res = kanal.transmit(cmd);
if (res.getSW1() != 0x90 && res.getSW2() != 0x00) throw new RuntimeException(String.format("uid: greška SW1 SW2 = %02X %02X", res.getSW1(), res.getSW2()));
return res.getData();
}