public abstract class HostApduService
extends Service
java.lang.Object | ||||
↳ | android.content.Context | |||
↳ | android.content.ContextWrapper | |||
↳ | android.app.Service | |||
↳ | android.nfc.cardemulation.HostApduService |
HostApduService是一个便利的 Service
类,可以扩展为模拟Android服务组件内的NFC卡。
该类仿真的卡基于NFC-Forum ISO-DEP协议(基于ISO / IEC 14443-4),并支持ISO / IEC 7816-4规范中定义的处理命令应用协议数据单元(APDU)。
当远程NFC设备想要与您的服务通话时,它会发送ISO / IEC 7816-4规范中定义的所谓“SELECT AID”APDU。 AID是ISO / IEC 7816-4中定义的应用程序标识符。
AID的注册程序在ISO / IEC 7816-5规范中定义。 如果您不想注册AID,则可以在专有范围内自由使用AID:第一个字节的第8-5位必须各设置为“1”。 例如,“0xF00102030405”是专有的AID。 如果确实使用专有AID,则建议选择至少6个字节的AID,以降低与可能使用专有AID的其他应用程序发生冲突的风险。
在某些情况下,服务可能需要注册多个AID来实现某个应用程序,并且需要确定它是所有这些AID的默认处理程序(而不是组中的某些AID转到其他服务)。
一个AID组是应该被OS视为一起归属的AID列表。 对于AID组中的所有AID,操作系统将保证以下之一:
每个AID组都可以与一个类别关联。 这允许Android OS对服务进行分类,并允许用户在类别级别而不是AID级别设置默认值。
您可以使用 isDefaultServiceForCategory(android.content.ComponentName, String)
来确定您的服务是否是某个类别的默认处理程序。
在这个版本的平台中,唯一已知的类别是CATEGORY_PAYMENT
和CATEGORY_OTHER
。 没有类别的AID组或者当前平台版本无法识别的类别将自动分组到CATEGORY_OTHER
类别中。
为了告知平台哪些AIDs组被这个服务请求,一个SERVICE_META_DATA
条目必须包含在服务声明中。 HostApduService清单声明的示例如下所示:
<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_ervice" android:resource="@xml/apduservice"/> </service>This meta-data tag points to an apduservice.xml file. An example of this file with a single AID group declaration is shown below:
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/servicedesc" android:requireDeviceUnlock="false"> <aid-group android:description="@string/aiddescription" android:category="other"> <aid-filter android:name="F0010203040506"/> <aid-filter android:name="F0394148148100"/> </aid-group> </host-apdu-service>
<host-apdu-service>
需要包含<android:description>
属性,其中包含可能在UI中显示的用户友好的服务说明。 可以使用<requireDeviceUnlock>
属性指定在调用此服务来处理APDU之前必须先解锁设备。
<host-apdu-service>
必须包含一个或多个<aid-group>
标签。 每个<aid-group>
必须包含一个或多个<aid-filter>
标签,每个标签包含一个AID。 AID必须以十六进制格式指定,并且包含偶数个字符。
getSelectionModeForCategory(String)
.
一旦平台将“SELECT AID”命令APDU解析为特定服务组件,“SELECT AID”命令APDU和所有后续命令APDU将通过 processCommandApdu(byte[], Bundle)
发送到该服务,直到:
onDeactivated(int)
.
使用此类需要 FEATURE_NFC_HOST_CARD_EMULATION
在设备上。
Constants |
|
---|---|
int |
DEACTIVATION_DESELECTED 原因为 |
int |
DEACTIVATION_LINK_LOSS 原因为 |
String |
SERVICE_INTERFACE 必须声明为由服务处理的 |
String |
SERVICE_META_DATA 包含有关此服务的更多信息的元数据元素的名称。 |
Inherited constants |
---|
From class android.app.Service
|
From class android.content.Context
|
From interface android.content.ComponentCallbacks2
|
Public constructors |
|
---|---|
HostApduService() |
Public methods |
|
---|---|
final void |
notifyUnhandled() 调用此方法允许服务告诉操作系统它将无法完成此事务 - 例如,因为它需要当时不存在的数据连接。 |
final IBinder |
onBind(Intent intent) 将通信信道返回给服务。 |
abstract void |
onDeactivated(int reason) 这种方法将在两种可能的情况下被调用: |
abstract byte[] |
processCommandApdu(byte[] commandApdu, Bundle extras) 当从远程设备接收到命令APDU时,将调用此方法。 |
final void |
sendResponseApdu(byte[] responseApdu) 将响应APDU发送回远程设备。 |
Inherited methods |
|
---|---|
From class android.app.Service
|
|
From class android.content.ContextWrapper
|
|
From class android.content.Context
|
|
From class java.lang.Object
|
|
From interface android.content.ComponentCallbacks2
|
|
From interface android.content.ComponentCallbacks
|
int DEACTIVATION_DESELECTED
原因为 onDeactivated(int)
。
指示取消激活是由于选择了不同的AID(隐式取消选择当前在逻辑通道上激活的AID)。
请注意,这个下一个AID仍然可以解析为此服务,在这种情况下 processCommandApdu(byte[], Bundle)
将再次被调用。
常数值:1(0x00000001)
int DEACTIVATION_LINK_LOSS
原因为onDeactivated(int)
。 表示取消激活是由于NFC链路丢失。
常量值:0(0x00000000)
String SERVICE_INTERFACE
Intent
必须声明为由服务处理的操作。
常量值:“android.nfc.cardemulation.action.HOST_APDU_SERVICE”
String SERVICE_META_DATA
包含有关此服务的更多信息的元数据元素的名称。
常量值:“android.nfc.cardemulation.host_apdu_service”
void notifyUnhandled ()
调用此方法允许服务告诉操作系统它将无法完成此事务 - 例如,因为它需要当时不存在的数据连接。 操作系统可以使用该指示为用户提供可以处理所选择的最后AID的替代应用程序的列表。 如果用户从列表中选择应用程序,则该操作本身不会导致默认值被更改; 所选的应用程序将只为下一次点击而被调用。 如果没有其他应用程序可以处理此事务,则操作系统将显示一个错误对话框,指出您的服务无法完成该事务。
注意:可以在第一个 processCommandApdu(byte[], Bundle)
调用和 onDeactivated(int)
调用之间的任何地方调用此方法。
IBinder onBind (Intent intent)
将通信信道返回给服务。 如果客户端无法绑定到服务,可能会返回null。 返回的IBinder
通常用于一个复杂的接口described using aidl 。
请注意,与其他应用程序组件不同,此处返回的IBinder接口调用可能不会发生在进程的主线程上 。 有关主线程的更多信息可以在Processes and Threads中找到。
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service, as given to Context.bindService . Note that any extras that were included with the Intent at that point will not be seen here. |
Returns | |
---|---|
IBinder |
Return an IBinder through which clients can call on to the service. |
void onDeactivated (int reason)
这种方法将在两种可能的情况下被调用:
Parameters | |
---|---|
reason |
int : Either DEACTIVATION_LINK_LOSS or DEACTIVATION_DESELECTED |
byte[] processCommandApdu (byte[] commandApdu, Bundle extras)
当从远程设备接收到命令APDU时,将调用此方法。 响应APDU可以通过在此方法中返回字节数组直接提供。 请注意,一般来说,响应APDU必须尽可能快地发送,因为当调用此方法时,用户可能将他的设备通过NFC读取器。
如果有多个服务在其元数据条目中注册了相同的AID,则只有在用户明确选择了服务时才会被调用,无论是默认还是仅用于下一次点击。
此方法在您的应用程序的主线程上运行。 如果您无法立即返回响应APDU,请返回null并稍后使用sendResponseApdu(byte[])
方法。
Parameters | |
---|---|
commandApdu |
byte : The APDU that was received from the remote device |
extras |
Bundle : A bundle containing extra data. May be null. |
Returns | |
---|---|
byte[] |
a byte-array containing the response APDU, or null if no response APDU can be sent at this point. |
void sendResponseApdu (byte[] responseApdu)
将响应APDU发送回远程设备。
注意:这个方法可以从任何线程调用并且不会被阻塞。
Parameters | |
---|---|
responseApdu |
byte : A byte-array containing the reponse APDU. |