我目前正在为我的Galaxy s4开发HCE实现。我有一个支持7816-4的Omnikey 5321-cl阅读器。我的android类看起来像这样:
public class NfcHceService extends HostApduService{
private int counter = 0;
@Override
public void onStart(android.content.Intent intent, int startId)
{
new Thread(new Runnable() {
@Override
public void run()
{
while (true)
{
Log.d("HCE", String.valueOf(counter));
counter++;
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}).run();
}
@Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras)
{
byte[] response = null;
if (apdu[2] == 0xA4)
{
// return selecting applet
response = new byte[] { (byte) 0x90, 0x00 };
}
return response;
}
@Override
public void onDeactivated(int reason)
{
android.os.Debug.waitForDebugger();
Log.d("HCE", "onDeactivated");
}
}
我的读者课程看起来像这样:
private static final byte[] CLA_INS_P1_P2 = { 0x00, (byte) 0xA4, 0x04, 0x00 };
private static final byte[] AID_ANDROID = { (byte) 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
private static byte[] createSelectAidApdu(byte[] aid)
{
byte[] result = new byte[6 + aid.length];
System.arraycopy(CLA_INS_P1_P2, 0, result, 0, CLA_INS_P1_P2.length);
result[4] = (byte) (aid.length);
System.arraycopy(aid, 0, result, 5, aid.length);
result[result.length - 1] = 10;
return result;
}
public static void Create_MF() throws CardException
{
// --Variable declaration
Card card = null;
ResponseAPDU answer = null;
// ---------------------------------------------
// --1--Establish connection with the smart card
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
// Use the first terminal
CardTerminal terminal = terminals.get(1);
// Connect with the card
card = terminal.connect("*");
CardChannel channel = card.getBasicChannel();
// ---------------------------------------------
byte[] selectAidApdu = createSelectAidApdu(AID_ANDROID);
answer = channel.transmit(new CommandAPDU(selectAidApdu));
我的hce服务的AID是F0010203040506。
我现在的问题是我在Android设备上获得了正确的选择APDU,如下所示:
> RX: Type 4 Tag Command (13 bytes)
CLA:0x00
INS:0xA4(Select)
P1:0x04(Name)
P2:0x00(First or Only)
LC:0x07(7)
Data(7 bytes)
00: f0 01 02 03 04 05 06
Le:0x0A(10)
但我得到了回复代码6A82。据我了解,这意味着该设备无法找到该服务。但我不明白为什么。 有人可以帮忙吗?
清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hce"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service
android:name=".NfcHceService"
android:exported="false"
android:permission="android.permission.BIND_NFC_SERVICE" >
<intent-filter>
<action android:name="android.nfc.cardemulation.HOST_APDU_SERVICE" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/hce_service" />
</service>
</application>
和xml文件:
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/my_app_hce_service" >
<aid-group
android:category="other"
android:description="@string/my_app_aid_group" >
<aid-filter android:name="F0010203040506" />
</aid-group></host-apdu-service>
更新
public static void Create_MF() throws CardException
{
// --Variable declaration
Card card = null;
ResponseAPDU answer = null;
// ---------------------------------------------
// --1--Establish connection with the smart card
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
// Use the first terminal
CardTerminal terminal = terminals.get(1);
// Connect with the card
card = terminal.connect("*");
CardChannel channel = card.getBasicChannel();
// ---------------------------------------------
byte[] selectAidApdu = { 0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; // createSelectAidApdu(AID_ANDROID);
answer = channel.transmit(new CommandAPDU(selectAidApdu));}
更新2
我尝试实现isDefaultServiceForAid()。但我不确定我是否正确使用它,如果它做我想要的。
CardEmulation card = CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(this));
ComponentName comp = new ComponentName(getApplicationContext(), NfcHceService.class);
boolean tmp = card.isDefaultServiceForAid(comp, "F0010203040506");
它真的测试我的服务的AID还是其他的东西?我想测试我的服务是否可以使用我在我的清单中声明的hce_service.xml中指定的AID访问。
答案 0 :(得分:1)
错误6A82
表示file not found
。
在这种情况下,这意味着您选择的AID不存在。
这可能是由于您选择的AID不匹配所致。 f0 01 02 03 04 05 06
和AndroidManifest.xml中指定的AID
ISO 7816参考here
<强>更新强>
从检查更新的代码开始,看起来您正在向APDU的末尾添加另一个字节,即0x10
。尝试从函数createSelectAidApdu()
result[result.length - 1] = 10;
另外,我不确定为什么将最后一个字节设置为10,即十进制等于16。请注意,最后一个字节通常用于指定目标设备预期/请求的数据量。并不总是需要,这是选择应用程序命令的情况。
答案 1 :(得分:0)
我认为AID选择没问题。如果Android没有AID的应用程序,它什么都不做,甚至没有收发错误代码。
我怀疑问题是应用程序返回null作为消息,因此Android可能会发回错误代码。
以下if语句测试为负,因为apdu [2]实际上是(字节)0x04。 apdu [1]将是(byte)0xA4。
byte[] response = null;
if (apdu[2] == 0xA4)
{
// return selecting applet
response = new byte[] { (byte) 0x90, 0x00 };
}
return response;
答案 2 :(得分:0)
我刚刚玩过类似的事情。
我注意到你的intent-filter指定了一个“android.nfc.cardemulation.HOST_APDU_SERVICE”的动作,但正确的动作似乎是“android.nfc.cardemulation.action.HOST_APDU_SERVICE” - 详见http://developer.android.com/guide/topics/connectivity/nfc/hce.html
在intent-filter中使用此操作,我成功地为我的AID调用了我的Android服务。
祝你好运!答案 3 :(得分:0)
我遇到了类似的问题 - 我的AID在两端都是正确的,但仍然无法找到服务。
official HCE page包含以下代码段:
<service android:name=".MyHostApduService" android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
</intent-filter>
<meta-data android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apduservice"/>
我注意到<intent-filter>
没有<category>
标记。我添加了这个,突然间我的服务被找到了!见下文:
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
<!-- category required!!! this was not included in official android HCE documentation -->
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>