我正在开发一个应用程序来从 NFC 阅读器 (ACR122U-A9) 设备读取 NFC 标签 UID。我使用 JAVA 和 javax.smartcardio API 来检测 NFC 读取器和读取 NFC 标签。
该应用程序的功能是在 NFC 阅读器设备与 PC 连接或断开连接时显示通知。然后,如果设备已连接并且出现 NFC 标签,则显示出现 NFC 标签的通知。我试图找到基于事件的 api 来实现上述功能,但我找不到,所以我对 NFC 阅读器设备和 NFC 标签使用了 Java 计时器和轮询。
以下是用于轮询 NFC 设备和标签的示例 JAVA 代码。
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");
}
}
}
}
上面的代码在 Windows 操作系统中运行良好,但是当我在 MAC 操作系统上运行它时,应用程序完美地运行了 5-10 秒,但随后它突然崩溃并出现以下内存错误。
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
我在互联网上搜索并找不到有关上述内存错误的任何信息。此外,我还包含了内存管理代码,以便在计时器中使用该对象时通过为其分配 NULL 值来释放该对象。
我使用http://ludovicrousseau.blogspot.com/2010/06/pcsc-sample-in-java.html供参考