Google開始放出HCE的支援後,掀起了巨大的反響。 擺脫了SWP-SIM對電訊廠商的依賴,擺脫了eSE對手機廠商的依賴,其對於產業生態的影響不言而喻。網上基於HCE的前景和應用討論的不亦樂乎,但技術層面的資料卻乏善可陳。現我們就通過一個具體的實現來揭秘HCE,同時給出一個技術層面的理解。
首先,需要的環境:
一個支援Android 4.4.2 SDK的開發環境:可以是eclipse外掛程式或者ADT工具。可以到google的網站上去下載:http://developer.android.com/sdk/index.html 。 (此處攻略漫天飛,搞不定的同學自己搜)
一個支援HCE的測試手機:目前可以確定使用了NXP PN547作為CLF的NFC手機已經打通了HCE。市面上可見的目前有Sony Xperia Z2 和 Samsung Galaxy S5。本次測試使用Xperia Z2。(CLF晶片不包含在手機發布的資料裡,最終確定Z2的CLF晶片還是依靠網上流出的拆機圖)
一份參考資料:http://developer.android.com/guide/topics/connectivity/nfc/hce.html 裡面寫的非常細緻,我摘要一下:
1. HCE工作在ISO 7816-4也就是ISO-DEP層面。(想類比Mifare標籤的同學洗洗睡吧)
2.命令的派發是基於系統接管SelectbyName指令,以及HCE服務註冊到系統的AID來完成的。HCE的派發高於SE,不支援logic channel,也不支援GP的AID部分匹配。
3.HCE以Android服務的方式啟動,通過介面函數響應APDU。可以配置多個AID(AID Group),可以配置類型--支付類或者其它類,該類型用於AID衝突時系統的策略。支付類是通過設定預設應用,而其它類則是UI彈出選擇提示。
4.螢幕關閉的狀態下HCE不可用,螢幕鎖定狀態下HCE可以選擇支援,也可以選擇提示使用者解鎖再支援。
5.在終端只有HCE沒有SE的情況下,ISO 14443-3的非接參數由Android接管,UID使用隨機數,請勿使用HCE實現任何基於UID的ID卡。
6.Open Mobile API並不能向訪問SE一樣訪問HCE。
然後,我們開始編碼了,首先實現Service:
package com.broadthinking.hcedemo;import android.nfc.cardemulation.HostApduService;import android.os.Bundle;import android.util.Log;public class MyHostApduService extends HostApduService {private int messageCounter = 0;@Overridepublic byte[] processCommandApdu(byte[] apdu, Bundle extras) {if (selectAidApdu(apdu)) {Log.i("HCEDEMO", "Application selected");return getWelcomeMessage();}else {Log.i("HCEDEMO", "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) {return apdu.length >= 2 && apdu[0] == (byte)0 && apdu[1] == (byte)0xa4;}@Overridepublic void onDeactivated(int reason) {Log.i("HCEDEMO", "Deactivated: " + reason);}}
其中:processCommandApdu用以重載傳入接收到的CAPDU,函數返回值作為RAPDU。但此介面的調用使用程式主棧,如果處理時間較長(比如雲端式的處理),則需要啟動處理線程,並返回null,並在處理線程結束後主動調用sendResponseApdu來發送RAPDU。
繼續配置Android環境 AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.broadthinking.hcedemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.NFC" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.broadthinking.hcedemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <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" /> </service> </application></manifest>
幾個關鍵點:
使用者授權:android.permission.NFC
服務授權:android.permission.BIND_NFC_SERVICE
exported:必須為true
initent-filter:android.nfc.cardemulation.action.HOST_APDU_SERVICE
meta-data:指定服務的細節,見apduservice.xml
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="servicedesc" android:requireDeviceUnlock="false" > <aid-group android:category="other" android:description="aiddescription" > <aid-filter android:name="F0010203040506" /> <aid-filter android:name="F0394148148100" /> </aid-group></host-apdu-service>
幾個關鍵點:
可以通過指定多個aid-filter,來註冊多個AID。
category可以指定為 other 或者 payment。
requireDeviceUnlock為false的時候,可以在鎖屏狀態下完成處理,為true的時候,則會要求使用者解鎖螢幕。
開始測試:
把應用下載到手機中,保持螢幕開啟狀態,將手機放入非接觸讀卡機,發送APDU:00A4040007F0010203040506 或者 00A4040007F0394148148100, 將會得到反饋:48656C6C6F204465736B746F7021,解碼一看,正是“Hello Desktop!”的ASCII值,應用的選擇成功。繼續發送一條APDU 00010000,將會得到反饋:4D6573736167652066726F6D20616E64726F69643A2030,解碼一看,正是“Message from android: 0”的ASCII值,可以看到命令的派發成功!
噴幾句:
結合實踐,我們看到HCE支援人員提供了一個軟實現SE的通路,Service實現的方式很多,可以使用檔案,使用網路,甚至串連真正的SE。具體的實現方案還是要依賴於具體的業務需求,網上熱炒的雲方案只是其中一種。雲端式的方式我個人並不看好,從安全的角度:雲的方式固然保證了資料安全,但是如何保證用戶端的訪問安全?從易用性的角度:而基於網路導致的刷卡時間不穩定也不適合公交地鐵等需要快速通過的場合。反而是基於檔案的方式比較適用於ID卡,積分卡等低安全等級的一卡通整合業務。
雲端式的HCE支付是否名至實歸,還是本人受限於技術層面理解的不夠,萬望指正。