­

Android系統編程入門系列之硬件交互——通信硬件NFC

上篇文章介紹了接入式USB硬件的簡單使用,接下來將介紹不依賴物理連接的硬件通信了。本文的重點是近距離通信的硬件NFC。

NFC硬件

應用程序中可以通過NFC硬件讀取或發送指定協議的技術實現,在Android10.0之前甚至可以封裝大段的NDEF數據。另外,Android系統基於NFC的特性,結合移動設備的安全元件,構建了一層HCE架構,從而應用於安全級別較高的公交卡刷卡或付款交易等操作。

權限聲明

要想使用NFC硬件的相關功能,必須要聲明權限,在應用程序的清單文件中聲明<uses-permission />標籤,其中的android:name屬性值為android.permission.NFC
當然,為了強調應用程序需要運行在支持NFC硬件的設備上,也可以在應用程序的清單文件中聲明<uses-feature />標籤,其中的android:name屬性值為android.hardware.nfc

使用流程

由於NFC硬件是在近距離接觸後即可觸發,所以首先要在應用程序中確定觸發NFC連接後要響應的界面Activity。在清單文件註冊的<activity></activity>標籤內部,增加意圖過濾<intent-filter></intent-filter>標籤,並在該標籤內部添加<action />標籤,並指定android:name屬性值分別為android.nfc.action.NDEF_DISCOVERED作為NDEF數據傳輸行為、android.nfc.action.TECH_DISCOVERED作為技術標籤行為或android.nfc.action.TAG_DISCOVERED作為普通行為。

上邊指定的意圖行為有三種方式,但是在連接NFC硬件後,系統將按照上述順序優先啟動對應的界面Activity。另外針對上述三種不同的意圖行為,還要在清單文件下分別追加相應的配置。

在通過上述三種方式收到Intent意圖啟動的界面Activity中,可以通過getIntent()獲取啟動傳入的Intent意圖對象。在該對象中,可以接收其他NFC硬件輸入的標籤及相關內容。

默認功能

針對action值為android.nfc.action.TAG_DISCOVERED的配置,由於是優先級最低的意圖行為,因此在上面兩種意圖行為及配置未調起時,就會調用該意圖行為綁定的界面Activity。因此該意圖行為下不需要其他的配置參數。

在啟動的界面Activity中,調用Intent對象的getParcelableExtra(String name)方法,傳入參數 name 值為NfcAdapter.EXTRA_TAG="android.nfc.extra.TAG",得到android.nfc.TagNFC標籤類型的對象,該對象中記錄了標籤的基本信息。

NDEF數據傳輸功能

針對action值為android.nfc.action.NDEF_DISCOVERED的配置,還要聲明要傳輸的數據類型。同樣在意圖過濾的<intent-filter></intent-filter>標籤內部,添加<data />標籤。可支持傳輸的數據類型可以使用的表示方式,包括 MIME TYPE 類型的結構,和 URI 結構,二選一皆可。在<data />標籤中使用android:mimeType屬性,可以設置 MIME TYPE 結構的數據類型,通常如屬性值為text/plain的文本類型。另外,在<data />標籤中使用android:schemeandroid:hostandroid:pathPrefix三個屬性同時標註URI內容。

在啟動的界面Activity中,調用Intent對象的getParcelableArrayExtra(String name)方法,傳入參數 name 值為NfcAdapter.EXTRA_NDEF_MESSAGES="android.nfc.extra.NDEF_MESSAGES",得到Parcelable[]數組可以分彆強轉為android.nfc.NdefMessage用以保存消息內容的類型對象數組。當使用android.nfc.action.NDEF_DISCOVERED意圖行為過濾的NFC硬件啟動後,可通過該方法獲取NDEF消息內容。

在應用程序內可以自定義NDEF消息體內容並發送。藉助android.nfc.NdefRecordNFC記錄類。在該類中有多個靜態方法,包括createExternal(String domain, String type, byte[] data)創建有攜帶數據的NFC記錄對象;createMime(String mimeType, byte[] mimeData)創建MIME類型的NFC記錄對象;createTextRecord(String languageCode, String text)創建短文本內容的NFC記錄對象;createUri (Uri uri)創建Uri類型的NFC記錄對象等。

在創建NdefRecord對象之後,可以作為參數傳入NdefMessageNFC消息類的構造方法中,從而創建NdefMessage對象,將該對象作為參數,傳入NdefAdapter對象的setNdefPushMessage(NdefMessage message, Activity activity, Activity... activities)方法中,這樣在當前參數 activity 中將會一直發送參數 message 中的內容。

從Android10.0即API級別29開始,NFC功能的NDEF消息傳輸功能就被廢棄了,因此其相關功能方法在以後的版本中也將不再支持。

標籤技術功能

針對action值為android.nfc.action.TECH_DISCOVERED的配置,還要通過資源文件聲明要依賴的技術集。資源文件的聲明是在註冊的<activity></activity>標籤內部,添加<meta-data />標籤,同樣設置其屬性android:name值為android.nfc.action.TECH_DISCOVERED,更別忘了設置屬性android:resource,其值為保存在 res/xml 目錄下的資源文件。而資源文件的定義,是在 res/xml 路徑下,定義 xml 格式的資源文件,在該文件中使用<tech-list></tech-list>標籤作為最外層的集合,在該標籤中包含了一堆使用<tech>標籤定義的可支持技術。這些技術的定義均實現了android.nfc.tech.TagTechnology標籤技術接口,在各種實現類中定義了相應技術的常量值。

在啟動的界面Activity中,同樣可以調用Intent對象的getParcelableExtra(String name)方法,傳入參數 name 值為[NfcAdapter.EXTRA_TAG]得到TAGNFC標籤類的對象。

另外可以通過其getTechList()方法,獲取通過意圖行為android.nfc.action.TECH_DISCOVERED啟動的NFC硬件中所使用技術列表。其中系統支持的技術類型均實現了android.nfc.tech.TagTechnology標籤技術接口。

在得到的TagNFC標籤類的對象後,可以遵循相關技術類型對標籤進行讀寫操作。對實現了TagTechnology接口的具體技術類中,可以調用靜態方法get(Tag tag)得到具體的技術類對象,其參數即得到的TagNFC標籤類對象。在實現TagTechnology接口的對象中,需要首先調用connect()建立連接;之後可以根據不同的技術實現,調用相關的讀寫操作方法;最終在操作結束後,調用close()斷開連接即可。

HCE服務功能

該功能是由Android系統實現的一套在後台使用NFC進行交易等服務的架構。該架構主要依賴android.nfc.cardemulation.HostApduService抽象服務類。在自定義的服務中必須繼承自HostApduService服務類,並實現其兩個抽象方法,接收並響應數據的byte[] processCommandApdu(byte[] apdu, Bundle extras)方法,和NFC切換或關閉當前APDU連接時的void onDeactivated(int reason)方法。

在定義了繼承自HostApduService的服務之後,需要在清單文件中註冊該服務組件,在<service></service>標籤中要設置android:exported屬性值為true。同時在標籤內嵌入<intent-filter></intent-filter>意圖過濾標籤中,設置行為值為HostApduService.SERVICE_INTERFACE="android.nfc.cardemulation.action.HOST_APDU_SERVICE"。另外要在標籤內嵌入<meta-data />額外數據標籤,設置其android:name屬性值為HostApduService.SERVICE_META_DATA="android.nfc.cardemulation.host_apdu_service",設置其android:resource屬性為包含 AID 群組的資源文件。

定義的 AID 群組,是由NFC卡提供的應用唯一標識,如用於支付的銀聯儲蓄卡、公交卡等,每張卡都有唯一的16位元組組成的AID。而在資源文件中可以定義該應用程序自定義的HostApduService服務中允許交易的 AID 群組,該群組的所有 AID 只要有一個 AID 連接當前設備的 NFC 硬件,都會喚起 HCE 服務。

在應用程序的資源文件 res/xml 目錄下,可以創建自定義的資源文件以定義上述 AID 群組,在資源文件中根標籤為<host-apdu-service></host-apdu-service>,在其中可以嵌入多組標籤<aid-group></aid-group>用來標記 AID 群組,其中設置android:description屬性值為字符串類型的群組介紹,還需要設置android:category屬性值為android.nfc.cardemulation.CardEmulation.CATEGORY_PAYMENT="payment"作為支付使用、或者屬性值為android.nfc.cardemulation.CardEmulation.CATEGORY_OTHER="other"。在該標籤內部,就可以嵌入多組<aid-filter / >標籤並設置其android:name屬性值,用以標記當前群組下的 AID 值。