Android系統編程入門系列之硬件交互——通信硬件NFC
- 2022 年 1 月 21 日
- 筆記
- Android_Home
在上篇文章介紹了接入式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:scheme
、android:host
、android: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
對象之後,可以作為參數傳入NdefMessage
NFC消息類的構造方法中,從而創建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]得到TAG
NFC標籤類的對象。
另外可以通過其getTechList()
方法,獲取通過意圖行為android.nfc.action.TECH_DISCOVERED
啟動的NFC硬件中所使用技術列表。其中系統支持的技術類型均實現了android.nfc.tech.TagTechnology標籤技術接口。
在得到的Tag
NFC標籤類的對象後,可以遵循相關技術類型對標籤進行讀寫操作。對實現了TagTechnology
接口的具體技術類中,可以調用靜態方法get(Tag tag)
得到具體的技術類對象,其參數即得到的Tag
NFC標籤類對象。在實現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 值。