安卓 NFC 卡模拟
StackOverFlow:Android HCE: are there rules for AID?
主机卡模拟Demo
第一步
新建类CardEmulatorService 继承 HostApduService,实现方法
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras)
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
byte[] ret = null;
Log.d("cyb", "processCommandApdu commandApdu=" + Hex.toHexString(commandApdu));
Toast.makeText(getApplicationContext(), Hex.toHexString(commandApdu), Toast.LENGTH_SHORT).show();
String MF_NAME = "1PAY.SYS.DDF01";
byte[] selectMF = Hex.hexToBytes("00A404000E" + Hex.toHexString(PbocCmd.MF_Name) + "00");
Log.d("cyb", "processCommandApdu selectMF=" + Hex.toHexString(selectMF));
if(Arrays.equals(commandApdu, selectMF)){ // 选择MF
ret = Hex.hexToBytes("6F15840E315041592E5359532E4444463031A5038801019000");
}else if(Arrays.equals(commandApdu, Hex.hexToBytes("00A40000023F0100"))){ // 选择应用
ret = Hex.hexToBytes("6F088400A5049F0801029000");
}else if(Arrays.equals(commandApdu, Hex.hexToBytes("00A4000002000400"))){ // 选择文件
ret = Hex.hexToBytes("9000");
}else if(Arrays.equals(commandApdu, Hex.hexToBytes("00B0000000"))){ // 读文件
ret = Hex.hexToBytes("4F545142475535394352555245304D369000");
}
Log.d("cyb", "processCommandApdu ret=" + Hex.toHexString(ret));
return ret;
}
第二步
在res/xml 文件夹新建aid_list.xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/service_name"
android:requireDeviceUnlock="false">
<aid-group android:description="@string/card_title" android:category="other">
<!--应用名称 1PAY.SYS.DDF01 对应的二进制-->
<aid-filter android:name="315041592E5359532E4444463031"/>
</aid-group>
</host-apdu-service>
第三步
在AndroidManifest.xml中配置Service
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<uses-feature
android:name="android.hardware.nfc.hce"
android:required="true" />
<!-- Service for handling communication with NFC terminal. -->
<service
android:name=".CardEmulatorService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<!-- Intent filter indicating that we support card emulation. -->
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- Required XML configuration file, listing the AIDs that we are emulating cards
for. This defines what protocols our card emulation service supports. -->
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/aid_list" />
</service>
读卡器代码
println("++++++++++++++ start ++++++++++++++++");
println("开始读文件...");
isoDep.connect();
Log.d("cyb", "Hex.toHexString(PbocCmd.MF_Name)=" + Hex.toHexString(PbocCmd.MF_Name));
// byte[] select_mf = PbocCmd.selectByName(isoDep, PbocCmd.MF_Name);
byte[] select_mf = PbocCmd.selectByName(isoDep, PbocCmd.MF_Name);
println("选择MF返回值=" + Hex.toHexString(select_mf));
if (IsoDepUtils.isNoError(select_mf)) {
// 选择应用
byte[] appId = {0x3F, 0x01};
byte[] response = PbocCmd.selectById(isoDep, appId);
if (IsoDepUtils.isNoError(response)) {
println("选择文件=" + Hex.toHexString(appId));
println("选择文件返回值=" + Hex.toHexString(response));
println("卡文件名称=" + new SelectResult(response).getName());
byte[] fileId = {0x00, 0x04};
// 选择文件
byte[] response_f = PbocCmd.selectById(isoDep, fileId);
if (IsoDepUtils.isNoError(response_f)) {
println("选择文件=" + Hex.toHexString(fileId));
println("选择文件返回值=" + Hex.toHexString(response_f));
println("卡文件名称=" + new SelectResult(response_f).getName());
byte[] read = PbocCmd.readBinary(isoDep);
if(IsoDepUtils.isNoError(read)){
println(Hex.toHexString(read));
println(new String(read, "utf-8"));
}
}
}
}
println("++++++++++++++ end ++++++++++++++++\n\n\n\n\n");
isoDep.close();