我问过这个问题here但是它被标记为重复 - 但是我没有在评论中找到任何有用的解决方案。 在这里,我再次询问更多细节......
我正在HCE上进行示例应用(PoC),并根据Android用户指南使用HostApduService。我创建了两个应用程序 1)ReaderApp - 充当读卡器 2)HCEApp - 模拟卡
在HCEApp中,我创建了一个扩展HostApduService
的类'MyService'public class MyService extends HostApduService {
private int messageCounter;
private final String TAG = "MyService";
Intent mIntent;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
mIntent = new Intent(this, MyActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
}
/**
* returned bytes will be sent as response. This method runs in Main thread
* so return ASAP.
*/
@Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
if (selectAidApdu(apdu)) {
Log.i(TAG, "Application selected");
return getWelcomeMessage();
} else {
Log.i(TAG, "Received: " + new String(apdu));
return getNextMessage();
}
}
private byte[] getWelcomeMessage() {
return "Hello Desktop!".getBytes();
}
private byte[] getNextMessage() {
return ("Message from android: " + messageCounter++).getBytes();
}
private boolean selectAidApdu(byte[] apdu) {
if (apdu != null) {
for (byte b : apdu) {
System.out.printf("0x%02X", b);
}
}
return apdu.length >= 2 && apdu[0] == (byte) 0
&& apdu[1] == (byte) 0xa4;
}
@Override
public void onDeactivated(int reason) {
Log.i(TAG, "Deactivated: " + reason);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
正如您在 onCreate()中看到的那样,我正在启动 MyActivity ,用户可以输入一些信息,需要将其发送回 MyService 。
我认为我不能使用绑定,因为' onBind()'在HostApduService中声明为final,如下所示
@Override
public final IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
如果我正确地理解它,请告诉我。感谢任何帮助。
感谢
iuq
答案 0 :(得分:1)
你是否可以使用onBind我不知道,但我最近使用的是BroadcastReceiver,我必须从中启动一个服务。根据文档,您无法从BroadcastReceiver bind
提供服务,您只能start
它。稍后我需要从我的BroadcastReceiver向服务发送一些数据,由于我无法使用绑定器技术,我必须找到一种与服务通信的不同方式,就像你不喜欢的情况一样。 ; t引用它。
我做了一些研究,但找不到任何解决方案,但后来我记得你可以通过startService(intent)调用传递intent数据。我在onCreate中开始我的服务工作,因为onCreate仅在创建服务时调用一次。
在您的活动中
public void sendDataToService(){
Intent intent = new Intent(context, MyService.class);
intent.putExtra("message", SOME_DATA);
context.startService(intent);
}
在您的服务中
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Check if intent has extras
if(intent.getExtras() != null){
// Get message
int message = intent.getExtras().getInt("message");
}
return START_NOT_STICKY;
}
这可能是某种黑客行为,因为" startService"听起来不应该用它来发送消息,我不确定这是否正是你所需要的,但它对我有用,所以我希望它适合你。干杯
编辑:BTW。我用它来告诉LocationService特定活动不再需要位置更新。
答案 1 :(得分:1)
我最终采取了不同的方法来解决同样的问题。当我绑定到HostApduService
子类时,我抓住了Messenger
HostApduService
实现返回的onBind
接口的句柄。
这是一些示例代码。这将全部放在您的活动实施中(在此处将其称为MyActivity
,与MyHostApduServiceSubclass
进行通信)。这是MyActivity
需要包含的内容:
private Messenger mAPDUMessenger;
...
@Override
protected void onStart() {
super.onStart();
Context context = getApplicationContext();
Intent apduIntent = new Intent(montext, ContactlessApduService.class);
context.bindService(apduIntent, mAPDUConnection, Context.BIND_AUTO_CREATE);
}
...
private ServiceConnection mAPDUConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// The HostApduService has a final override on the onBind() service method that returns
// an IMessageHandler interface that we can grab and use to send messages back to the
// terminal - would be better to get a handle to the running instance of the service so
// that we could make use of the HostApduService#sendResponseApdu public method
mAPDUMessenger = new Messenger(service);
registerAPDUMessengerIntentFilters();
// ^ This method sets up my handlers for local broadcast messages my BroadcastReceiver processes.
}
...
}
...
private void registerAPDUMessengerIntentFilters() {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(MyActivity.this);
IntentFilter intentFilter = new IntentFilter(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT);
lbm.registerReceiver(apduMessageBroadcastReceiver, intentFilter);
}
...
BroadcastReceiver apduMessageBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT)) {
sendResponseApdu(MyActivity.PPSE_APDU_SELECT_RESPONSE_BYTES);
}
}
};
...
public final void sendResponseApdu(byte[] responseApdu) {
Message responseMsg = Message.obtain(null, MyHostApduServiceSubclass.MSG_RESPONSE_APDU);
// ^ Note here that because MSG_RESPONSE_APDU is the message type
// defined in the abstract HostApduService class, I had to override
// the definition in my subclass to expose it for use from MyActivity.
// Same with the KEY_DATA constant value below.
Bundle dataBundle = new Bundle();
dataBundle.putByteArray(MyHostApduServiceSubclass.KEY_DATA, responseApdu);
responseMsg.setData(dataBundle);
try {
mAPDUMessenger.send(responseMsg);
} catch (RemoteException e) {
// Do something with the failed message
}
}
然后你的HostApduService
子类只需要向你的活动发送广播,指示收到了什么APDU命令。以下是MyHostApduServiceSubclass
中需要包含的内容:
public static final String ACTION_PPSE_APDU_SELECT = "ACTION_PPSE_APDU_SELECT";
// Abstract super class constant overrides
public static final String KEY_DATA = "data";
public static final int MSG_RESPONSE_APDU = 1;
@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
Context context = getApplicationContext();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
if (Arrays.equals(MyHostApduServiceSubclass.PPSE_APDU_SELECT_BYTES, commandApdu)) {
lbm.sendBroadcast(new Intent(ACTION_PPSE_APDU_SELECT));
}
return null;
// ^ Note the need to return null so that the other end waits for the
// activity to send the response via the Messenger handle
}