Android NFC详解
1、NFC概覽
? ? ? ? NFC,全稱是Near Field Communication,中為近場通信,也叫做近距離無線通信技術。使用了NFC技術的設備(例如移動電話)可以在彼此靠近的情況下進行數據交換,是由非接觸式射頻識別(RFID)及互連互通技術整合演變而來的,通過在單一芯片上集成感應式讀卡器、感應式卡片和點對點通信的功能,利用移動終端實現移動支付、電子票務、門禁、移動身份識別、防偽等應用。
2、NFC工作原理
? ? ? ? NFC是一種短距高頻的無線電技術,NFCIP-1標準規定NFC的通信距離為10厘米以內,運行頻率13.56MHz,傳輸速度有106Kbit/s、212Kbit/s或者424Kbit/s三種。NFCIP-1標準詳細規定NFC設備的傳輸速度、編解碼方法、調制方案以及射頻接口的幀格式,此標準中還定義了NFC的傳輸協議,其中包括啟動協議和數據交換方法等。
? ? ? ? NFC工作模式分為被動模式和主動模式。
? ? ? ? 1)被動模式
? ? ? ? 被動模式中NFC發起設備(也稱為主設備)需要供電設備,主設備利用供電設備的能量來提供射頻場,并將數據發送到NFC目標設備(也稱作從設備),傳輸速率需在106kbps、212kbps或424kbps中選擇其中一種。從設備不產生射頻場,所以可以不需要供電設備,而是利用主設備產生的射頻場轉換為電能,為從設備的電路供電,接收主設備發送的數據,并且利用負載調制(load modulation)技術,以相同的速度將從設備數據傳回主設備。因為此工作模式下從設備不產生射頻場,而是被動接收主設備產生的射頻場,所以被稱作被動模式,在此模式下,NFC主設備可以檢測非接觸式卡或NFC目標設備,與之建立連接。
? ? ? ? 2)主動模式
? ? ? ? 主動模式中,發起設備和目標設備在向對方發送數據時,都必須主動產生射頻場,所以稱為主動模式,它們都需要供電設備來提供產生射頻場的能量。這種通信模式是對等網絡通信的標準模式,可以獲得非常快速的連接速率
3、NFC在Android上應用
? ? ? ? 近距離無線通信 (NFC) 是一組近距離無線技術,借助 NFC,您可以在 NFC 標簽與 Android 設備之間或者兩臺 Android 設備之間共享小型負載。
? ? ? ? 標簽的復雜度可能各有不同。簡單標簽僅提供讀取和寫入語義,有時可使用一次性可編程區域將卡片設置為只讀。較復雜的標簽可提供數學運算,還可使用加密硬件來驗證對扇區的訪問權限。最為復雜的標簽可包含操作環境,允許與針對標簽執行的代碼進行復雜的互動。存儲在標簽中的數據也可以采用多種格式編寫,但許多 Android 框架 API 都基于名為 NDEF(NFC 數據交換格式)的?NFC Forum?標準。
支持 NFC 的 Android 設備同時支持以下三種主要操作模式:
? ? ? ? 1)基本 NFC 任務
將 NDEF 數據與 Android 結合使用時,會有兩個主要用例:
- 從 NFC 標簽讀取 NDEF 數據
- 使用Android Beam?將 NDEF 消息從一臺設備傳輸到另一臺設備
? ? ? ? 從 NFC 標簽讀取 NDEF 數據的操作由標簽調度系統進行處理,該系統會分析已發現的 NFC 標簽,對相應數據進行適當分類,然后啟動對分類后的數據感興趣的應用。如果某個應用想要處理掃描到的 NFC 標簽,則可以聲明 Intent 過濾器,并請求對數據進行處理。
? ? ? ? 借助 Android Beam? 功能,設備可以將 NDEF 消息推送到另一臺設備,方法是將兩臺設備靠在一起。與藍牙等其他無線技術相比,這種互動可提供更簡便的數據發送方式,因為使用 NFC 時無需手動發現設備并將其配對。當兩臺設備之間的距離近到一定范圍內時,系統會自動開始連接。Android Beam 功能通過一組 NFC API 提供,因此任何應用都可以在設備間傳輸信息。例如,通訊錄、瀏覽器和 YouTube 應用可使用 Android Beam 在多臺設備之間共享聯系人信息、網頁和視頻。
? ? ? ? 標簽調度系統
? ? ? ? Android 設備通常會在屏幕解鎖后查找 NFC 標簽,除非設備的“設置”菜單中停用了 NFC 功能。在 Android 設備發現 NFC 標簽后,期望的行為就是讓最合適的 Activity 來處理該 Intent,而不是詢問用戶應使用哪個應用。
? ? ? ? 為幫助您實現這一目標,Android 提供了一個特殊的標簽調度系統,用于分析掃描到的 NFC 標簽、解析它們并嘗試找到對掃描到的數據感興趣的應用。這個標簽調度系統通過以下操作來實現這些目的:
如何將 NFC 標簽映射到 MIME 類型和 URI
? ? ? ? 在開始編寫 NFC 應用之前,請務必了解不同類型的 NFC 標簽、標簽調度系統如何解析 NFC 標簽,以及標簽調度系統在檢測到 NDEF 消息后所執行的特殊工作。NFC 標簽涉及多種技術,也可以通過許多不同的方式將數據寫入 NFC 標簽中。Android 對 NFC Forum 定義的 NDEF 標準的支持最完備。
? ? ? ? NDEF 數據封裝在包含一條或多條記錄 (NdefRecord) 的消息 (NdefMessage) 內。每條 NDEF 記錄的格式都必須正確,符合您要創建的記錄所屬的類型對應的規范。Android 還支持其他類型的不包含 NDEF 數據的標簽,您可以使用 android.nfc.tech 軟件包中的類處理這些標簽。在處理這些其他類型的標簽時,您需要通過編寫自己的協議棧來與標簽進行通信,因此,我們建議您盡可能使用 NDEF,以簡化開發,同時最大限度地支持 Android 設備。
? ? ? ? 注意:要下載完整的 NDEF 規范,請轉到?NFC Forum 規范和應用文檔網站,查看有關如何構造 NDEF 記錄的示例。
? ? ? ? 現在,您已了解 NFC 標簽的一些相關背景知識,以下幾部分將詳細介紹 Android 如何處理 NDEF 格式的標簽。當 Android 設備掃描包含 NDEF 格式數據的 NFC 標簽時,它會解析該消息并嘗試確定數據的 MIME 類型或起標識作用的 URI。為此,系統需要讀取 NdefMessage 中的第一條 NdefRecord,以確定如何解讀整個 NDEF 消息(一個 NDEF 消息可能具有多條 NDEF 記錄)。在格式正確的 NDEF 消息中,第一條 NdefRecord 包含以下字段:
? ? ? ? a)、3 位 TNF(類型名稱格式)
表示如何解讀可變長度類型字段。表 1 中介紹了有效的值。
? ? ? ? b)、可變長度類型
介紹了記錄的類型。如果使用 TNF_WELL_KNOWN,那么請使用此字段來指定記錄類型定義 (RTD)。表 2 中介紹了有效的 RTD 值。
? ? ? ? c)、可變長度 ID
記錄的唯一標識符。此字段并不經常使用,但如果您需要對標簽進行唯一標識,則可為其創建 ID。
? ? ? ? d)、可變長度負載
您要讀取或寫入的實際數據負載。一個 NDEF 消息可以包含多條 NDEF 記錄,因此不要假定 NDEF 消息的第一條 NDEF 記錄中就有完整的負載。
| TNF_ABSOLUTE_URI | 基于類型字段的 URI。 |
| TNF_EMPTY | 回退到?ACTION_TECH_DISCOVERED。 |
| TNF_EXTERNAL_TYPE | 基于類型字段中 URN 的 URI。URN 以縮短形式 (<domain_name>:<service_name>) 編碼到 NDEF 類型字段中。Android 會以如下形式將此映射到 URI:vnd.android.nfc://ext/<domain_name>:<service_name>。 |
| TNF_MIME_MEDIA | 基于類型字段的 MIME 類型。 |
| TNF_UNCHANGED | 在第一條記錄中無效,因此會回退到?ACTION_TECH_DISCOVERED。 |
| TNF_UNKNOWN | 回退到?ACTION_TECH_DISCOVERED。 |
| TNF_WELL_KNOWN | MIME 類型或 URI,具體取決于您在類型字段中設置的記錄類型定義 (RTD)。如需詳細了解可用的 RTD 及其映射,請參閱表 2。 |
| RTD_ALTERNATIVE_CARRIER | 回退到?ACTION_TECH_DISCOVERED。 |
| RTD_HANDOVER_CARRIER | 回退到?ACTION_TECH_DISCOVERED。 |
| RTD_HANDOVER_REQUEST | 回退到?ACTION_TECH_DISCOVERED。 |
| RTD_HANDOVER_SELECT | 回退到?ACTION_TECH_DISCOVERED。 |
| RTD_SMART_POSTER | 基于負載解析結果的 URI。 |
| RTD_TEXT | text/plain?的 MIME 類型。 |
| RTD_URI | 基于負載的 URI。 |
? ? ? ? 標簽調度系統使用 TNF 和類型字段來嘗試將 MIME 類型或 URI 映射到 NDEF 消息。如果成功映射,它會將相關信息與實際負載一起封裝到 ACTION_NDEF_DISCOVERED Intent 內。不過,在某些情況下,標簽調度系統無法根據第一條 NDEF 記錄來確定數據的類型。如果 NDEF 數據無法映射到 MIME 類型或 URI,或者 NFC 標簽不包含 NDEF 數據,就會出現上述情況。在此類情況下,標簽調度系統會轉而將含有標簽技術相關信息的 Tag 對象及負載封裝到ACTION_TECH_DISCOVERED Intent 中。
? ? ? ? 表 1 介紹了標簽調度系統如何將 TNF 和類型字段映射到 MIME 類型或 URI,還介紹了哪些 TNF 無法映射到 MIME 類型或 URI。如果無法映射,標簽調度系統會回退到 ACTION_TECH_DISCOVERED。
? ? ? ? 例如,如果標簽調度系統遇到 TNF_ABSOLUTE_URI 類型的記錄,則會將該記錄的可變長度類型字段映射到 URI 中。標簽調度系統將此 URI 連同與標簽有關的其他信息(如負載)一起封裝在 ACTION_NDEF_DISCOVERED Intent 的數據字段中。另一方面,如果標簽調度系統遇到 TNF_UNKNOWN 類型的記錄,則會轉而創建一個 Intent,用于封裝與標簽技術相關的信息。
如何將 NFC 標簽分發到應用
當標簽調度系統創建完用于封裝 NFC 標簽及其標識信息的 Intent 后,它會將該 Intent 發送給感興趣的應用,由這些應用對其進行過濾。如果有多個應用可處理該 Intent,系統會顯示 Activity 選擇器,供用戶選擇要使用的 Activity。標簽調度系統定義了三種 Intent,按優先級從高到低列出如下:
標簽調度系統的基本工作方式如下:
? ? ? ? ?盡可能使用 NDEF 消息和 ACTION_NDEF_DISCOVERED Intent,因為它是三種 Intent 中最具體的一種。與其他兩種 Intent 相比,此 Intent 可使您在更恰當的時間啟動應用,從而為用戶帶來更好的體驗。
? ? ? ? 在 Android 清單中請求 NFC 訪問權限
? ? ? ? 您必須先在?AndroidManifest.xml?文件中聲明以下內容,然后才能訪問設備的 NFC 硬件并正確處理 NFC Intent:
- 用于訪問 NFC 硬件的 NFC?<uses-permission>?元素:
- 您的應用支持的最低 SDK 版本。API 級別 9 僅通過 ACTION_TAG_DISCOVERED 支持有限的標簽調度,并且只能通過 EXTRA_NDEF_MESSAGES extra 提供對 NDEF 消息的訪問權限。無法訪問其他任何標簽屬性或 I/O 操作。API 級別 10 提供全面的讀取器/寫入器支持以及前臺 NDEF 推送功能;API 級別 14 則提供了一種更簡便的方式(即,使用 Android Beam 將 NDEF 消息推送到其他設備),同時提供了用于創建 NDEF 記錄的其他便捷方法。
- uses-feature?元素,以便您的應用僅在那些具備 NFC 硬件的設備的 Google Play 中顯示:
? ? ? ? ?如果您的應用使用 NFC 功能,但該功能對您的應用來說并不重要,您可以省略 uses-feature 元素,并在運行時通過檢查 getDefaultAdapter() 是否為 null 來了解 NFC 的可用性。
? ? ? ? 過濾 NFC Intent
? ? ? ? 要在掃描到您打算處理的 NFC 標簽時啟動您的應用,您的應用可以在 Android 清單中過濾一個、兩個或所有三個 NFC Intent。不過,您通常需要過濾 ACTION_NDEF_DISCOVERED Intent,以最有力地控制應用在何時啟動。如果沒有應用過濾 ACTION_NDEF_DISCOVERED,或者負載不是 NDEF,ACTION_TECH_DISCOVERED Intent 會取代 ACTION_NDEF_DISCOVERED。ACTION_TAG_DISCOVERED 通常因過于籠統而不適合過濾。許多應用會在過濾 ACTION_TAG_DISCOVERED 前過濾 ACTION_NDEF_DISCOVERED 或 ACTION_TECH_DISCOVERED,導致 您的應用啟動的概率會比較低。過濾 ACTION_TAG_DISCOVERED 是應用在沒有其他應用來處理 ACTION_NDEF_DISCOVERED 或 ACTION_TECH_DISCOVERED Intent 的情況下的最后一道保險。
? ? ? ? 由于 NFC 標簽部署各有不同,并且很多時候它們都不由您控制,因此,ACTION_NDEF_DISCOVERED 不一定每次都可用,您可以根據需要回退到另外兩種 Intent。如果您可以控制標簽和寫入數據的類型,建議您使用 NDEF 來設置標簽的格式。以下幾部分介紹了如何過濾各類 Intent。
- ACTION_NDEF_DISCOVERED
? ? ? ? 要過濾 ACTION_NDEF_DISCOVERED Intent,請聲明 Intent 過濾器以及要過濾的數據類型。以下示例展示了如何過濾 MIME 類型為 text/plain 的 ACTION_NDEF_DISCOVERED Intent:
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="text/plain" /></intent-filter>? ? ? ? 以下示例展示了如何過濾采用?https://developer.android.com/index.html?形式的 URI。
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED"/><category android:name="android.intent.category.DEFAULT"/><data android:scheme="http"android:host="developer.android.com"android:pathPrefix="/index.html" /></intent-filter>- ACTION_TECH_DISCOVERED
? ? ? ? 如果您的 Activity 過濾 ACTION_TECH_DISCOVERED Intent,您必須創建一個 XML 資源文件,用它在 tech-list 集內指定您的 Activity 所支持的技術。如果 tech-list 集是標簽所支持的技術(可通過調用 getTechList() 來獲取)的子集,則您的 Activity 會被視為一個匹配項。
? ? ? ? 例如,如果掃描到的標簽支持 MifareClassic、NdefFormatable 和 NfcA,為了使它們與您的 Activity 匹配,您的 tech-list 集必須指定所有這三種技術,或者其中的兩種或一種技術。
? ? ? ? 以下示例定義了所有技術。您可以移除自己不需要的技術。將此文件(你可以隨便命名)保存到 <project-root>/res/xml 文件夾中。
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><tech-list><tech>android.nfc.tech.IsoDep</tech><tech>android.nfc.tech.NfcA</tech><tech>android.nfc.tech.NfcB</tech><tech>android.nfc.tech.NfcF</tech><tech>android.nfc.tech.NfcV</tech><tech>android.nfc.tech.Ndef</tech><tech>android.nfc.tech.NdefFormatable</tech><tech>android.nfc.tech.MifareClassic</tech><tech>android.nfc.tech.MifareUltralight</tech></tech-list></resources>? ? ? ? 您還可以指定多個 tech-list 集。每個 tech-list 集都是獨立的;如果任意一個 tech-list 集是由 getTechList() 返回的技術的子集,則您的 Activity 會被視為一個匹配項。這為匹配技術提供了 AND 和 OR 語義。以下示例展示了如何與支持 NfcA 和 Ndef 技術的標簽或者支持 NfcB 和 Ndef 技術的標簽相匹配:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><tech-list><tech>android.nfc.tech.NfcA</tech><tech>android.nfc.tech.Ndef</tech></tech-list><tech-list><tech>android.nfc.tech.NfcB</tech><tech>android.nfc.tech.Ndef</tech></tech-list></resources>? ? ? ? 在您的?AndroidManifest.xml?文件中,在?<activity>?元素的?<meta-data>?元素中指定您剛剛創建的資源文件,如以下示例所示:
<activity>...<intent-filter><action android:name="android.nfc.action.TECH_DISCOVERED"/></intent-filter><meta-data android:name="android.nfc.action.TECH_DISCOVERED"android:resource="@xml/nfc_tech_filter" />...</activity>? ? ? ??如需詳細了解如何使用標簽技術和 ACTION_TECH_DISCOVERED Intent,請參閱高級 NFC 文檔中的使用支持的標簽技術(以后寫)。
-
ACTION_TAG_DISCOVERED
? ? ? ? 要過濾 ACTION_TAG_DISCOVERED,請使用以下 Intent 過濾器:
<intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED"/></intent-filter>-
從 Intent 中獲取信息
? ? ? ? 如果某個 Activity 由于 NFC Intent 而啟動,您可以從該 Intent 中獲取有關掃描到的 NFC 標簽的信息。Intent 可以包含以下 extra,具體取決于掃描到的標簽:
- EXTRA_TAG(必需):一個 Tag 對象,表示掃描到的標簽。
- EXTRA_NDEF_MESSAGES(可選):從標簽中解析出的一組 NDEF 消息。此 extra 對于 ACTION_NDEF_DISCOVERED Intent 而言是必需的。
- EXTRA_ID(可選):標簽的低級別 ID。
? ? ? ? 要獲取這些 extra,請檢查您的 Activity 是不是使用某個 NFC Intent 啟動的,以確保已掃描到標簽,然后獲取 Intent 的 extra。以下示例展示了如何檢查 ACTION_NDEF_DISCOVERED Intent 并從 Intent extra 獲取 NDEF 消息。
@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);...if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {Parcelable[] rawMessages =intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);if (rawMessages != null) {NdefMessage[] messages = new NdefMessage[rawMessages.length];for (int i = 0; i < rawMessages.length; i++) {messages[i] = (NdefMessage) rawMessages[i];}// Process the messages array....}}}? ? ? ? 或者,您可以從 Intent 中獲取 Tag 對象,該對象包含負載并允許您枚舉標簽的技術:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);? ? ? ? 創建常見類型的 NDEF 記錄?
? ? ? ? 本部分介紹了如何創建常見類型的 NDEF 記錄,以幫助向 NFC 標簽寫入數據或使用 Android Beam 發送數據。從 Android 4.0(API 級別 14)開始引入平臺的 createUri() 方法可幫助您自動創建 URI 記錄。從 Android 4.1(API 級別 16)開始引入平臺的 createExternal() 和 createMime() 可幫助您創建 MIME 和外部類型的 NDEF 記錄。請盡可能使用這些輔助方法,以免在手動創建 NDEF 記錄時出錯。
? ? ? ? 本部分還介紹了如何為記錄創建相應的 Intent 過濾器。所有這些 NDEF 記錄示例都應該位于您寫入標簽或傳輸到另一設備的 NDEF 消息的第一條 NDEF 記錄中。
? ? ? ? a)、TNF_ABSOLUTE_URI
注意:建議您使用 RTD_URI 類型,而不是 TNF_ABSOLUTE_URI,因為前者更為高效。
您可以通過以下方式創建一條 TNF_ABSOLUTE_URI NDEF 記錄:
NdefRecord uriRecord = new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI ,"https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),new byte[0], new byte[0]);上一條 NDEF 記錄的 Intent 過濾器如下所示:?
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /><data android:scheme="http"android:host="developer.android.com"android:pathPrefix="/index.html" /></intent-filter>? ? ? ? b)、TNF_MIME_MEDIA?
您可以通過以下方式創建一條 TNF_MIME_MEDIA NDEF 記錄:
使用 createMime() 方法:
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam","Beam me up, Android".getBytes(Charset.forName("US-ASCII")));手動創建 NdefRecord:
NdefRecord mimeRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA ,"application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));?上一條 NDEF 記錄的 Intent 過濾器如下所示:
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="application/vnd.com.example.android.beam" /></intent-filter>? ? ? ? c)、RTD 為 RTD_TEXT 的 TNF_WELL_KNOWN
您可以通過以下方式創建一條 TNF_WELL_KNOWN NDEF 記錄:?
上一條 NDEF 記錄的 Intent 過濾器如下所示:
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="text/plain" /></intent-filter>? ? ? ? ?d)、RTD 為 RTD_URI 的 TNF_WELL_KNOWN
您可以通過以下方式創建一條 TNF_WELL_KNOWN NDEF 記錄:
使用 createUri(String) 方法:
? ? NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");使用 createUri(Uri) 方法:
Uri uri = Uri.parse("http://example.com");NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);?手動創建 NdefRecord:
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefixpayload[0] = 0x01; //prefixes http://www. to the URISystem.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payloadNdefRecord rtdUriRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);上一條 NDEF 記錄的 Intent 過濾器如下所示:
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /><data android:scheme="http"android:host="example.com"android:pathPrefix="" /></intent-filter>? ? ? ? 使用 TNF_EXTERNAL_TYPE 實現更通用的 NFC 標簽部署,以更好地支持 Android 設備和非 Android 設備。
? ? ? ? 注意:TNF_EXTERNAL_TYPE 的 URN 的規范格式為urn:nfc:ext:example.com:externalType,但 NFC Forum RTD 規范包含如下聲明:NDEF 記錄中必須省略 URN 的?urn:nfc:ext:?部分。因此,您只需要提供域名(示例中為?example.com)和類型(示例中為?externalType),并通過英文冒號將兩者分隔開。分發?TNF_EXTERNAL_TYPE?時,Android 會將?urn:nfc:ext:example.com:externalType?URN 轉換為?vnd.android.nfc://ext/example.com:externalType?URI,也就是示例中的 Intent 過濾器聲明的 URI。
? ? ? ? e)、Android 應用記錄
? ? ? ? Android 4.0(API 級別 14)中引入了 Android 應用記錄 (AAR) 功能,它可以更有力地確保在掃描到 NFC 標簽時啟動您的應用。AAR 在 NDEF 記錄內嵌入了應用的軟件包名稱。您可以將 AAR 添加到 NDEF 消息的任意 NDEF 記錄中,因為 Android 會在整個 NDEF 消息中搜索 AAR。如果找到 AAR,它會根據 AAR 中的軟件包名稱啟動相應應用。如果設備上沒有該應用,則會啟動 Google Play,供用戶下載該應用。
? ? ? ? 如果您想要阻止其他應用過濾同一 Intent,并阻止其他應用潛在地處理您已部署的特定標簽,則可以使用 AAR。由于軟件包名稱方面的限制,AAR 僅在應用級別受支持,與 Intent 過濾一樣在 Activity 級別不受支持。如果您需要在 Activity 級別處理 Intent,可使用 Intent 過濾器。
? ? ? ? 如果標簽包含 AAR,標簽調度系統將按以下方式執行分發:
? ? ? ? 注意:您可以使用前臺調度系統替換 AAR 和 Intent 調度系統,以便在發現 NFC 標簽后優先啟動前臺 Activity。使用此方法時,Activity 必須在前臺運行才能替換 AAR 和 Intent 調度系統。
? ? ? ? 如果您仍希望過濾掃描到的不包含 AAR 的標簽,則可以照常聲明 Intent 過濾器。如果您的應用對其他不包含 AAR 的標簽感興趣,這將非常有用。例如,您可能需要保證您的應用能夠處理由您部署的專有標簽以及由第三方部署的常規標簽。請注意,AAR 特定于搭載 Android 4.0 或更高版本的設備,因此,在部署標簽時,您很可能需要將 AAR 和 MIME 類型/URI 結合使用,以支持各種設備。此外,在部署 NFC 標簽時,請考慮:要如何編寫 NFC 標簽,才能使其支持大多數設備(Android 設備和其他設備)。為此,您可以定義相對唯一的 MIME 類型或 URI,從而使應用更容易區分它們。
? ? ? ? Android 提供了 createApplicationRecord() 這個簡單的 API 來創建 AAR。您只需將 AAR 嵌入 NdefMessage 中的任意位置即可。您不需要使用 NdefMessage 的第一條記錄,除非 AAR 是 NdefMessage 中唯一的記錄。這是因為 Android 系統會檢查 NdefMessage 的第一條記錄,以此來確定標簽的 MIME 類型或 URI;在創建應用要過濾的 Intent 時需要用到標簽的 MIME 類型或 URI。以下代碼展示了如何創建 AAR:
NdefMessage msg = new NdefMessage(new NdefRecord[] {...,NdefRecord.createApplicationRecord("com.example.android.beam")});)? ? ? ? 向其他設備傳輸 NDEF 消息?
? ? ? ? Android Beam 可在兩臺 Android 設備之間進行簡單的點對點數據交換。需要將數據傳輸到另一臺設備的應用必須在前臺運行,并且要接收數據的設備不得處于鎖定狀態。當傳輸設備與接收設備的距離足夠近時,傳輸設備會顯示“觸摸即可傳輸”界面。然后,用戶可以選擇是否將消息傳輸到接收設備。
? ? ? ? 注意:API 級別 10 中提供前臺 NDEF 推送,其功能與 Android Beam 類似。此后,這些 API 已棄用,但可用于支持舊設備。如需了解詳情,請參閱?enableForegroundNdefPush()。
? ? ? ? 調用以下兩種方法之一可為您的應用啟用 Android Beam:
- setNdefPushMessage():接受 NdefMessage 以將其設置為待傳輸的消息。在兩臺設備的距離足夠接近時自動傳輸消息。
- setNdefPushMessageCallback():接受包含 createNdefMessage()(在設備處于可接收數據的范圍內時調用)的回調。該回調支持您根據需要創建 NDEF 消息。
? ? ? ? Activity 一次只能推送一個 NDEF 消息,因此,如果設置了兩個 NDEF 消息,setNdefPushMessageCallback() 將優先于 setNdefPushMessage()。要使用 Android Beam,必須滿足以下一般準則:
- 傳輸數據的 Activity 必須在前臺運行。兩臺設備的屏幕都必須處于解鎖狀態。
- 必須將要傳輸的數據封裝到 NdefMessage 對象中。
- 接收傳輸數據的 NFC 設備必須支持 com.android.npp NDEF 推送協議或 NFC Forum 的 SNEP(簡單 NDEF 交換協議)。API 級別 9 (Android 2.3) 到 API 級別 13 (Android 3.2) 的設備都需要使用 com.android.npp 協議。API 級別 14 (Android 4.0) 及更高版本的設備需要使用 com.android.npp 和 SNEP。
? ? ? ? 注意:如果您的 Activity 支持 Android Beam 且在前臺運行,則標準 Intent 調度系統將停用。不過,如果您的 Activity 也支持前臺調度,那么它仍然可以掃描與前臺調度中設置的 Intent 過濾器相匹配的標簽。
? ? ? ? 要啟用 Android Beam,請執行以下操作:
? ? ? ? 以下示例展示了一個簡單 Activity 如何調用 Activity 的 onCreate() 方法中的 NfcAdapter.CreateNdefMessageCallback。此示例還提供了一些方法來幫助您創建 MIME 記錄:
package com.example.android.beam;import android.app.Activity;import android.content.Intent;import android.nfc.NdefMessage;import android.nfc.NdefRecord;import android.nfc.NfcAdapter;import android.nfc.NfcAdapter.CreateNdefMessageCallback;import android.nfc.NfcEvent;import android.os.Bundle;import android.os.Parcelable;import android.widget.TextView;import android.widget.Toast;import java.nio.charset.Charset;public class Beam extends Activity implements CreateNdefMessageCallback {NfcAdapter nfcAdapter;TextView textView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);TextView textView = (TextView) findViewById(R.id.textView);// Check for available NFC AdapternfcAdapter = NfcAdapter.getDefaultAdapter(this);if (nfcAdapter == null) {Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();finish();return;}// Register callbacknfcAdapter.setNdefPushMessageCallback(this, this);}@Overridepublic NdefMessage createNdefMessage(NfcEvent event) {String text = ("Beam me up, Android!\n\n" +"Beam Time: " + System.currentTimeMillis());NdefMessage msg = new NdefMessage(new NdefRecord[] { createMime("application/vnd.com.example.android.beam", text.getBytes())/*** The Android Application Record (AAR) is commented out. When a device* receives a push with an AAR in it, the application specified in the AAR* is guaranteed to run. The AAR overrides the tag dispatch system.* You can add it back in to guarantee that this* activity starts when receiving a beamed message. For now, this code* uses the tag dispatch system.*///,NdefRecord.createApplicationRecord("com.example.android.beam")});return msg;}@Overridepublic void onResume() {super.onResume();// Check to see that the Activity started due to an Android Beamif (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {processIntent(getIntent());}}@Overridepublic void onNewIntent(Intent intent) {// onResume gets called after this to handle the intentsetIntent(intent);}/*** Parses the NDEF Message from the intent and prints to the TextView*/void processIntent(Intent intent) {textView = (TextView) findViewById(R.id.textView);Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);// only one message sent during the beamNdefMessage msg = (NdefMessage) rawMsgs[0];// record 0 contains the MIME type, record 1 is the AAR, if presenttextView.setText(new String(msg.getRecords()[0].getPayload()));}}? ? ? ? 注意,此代碼為 AAR 添加了注釋,您可以將其移除。如果啟用 AAR,則 AAR 中指定的應用始終會收到 Android Beam 消息。如果該應用不存在,則會啟動 Google Play,請用戶下載該應用。因此,對于搭載 Android 4.0 及更高版本的設備(如果使用了 AAR)而言,以下 Intent 過濾器在技術上是不需要的:?
<intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="application/vnd.com.example.android.beam"/></intent-filter>? ? ? ? ?憑借此 Intent 過濾器,com.example.android.beam?應用現在可以在以下情況下啟動:掃描到 NFC 標簽或通過 Android Beam 接收到類型為 的 AAR,或者在 NDEF 格式的消息包含類型為?application/vnd.com.example.android.beam?的 MIME 記錄時。
? ? ? ? 即使 AAR 能夠保證啟動或下載應用,但我們仍建議您使用 Intent 過濾器,因為它們允許您在應用中啟動所選的 Activity,而不是始終啟動由 AAR 指定的軟件包內的主 Activity。AAR 不具備 Activity 級別的粒度。此外,由于某些 Android 設備不支持 AAR,因此您還應在 NDEF 消息的第一條 NDEF 記錄中嵌入標識信息,以便在需要時進行過濾。
?4、NFC與其他技術的比較
? ? ? ? 目前的近距離無線通信技術包括了RFID、藍牙、紅外等, NFC是一種短距離的高頻無線通訊技術,電子設備之間允許進行非接觸式點對點數據傳輸。其工作頻率為 13.56MHz,通信距離 0~20cm(實際大部分產品都在 10cm 以內),傳輸速率可為106kbit/s、212kbit/s、424 kbit/s和848kbit/s。近距無線通信技術除NFC外,主要還包括射頻識別(RFID)、藍牙(Bluetooth)、紫蜂(ZigBee)、紅外、 Wi-Fi等技術。以上各項技術都有各自的特點和優點,下圖給出了 NFC 以及其他六種幾種短距離無線通信技術在所列頻段上性能的比較。
?
? ? 可以看出,NFC 技術具有極高的安全性,在短距離通信中具有性能優勢,更重要的是成本較低,因此自其 2003 年問世以來,得到眾多企業的關注和支持。
? ? ? ? NFC與RFID的比較
? ? ? ? 第一,工作模式不同。NFC是將點對點通信功能,讀寫器功能和非接觸卡功能集成進一顆芯片,而RFID則有閱讀器和標簽兩部分組成。NFC技術既可以讀取也可以寫入,而RFID只能實現信息的讀取以及判定。 [2]?
? ? ? ? 第二,傳輸距離不同。NFC傳輸距離比RFID小的多,NFC 的傳輸距離只有10厘米,RFID的傳輸距離可以達到幾米、甚至幾十米。NFC是一種近距離的私密通信方式,相對于RFID來說NFC具有距離近、帶寬高、能耗低、安全性高等特點。 [2]?
? ? ? ? 第三,應用領域不同。NFC更多的應用于消費類電子設領域,在門禁、公交、手機支付等領域發揮著巨大的作用;RFID則更擅長于長距離識別,更多的被應用在生產、物流、跟蹤、資產管理上。 [2]?
? ? ? ? 近場通信NFC與藍牙的比較
? ? ? ? NFC和藍牙都是短程通信技術,相對于藍牙很早就被集成到移動電話中并已經被普及,NFC最近幾年才開始被集成進移動電話中,并且到目前為止只集成在少數移動電話中。 [2]?
? ? ? ? 第一,建立時間不同,NFC通信設置程序簡單,通信建立時間很短,僅需0.1s左右;而藍牙通信設置程序相對復雜,通信建立時間較長,大概需要6s。 [2]?
? ? ? ? 第二,傳輸距離不同,NFC傳輸距離只有10cm,而藍牙傳輸距離可達10m。但NFC在傳輸功耗和安全性方面略優于藍牙。 [2]?
? ? ? ? 第三,傳輸速度和工作頻率不同,NFC工作頻率為13.56MHz, 傳輸速度最大424 Kbit/s,而藍牙工作頻率為2.4GHz,傳輸速度可 達2.1 Mbit/s。 [2]?
? ? ? ? 近場通信NFC與紅外的比較
NFC和紅外傳輸相比,傳輸距離相當,但比紅外傳輸速度更快,NFC傳輸速度最大可達424 Kbit/s,而紅外傳輸速度大概 100Kbit/s。建立時間NFC比紅外略快,NFC建立時間為0.1s, 紅外傳輸建立時間為0.5s。紅外傳輸必須嚴格的對齊才能傳輸數據,且中間不能有障礙物,而NFC則沒有這種限制;另外NFC比紅外更安全可靠。
總結
以上是生活随笔為你收集整理的Android NFC详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASA 第五天实验
- 下一篇: android应用程序的组件,Andro