使用JAVA智能卡API读取NFC标记在MAC OS上不起作用
我正在开发一个从NFC阅读器(ACR122U-A9)设备读取NFC标签UID的应用程序。 我使用JAVA和javax.smartcardio API检测NFC阅读器并读取NFC标记 应用程序的功能是在NFC阅读器设备与PC连接或断开连接时显示通知。然后,如果设备已连接且显示NFC标签,则显示显示NFC标签的通知。 我试图找到基于事件的api来实现上述功能,但找不到,所以我使用Java定时器和轮询来实现NFC阅读器设备和NFC标记 下面是用于轮询NFC设备和标记的示例JAVA代码使用JAVA智能卡API读取NFC标记在MAC OS上不起作用,java,nfc,smartcard,smartcard-reader,Java,Nfc,Smartcard,Smartcard Reader,我正在开发一个从NFC阅读器(ACR122U-A9)设备读取NFC标签UID的应用程序。 我使用JAVA和javax.smartcardio API检测NFC阅读器并读取NFC标记 应用程序的功能是在NFC阅读器设备与PC连接或断开连接时显示通知。然后,如果设备已连接且显示NFC标签,则显示显示NFC标签的通知。 我试图找到基于事件的api来实现上述功能,但找不到,所以我使用Java定时器和轮询来实现NFC阅读器设备和NFC标记 下面是用于轮询NFC设备和标记的示例JAVA代码 import j
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
/**
*
* @author sa
*/
public class NFC_Test {
/**
* @param args the command line arguments
*/
static Timer timer;
public static void main(String[] args) {
try {
timer = new Timer(); //At this line a new Thread will be created
timer.scheduleAtFixedRate(new NFC_Test.MyTask(), 0, 1000);
} catch (Exception ex) {
Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
static class MyTask extends TimerTask {
public void run() {
///////////////////This fix applied after reading thread at http://stackoverflow.com/a/16987873/1411888
try {
Class pcscterminal =
Class.forName("sun.security.smartcardio.PCSCTerminals");
Field contextId = pcscterminal.getDeclaredField("contextId");
contextId.setAccessible(true);
if (contextId.getLong(pcscterminal) != 0L) {
Class pcsc =
Class.forName("sun.security.smartcardio.PCSC");
Method SCardEstablishContext = pcsc.getDeclaredMethod(
"SCardEstablishContext", new Class[]{Integer.TYPE});
SCardEstablishContext.setAccessible(true);
Field SCARD_SCOPE_USER =
pcsc.getDeclaredField("SCARD_SCOPE_USER");
SCARD_SCOPE_USER.setAccessible(true);
long newId = ((Long) SCardEstablishContext.invoke(pcsc, new Object[]{Integer.valueOf(SCARD_SCOPE_USER.getInt(pcsc))})).longValue();
contextId.setLong(pcscterminal, newId);
}
} catch (Exception ex) {
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
TerminalFactory factory = null;
List<CardTerminal> terminals = null;
try {
factory = TerminalFactory.getDefault();
terminals = factory.terminals().list();
} catch (Exception ex) { //
Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE,null, ex);
}
if (factory != null && factory.terminals() != null && terminals
!= null && terminals.size() > 0) {
try {
CardTerminal terminal = terminals.get(0);
if (terminal != null) {
System.out.println(terminal);
if (terminal.isCardPresent()) {
System.out.println("Card");
} else {
System.out.println("No Card");
}
} else {
System.out.println("No terminal");
}
terminal = null;
} catch (Exception e) {
Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE,null, e);
}
factory = null;
terminals = null;
Runtime.getRuntime().gc();
} else {
System.out.println("No terminal");
}
}
}
}
我在网上搜索,找不到任何关于上述内存错误的信息。此外,我还包含了内存管理代码,当对象在计时器中使用时,通过为其分配空值来释放该对象
我曾参考过我相信这是我在OS X上的64位Java上使用libj2pcsc.dylib查找bug时遇到的错误之一。另请参见和我的。基本上,问题在于,
DWORD*
应该是指向OS X上32位数字的指针,但Sun的库假设它是指向64位数字的指针。然后它取消对该值的引用,并尝试对该大小的缓冲区进行malloc,该缓冲区可能包含高32位的垃圾。请参阅中的Java\u sun\u security\u smartcardio\u PCSC\u SCardListReaders
可能的解决办法:
- 对
(间歇性崩溃)的调用要非常保守,不要信任终端.list()
、终端.isCardPresent()
或终端.waitForChange(long)
的结果。我的同事意识到他可以使用反射调用CardTerminal.waitForCard(boolean,long)
来获得正确的结果。这是我们过去常做的事。非常痛苦李>TerminalImpl.SCardGetStatusChange(long,long,int[],String[])
- 修复libj2pcsc.dylib的头文件并重新编译OpenJDK。这就是我们公司现在所做的
- 切换到不同的
实现。我知道两个:我自己的和我的。我还没有在NFC卡上尝试过我自己的库,但是我欢迎任何错误报告和补丁javax.smartcardio
java(921,0x10b0c3000) malloc: *** mmap(size=140350941302784) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Java Result: 139