Android NFC详解
1、NFC概覽
? ? ? ? NFC,全稱是Near Field Communication,中為近場通信,也叫做近距離無線通信技術(shù)。使用了NFC技術(shù)的設(shè)備(例如移動電話)可以在彼此靠近的情況下進(jìn)行數(shù)據(jù)交換,是由非接觸式射頻識別(RFID)及互連互通技術(shù)整合演變而來的,通過在單一芯片上集成感應(yīng)式讀卡器、感應(yīng)式卡片和點對點通信的功能,利用移動終端實現(xiàn)移動支付、電子票務(wù)、門禁、移動身份識別、防偽等應(yīng)用。
2、NFC工作原理
? ? ? ? NFC是一種短距高頻的無線電技術(shù),NFCIP-1標(biāo)準(zhǔn)規(guī)定NFC的通信距離為10厘米以內(nèi),運行頻率13.56MHz,傳輸速度有106Kbit/s、212Kbit/s或者424Kbit/s三種。NFCIP-1標(biāo)準(zhǔn)詳細(xì)規(guī)定NFC設(shè)備的傳輸速度、編解碼方法、調(diào)制方案以及射頻接口的幀格式,此標(biāo)準(zhǔn)中還定義了NFC的傳輸協(xié)議,其中包括啟動協(xié)議和數(shù)據(jù)交換方法等。
? ? ? ? NFC工作模式分為被動模式和主動模式。
? ? ? ? 1)被動模式
? ? ? ? 被動模式中NFC發(fā)起設(shè)備(也稱為主設(shè)備)需要供電設(shè)備,主設(shè)備利用供電設(shè)備的能量來提供射頻場,并將數(shù)據(jù)發(fā)送到NFC目標(biāo)設(shè)備(也稱作從設(shè)備),傳輸速率需在106kbps、212kbps或424kbps中選擇其中一種。從設(shè)備不產(chǎn)生射頻場,所以可以不需要供電設(shè)備,而是利用主設(shè)備產(chǎn)生的射頻場轉(zhuǎn)換為電能,為從設(shè)備的電路供電,接收主設(shè)備發(fā)送的數(shù)據(jù),并且利用負(fù)載調(diào)制(load modulation)技術(shù),以相同的速度將從設(shè)備數(shù)據(jù)傳回主設(shè)備。因為此工作模式下從設(shè)備不產(chǎn)生射頻場,而是被動接收主設(shè)備產(chǎn)生的射頻場,所以被稱作被動模式,在此模式下,NFC主設(shè)備可以檢測非接觸式卡或NFC目標(biāo)設(shè)備,與之建立連接。
? ? ? ? 2)主動模式
? ? ? ? 主動模式中,發(fā)起設(shè)備和目標(biāo)設(shè)備在向?qū)Ψ桨l(fā)送數(shù)據(jù)時,都必須主動產(chǎn)生射頻場,所以稱為主動模式,它們都需要供電設(shè)備來提供產(chǎn)生射頻場的能量。這種通信模式是對等網(wǎng)絡(luò)通信的標(biāo)準(zhǔn)模式,可以獲得非常快速的連接速率
3、NFC在Android上應(yīng)用
? ? ? ? 近距離無線通信 (NFC) 是一組近距離無線技術(shù),借助 NFC,您可以在 NFC 標(biāo)簽與 Android 設(shè)備之間或者兩臺 Android 設(shè)備之間共享小型負(fù)載。
? ? ? ? 標(biāo)簽的復(fù)雜度可能各有不同。簡單標(biāo)簽僅提供讀取和寫入語義,有時可使用一次性可編程區(qū)域?qū)⒖ㄆO(shè)置為只讀。較復(fù)雜的標(biāo)簽可提供數(shù)學(xué)運算,還可使用加密硬件來驗證對扇區(qū)的訪問權(quán)限。最為復(fù)雜的標(biāo)簽可包含操作環(huán)境,允許與針對標(biāo)簽執(zhí)行的代碼進(jìn)行復(fù)雜的互動。存儲在標(biāo)簽中的數(shù)據(jù)也可以采用多種格式編寫,但許多 Android 框架 API 都基于名為 NDEF(NFC 數(shù)據(jù)交換格式)的?NFC Forum?標(biāo)準(zhǔn)。
支持 NFC 的 Android 設(shè)備同時支持以下三種主要操作模式:
? ? ? ? 1)基本 NFC 任務(wù)
將 NDEF 數(shù)據(jù)與 Android 結(jié)合使用時,會有兩個主要用例:
- 從 NFC 標(biāo)簽讀取 NDEF 數(shù)據(jù)
- 使用Android Beam?將 NDEF 消息從一臺設(shè)備傳輸?shù)搅硪慌_設(shè)備
? ? ? ? 從 NFC 標(biāo)簽讀取 NDEF 數(shù)據(jù)的操作由標(biāo)簽調(diào)度系統(tǒng)進(jìn)行處理,該系統(tǒng)會分析已發(fā)現(xiàn)的 NFC 標(biāo)簽,對相應(yīng)數(shù)據(jù)進(jìn)行適當(dāng)分類,然后啟動對分類后的數(shù)據(jù)感興趣的應(yīng)用。如果某個應(yīng)用想要處理掃描到的 NFC 標(biāo)簽,則可以聲明 Intent 過濾器,并請求對數(shù)據(jù)進(jìn)行處理。
? ? ? ? 借助 Android Beam? 功能,設(shè)備可以將 NDEF 消息推送到另一臺設(shè)備,方法是將兩臺設(shè)備靠在一起。與藍(lán)牙等其他無線技術(shù)相比,這種互動可提供更簡便的數(shù)據(jù)發(fā)送方式,因為使用 NFC 時無需手動發(fā)現(xiàn)設(shè)備并將其配對。當(dāng)兩臺設(shè)備之間的距離近到一定范圍內(nèi)時,系統(tǒng)會自動開始連接。Android Beam 功能通過一組 NFC API 提供,因此任何應(yīng)用都可以在設(shè)備間傳輸信息。例如,通訊錄、瀏覽器和 YouTube 應(yīng)用可使用 Android Beam 在多臺設(shè)備之間共享聯(lián)系人信息、網(wǎng)頁和視頻。
? ? ? ? 標(biāo)簽調(diào)度系統(tǒng)
? ? ? ? Android 設(shè)備通常會在屏幕解鎖后查找 NFC 標(biāo)簽,除非設(shè)備的“設(shè)置”菜單中停用了 NFC 功能。在 Android 設(shè)備發(fā)現(xiàn) NFC 標(biāo)簽后,期望的行為就是讓最合適的 Activity 來處理該 Intent,而不是詢問用戶應(yīng)使用哪個應(yīng)用。
? ? ? ? 為幫助您實現(xiàn)這一目標(biāo),Android 提供了一個特殊的標(biāo)簽調(diào)度系統(tǒng),用于分析掃描到的 NFC 標(biāo)簽、解析它們并嘗試找到對掃描到的數(shù)據(jù)感興趣的應(yīng)用。這個標(biāo)簽調(diào)度系統(tǒng)通過以下操作來實現(xiàn)這些目的:
如何將 NFC 標(biāo)簽映射到 MIME 類型和 URI
? ? ? ? 在開始編寫 NFC 應(yīng)用之前,請務(wù)必了解不同類型的 NFC 標(biāo)簽、標(biāo)簽調(diào)度系統(tǒng)如何解析 NFC 標(biāo)簽,以及標(biāo)簽調(diào)度系統(tǒng)在檢測到 NDEF 消息后所執(zhí)行的特殊工作。NFC 標(biāo)簽涉及多種技術(shù),也可以通過許多不同的方式將數(shù)據(jù)寫入 NFC 標(biāo)簽中。Android 對 NFC Forum 定義的 NDEF 標(biāo)準(zhǔn)的支持最完備。
? ? ? ? NDEF 數(shù)據(jù)封裝在包含一條或多條記錄 (NdefRecord) 的消息 (NdefMessage) 內(nèi)。每條 NDEF 記錄的格式都必須正確,符合您要創(chuàng)建的記錄所屬的類型對應(yīng)的規(guī)范。Android 還支持其他類型的不包含 NDEF 數(shù)據(jù)的標(biāo)簽,您可以使用 android.nfc.tech 軟件包中的類處理這些標(biāo)簽。在處理這些其他類型的標(biāo)簽時,您需要通過編寫自己的協(xié)議棧來與標(biāo)簽進(jìn)行通信,因此,我們建議您盡可能使用 NDEF,以簡化開發(fā),同時最大限度地支持 Android 設(shè)備。
? ? ? ? 注意:要下載完整的 NDEF 規(guī)范,請轉(zhuǎn)到?NFC Forum 規(guī)范和應(yīng)用文檔網(wǎng)站,查看有關(guān)如何構(gòu)造 NDEF 記錄的示例。
? ? ? ? 現(xiàn)在,您已了解 NFC 標(biāo)簽的一些相關(guān)背景知識,以下幾部分將詳細(xì)介紹 Android 如何處理 NDEF 格式的標(biāo)簽。當(dāng) Android 設(shè)備掃描包含 NDEF 格式數(shù)據(jù)的 NFC 標(biāo)簽時,它會解析該消息并嘗試確定數(shù)據(jù)的 MIME 類型或起標(biāo)識作用的 URI。為此,系統(tǒng)需要讀取 NdefMessage 中的第一條 NdefRecord,以確定如何解讀整個 NDEF 消息(一個 NDEF 消息可能具有多條 NDEF 記錄)。在格式正確的 NDEF 消息中,第一條 NdefRecord 包含以下字段:
? ? ? ? a)、3 位 TNF(類型名稱格式)
表示如何解讀可變長度類型字段。表 1 中介紹了有效的值。
? ? ? ? b)、可變長度類型
介紹了記錄的類型。如果使用 TNF_WELL_KNOWN,那么請使用此字段來指定記錄類型定義 (RTD)。表 2 中介紹了有效的 RTD 值。
? ? ? ? c)、可變長度 ID
記錄的唯一標(biāo)識符。此字段并不經(jīng)常使用,但如果您需要對標(biāo)簽進(jìn)行唯一標(biāo)識,則可為其創(chuàng)建 ID。
? ? ? ? d)、可變長度負(fù)載
您要讀取或?qū)懭氲膶嶋H數(shù)據(jù)負(fù)載。一個 NDEF 消息可以包含多條 NDEF 記錄,因此不要假定 NDEF 消息的第一條 NDEF 記錄中就有完整的負(fù)載。
| 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,具體取決于您在類型字段中設(shè)置的記錄類型定義 (RTD)。如需詳細(xì)了解可用的 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 | 基于負(fù)載解析結(jié)果的 URI。 |
| RTD_TEXT | text/plain?的 MIME 類型。 |
| RTD_URI | 基于負(fù)載的 URI。 |
? ? ? ? 標(biāo)簽調(diào)度系統(tǒng)使用 TNF 和類型字段來嘗試將 MIME 類型或 URI 映射到 NDEF 消息。如果成功映射,它會將相關(guān)信息與實際負(fù)載一起封裝到 ACTION_NDEF_DISCOVERED Intent 內(nèi)。不過,在某些情況下,標(biāo)簽調(diào)度系統(tǒng)無法根據(jù)第一條 NDEF 記錄來確定數(shù)據(jù)的類型。如果 NDEF 數(shù)據(jù)無法映射到 MIME 類型或 URI,或者 NFC 標(biāo)簽不包含 NDEF 數(shù)據(jù),就會出現(xiàn)上述情況。在此類情況下,標(biāo)簽調(diào)度系統(tǒng)會轉(zhuǎn)而將含有標(biāo)簽技術(shù)相關(guān)信息的 Tag 對象及負(fù)載封裝到ACTION_TECH_DISCOVERED Intent 中。
? ? ? ? 表 1 介紹了標(biāo)簽調(diào)度系統(tǒng)如何將 TNF 和類型字段映射到 MIME 類型或 URI,還介紹了哪些 TNF 無法映射到 MIME 類型或 URI。如果無法映射,標(biāo)簽調(diào)度系統(tǒng)會回退到 ACTION_TECH_DISCOVERED。
? ? ? ? 例如,如果標(biāo)簽調(diào)度系統(tǒng)遇到 TNF_ABSOLUTE_URI 類型的記錄,則會將該記錄的可變長度類型字段映射到 URI 中。標(biāo)簽調(diào)度系統(tǒng)將此 URI 連同與標(biāo)簽有關(guān)的其他信息(如負(fù)載)一起封裝在 ACTION_NDEF_DISCOVERED Intent 的數(shù)據(jù)字段中。另一方面,如果標(biāo)簽調(diào)度系統(tǒng)遇到 TNF_UNKNOWN 類型的記錄,則會轉(zhuǎn)而創(chuàng)建一個 Intent,用于封裝與標(biāo)簽技術(shù)相關(guān)的信息。
如何將 NFC 標(biāo)簽分發(fā)到應(yīng)用
當(dāng)標(biāo)簽調(diào)度系統(tǒng)創(chuàng)建完用于封裝 NFC 標(biāo)簽及其標(biāo)識信息的 Intent 后,它會將該 Intent 發(fā)送給感興趣的應(yīng)用,由這些應(yīng)用對其進(jìn)行過濾。如果有多個應(yīng)用可處理該 Intent,系統(tǒng)會顯示 Activity 選擇器,供用戶選擇要使用的 Activity。標(biāo)簽調(diào)度系統(tǒng)定義了三種 Intent,按優(yōu)先級從高到低列出如下:
標(biāo)簽調(diào)度系統(tǒng)的基本工作方式如下:
? ? ? ? ?盡可能使用 NDEF 消息和 ACTION_NDEF_DISCOVERED Intent,因為它是三種 Intent 中最具體的一種。與其他兩種 Intent 相比,此 Intent 可使您在更恰當(dāng)?shù)臅r間啟動應(yīng)用,從而為用戶帶來更好的體驗。
? ? ? ? 在 Android 清單中請求 NFC 訪問權(quán)限
? ? ? ? 您必須先在?AndroidManifest.xml?文件中聲明以下內(nèi)容,然后才能訪問設(shè)備的 NFC 硬件并正確處理 NFC Intent:
- 用于訪問 NFC 硬件的 NFC?<uses-permission>?元素:
- 您的應(yīng)用支持的最低 SDK 版本。API 級別 9 僅通過 ACTION_TAG_DISCOVERED 支持有限的標(biāo)簽調(diào)度,并且只能通過 EXTRA_NDEF_MESSAGES extra 提供對 NDEF 消息的訪問權(quán)限。無法訪問其他任何標(biāo)簽屬性或 I/O 操作。API 級別 10 提供全面的讀取器/寫入器支持以及前臺 NDEF 推送功能;API 級別 14 則提供了一種更簡便的方式(即,使用 Android Beam 將 NDEF 消息推送到其他設(shè)備),同時提供了用于創(chuàng)建 NDEF 記錄的其他便捷方法。
- uses-feature?元素,以便您的應(yīng)用僅在那些具備 NFC 硬件的設(shè)備的 Google Play 中顯示:
? ? ? ? ?如果您的應(yīng)用使用 NFC 功能,但該功能對您的應(yīng)用來說并不重要,您可以省略 uses-feature 元素,并在運行時通過檢查 getDefaultAdapter() 是否為 null 來了解 NFC 的可用性。
? ? ? ? 過濾 NFC Intent
? ? ? ? 要在掃描到您打算處理的 NFC 標(biāo)簽時啟動您的應(yīng)用,您的應(yīng)用可以在 Android 清單中過濾一個、兩個或所有三個 NFC Intent。不過,您通常需要過濾 ACTION_NDEF_DISCOVERED Intent,以最有力地控制應(yīng)用在何時啟動。如果沒有應(yīng)用過濾 ACTION_NDEF_DISCOVERED,或者負(fù)載不是 NDEF,ACTION_TECH_DISCOVERED Intent 會取代 ACTION_NDEF_DISCOVERED。ACTION_TAG_DISCOVERED 通常因過于籠統(tǒng)而不適合過濾。許多應(yīng)用會在過濾 ACTION_TAG_DISCOVERED 前過濾 ACTION_NDEF_DISCOVERED 或 ACTION_TECH_DISCOVERED,導(dǎo)致 您的應(yīng)用啟動的概率會比較低。過濾 ACTION_TAG_DISCOVERED 是應(yīng)用在沒有其他應(yīng)用來處理 ACTION_NDEF_DISCOVERED 或 ACTION_TECH_DISCOVERED Intent 的情況下的最后一道保險。
? ? ? ? 由于 NFC 標(biāo)簽部署各有不同,并且很多時候它們都不由您控制,因此,ACTION_NDEF_DISCOVERED 不一定每次都可用,您可以根據(jù)需要回退到另外兩種 Intent。如果您可以控制標(biāo)簽和寫入數(shù)據(jù)的類型,建議您使用 NDEF 來設(shè)置標(biāo)簽的格式。以下幾部分介紹了如何過濾各類 Intent。
- ACTION_NDEF_DISCOVERED
? ? ? ? 要過濾 ACTION_NDEF_DISCOVERED Intent,請聲明 Intent 過濾器以及要過濾的數(shù)據(jù)類型。以下示例展示了如何過濾 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,您必須創(chuàng)建一個 XML 資源文件,用它在 tech-list 集內(nèi)指定您的 Activity 所支持的技術(shù)。如果 tech-list 集是標(biāo)簽所支持的技術(shù)(可通過調(diào)用 getTechList() 來獲取)的子集,則您的 Activity 會被視為一個匹配項。
? ? ? ? 例如,如果掃描到的標(biāo)簽支持 MifareClassic、NdefFormatable 和 NfcA,為了使它們與您的 Activity 匹配,您的 tech-list 集必須指定所有這三種技術(shù),或者其中的兩種或一種技術(shù)。
? ? ? ? 以下示例定義了所有技術(shù)。您可以移除自己不需要的技術(shù)。將此文件(你可以隨便命名)保存到 <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() 返回的技術(shù)的子集,則您的 Activity 會被視為一個匹配項。這為匹配技術(shù)提供了 AND 和 OR 語義。以下示例展示了如何與支持 NfcA 和 Ndef 技術(shù)的標(biāo)簽或者支持 NfcB 和 Ndef 技術(shù)的標(biāo)簽相匹配:
<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>?元素中指定您剛剛創(chuàng)建的資源文件,如以下示例所示:
<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>? ? ? ??如需詳細(xì)了解如何使用標(biāo)簽技術(shù)和 ACTION_TECH_DISCOVERED Intent,請參閱高級 NFC 文檔中的使用支持的標(biāo)簽技術(shù)(以后寫)。
-
ACTION_TAG_DISCOVERED
? ? ? ? 要過濾 ACTION_TAG_DISCOVERED,請使用以下 Intent 過濾器:
<intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED"/></intent-filter>-
從 Intent 中獲取信息
? ? ? ? 如果某個 Activity 由于 NFC Intent 而啟動,您可以從該 Intent 中獲取有關(guān)掃描到的 NFC 標(biāo)簽的信息。Intent 可以包含以下 extra,具體取決于掃描到的標(biāo)簽:
- EXTRA_TAG(必需):一個 Tag 對象,表示掃描到的標(biāo)簽。
- EXTRA_NDEF_MESSAGES(可選):從標(biāo)簽中解析出的一組 NDEF 消息。此 extra 對于 ACTION_NDEF_DISCOVERED Intent 而言是必需的。
- EXTRA_ID(可選):標(biāo)簽的低級別 ID。
? ? ? ? 要獲取這些 extra,請檢查您的 Activity 是不是使用某個 NFC Intent 啟動的,以確保已掃描到標(biāo)簽,然后獲取 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 對象,該對象包含負(fù)載并允許您枚舉標(biāo)簽的技術(shù):
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);? ? ? ? 創(chuàng)建常見類型的 NDEF 記錄?
? ? ? ? 本部分介紹了如何創(chuàng)建常見類型的 NDEF 記錄,以幫助向 NFC 標(biāo)簽寫入數(shù)據(jù)或使用 Android Beam 發(fā)送數(shù)據(jù)。從 Android 4.0(API 級別 14)開始引入平臺的 createUri() 方法可幫助您自動創(chuàng)建 URI 記錄。從 Android 4.1(API 級別 16)開始引入平臺的 createExternal() 和 createMime() 可幫助您創(chuàng)建 MIME 和外部類型的 NDEF 記錄。請盡可能使用這些輔助方法,以免在手動創(chuàng)建 NDEF 記錄時出錯。
? ? ? ? 本部分還介紹了如何為記錄創(chuàng)建相應(yīng)的 Intent 過濾器。所有這些 NDEF 記錄示例都應(yīng)該位于您寫入標(biāo)簽或傳輸?shù)搅硪辉O(shè)備的 NDEF 消息的第一條 NDEF 記錄中。
? ? ? ? a)、TNF_ABSOLUTE_URI
注意:建議您使用 RTD_URI 類型,而不是 TNF_ABSOLUTE_URI,因為前者更為高效。
您可以通過以下方式創(chuàng)建一條 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?
您可以通過以下方式創(chuàng)建一條 TNF_MIME_MEDIA NDEF 記錄:
使用 createMime() 方法:
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam","Beam me up, Android".getBytes(Charset.forName("US-ASCII")));手動創(chuàng)建 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
您可以通過以下方式創(chuàng)建一條 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
您可以通過以下方式創(chuàng)建一條 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);?手動創(chuàng)建 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 實現(xiàn)更通用的 NFC 標(biāo)簽部署,以更好地支持 Android 設(shè)備和非 Android 設(shè)備。
? ? ? ? 注意:TNF_EXTERNAL_TYPE 的 URN 的規(guī)范格式為urn:nfc:ext:example.com:externalType,但 NFC Forum RTD 規(guī)范包含如下聲明:NDEF 記錄中必須省略 URN 的?urn:nfc:ext:?部分。因此,您只需要提供域名(示例中為?example.com)和類型(示例中為?externalType),并通過英文冒號將兩者分隔開。分發(fā)?TNF_EXTERNAL_TYPE?時,Android 會將?urn:nfc:ext:example.com:externalType?URN 轉(zhuǎn)換為?vnd.android.nfc://ext/example.com:externalType?URI,也就是示例中的 Intent 過濾器聲明的 URI。
? ? ? ? e)、Android 應(yīng)用記錄
? ? ? ? Android 4.0(API 級別 14)中引入了 Android 應(yīng)用記錄 (AAR) 功能,它可以更有力地確保在掃描到 NFC 標(biāo)簽時啟動您的應(yīng)用。AAR 在 NDEF 記錄內(nèi)嵌入了應(yīng)用的軟件包名稱。您可以將 AAR 添加到 NDEF 消息的任意 NDEF 記錄中,因為 Android 會在整個 NDEF 消息中搜索 AAR。如果找到 AAR,它會根據(jù) AAR 中的軟件包名稱啟動相應(yīng)應(yīng)用。如果設(shè)備上沒有該應(yīng)用,則會啟動 Google Play,供用戶下載該應(yīng)用。
? ? ? ? 如果您想要阻止其他應(yīng)用過濾同一 Intent,并阻止其他應(yīng)用潛在地處理您已部署的特定標(biāo)簽,則可以使用 AAR。由于軟件包名稱方面的限制,AAR 僅在應(yīng)用級別受支持,與 Intent 過濾一樣在 Activity 級別不受支持。如果您需要在 Activity 級別處理 Intent,可使用 Intent 過濾器。
? ? ? ? 如果標(biāo)簽包含 AAR,標(biāo)簽調(diào)度系統(tǒng)將按以下方式執(zhí)行分發(fā):
? ? ? ? 注意:您可以使用前臺調(diào)度系統(tǒng)替換 AAR 和 Intent 調(diào)度系統(tǒng),以便在發(fā)現(xiàn) NFC 標(biāo)簽后優(yōu)先啟動前臺 Activity。使用此方法時,Activity 必須在前臺運行才能替換 AAR 和 Intent 調(diào)度系統(tǒng)。
? ? ? ? 如果您仍希望過濾掃描到的不包含 AAR 的標(biāo)簽,則可以照常聲明 Intent 過濾器。如果您的應(yīng)用對其他不包含 AAR 的標(biāo)簽感興趣,這將非常有用。例如,您可能需要保證您的應(yīng)用能夠處理由您部署的專有標(biāo)簽以及由第三方部署的常規(guī)標(biāo)簽。請注意,AAR 特定于搭載 Android 4.0 或更高版本的設(shè)備,因此,在部署標(biāo)簽時,您很可能需要將 AAR 和 MIME 類型/URI 結(jié)合使用,以支持各種設(shè)備。此外,在部署 NFC 標(biāo)簽時,請考慮:要如何編寫 NFC 標(biāo)簽,才能使其支持大多數(shù)設(shè)備(Android 設(shè)備和其他設(shè)備)。為此,您可以定義相對唯一的 MIME 類型或 URI,從而使應(yīng)用更容易區(qū)分它們。
? ? ? ? Android 提供了 createApplicationRecord() 這個簡單的 API 來創(chuàng)建 AAR。您只需將 AAR 嵌入 NdefMessage 中的任意位置即可。您不需要使用 NdefMessage 的第一條記錄,除非 AAR 是 NdefMessage 中唯一的記錄。這是因為 Android 系統(tǒng)會檢查 NdefMessage 的第一條記錄,以此來確定標(biāo)簽的 MIME 類型或 URI;在創(chuàng)建應(yīng)用要過濾的 Intent 時需要用到標(biāo)簽的 MIME 類型或 URI。以下代碼展示了如何創(chuàng)建 AAR:
NdefMessage msg = new NdefMessage(new NdefRecord[] {...,NdefRecord.createApplicationRecord("com.example.android.beam")});)? ? ? ? 向其他設(shè)備傳輸 NDEF 消息?
? ? ? ? Android Beam 可在兩臺 Android 設(shè)備之間進(jìn)行簡單的點對點數(shù)據(jù)交換。需要將數(shù)據(jù)傳輸?shù)搅硪慌_設(shè)備的應(yīng)用必須在前臺運行,并且要接收數(shù)據(jù)的設(shè)備不得處于鎖定狀態(tài)。當(dāng)傳輸設(shè)備與接收設(shè)備的距離足夠近時,傳輸設(shè)備會顯示“觸摸即可傳輸”界面。然后,用戶可以選擇是否將消息傳輸?shù)浇邮赵O(shè)備。
? ? ? ? 注意:API 級別 10 中提供前臺 NDEF 推送,其功能與 Android Beam 類似。此后,這些 API 已棄用,但可用于支持舊設(shè)備。如需了解詳情,請參閱?enableForegroundNdefPush()。
? ? ? ? 調(diào)用以下兩種方法之一可為您的應(yīng)用啟用 Android Beam:
- setNdefPushMessage():接受 NdefMessage 以將其設(shè)置為待傳輸?shù)南ⅰT趦膳_設(shè)備的距離足夠接近時自動傳輸消息。
- setNdefPushMessageCallback():接受包含 createNdefMessage()(在設(shè)備處于可接收數(shù)據(jù)的范圍內(nèi)時調(diào)用)的回調(diào)。該回調(diào)支持您根據(jù)需要創(chuàng)建 NDEF 消息。
? ? ? ? Activity 一次只能推送一個 NDEF 消息,因此,如果設(shè)置了兩個 NDEF 消息,setNdefPushMessageCallback() 將優(yōu)先于 setNdefPushMessage()。要使用 Android Beam,必須滿足以下一般準(zhǔn)則:
- 傳輸數(shù)據(jù)的 Activity 必須在前臺運行。兩臺設(shè)備的屏幕都必須處于解鎖狀態(tài)。
- 必須將要傳輸?shù)臄?shù)據(jù)封裝到 NdefMessage 對象中。
- 接收傳輸數(shù)據(jù)的 NFC 設(shè)備必須支持 com.android.npp NDEF 推送協(xié)議或 NFC Forum 的 SNEP(簡單 NDEF 交換協(xié)議)。API 級別 9 (Android 2.3) 到 API 級別 13 (Android 3.2) 的設(shè)備都需要使用 com.android.npp 協(xié)議。API 級別 14 (Android 4.0) 及更高版本的設(shè)備需要使用 com.android.npp 和 SNEP。
? ? ? ? 注意:如果您的 Activity 支持 Android Beam 且在前臺運行,則標(biāo)準(zhǔn) Intent 調(diào)度系統(tǒng)將停用。不過,如果您的 Activity 也支持前臺調(diào)度,那么它仍然可以掃描與前臺調(diào)度中設(shè)置的 Intent 過濾器相匹配的標(biāo)簽。
? ? ? ? 要啟用 Android Beam,請執(zhí)行以下操作:
? ? ? ? 以下示例展示了一個簡單 Activity 如何調(diào)用 Activity 的 onCreate() 方法中的 NfcAdapter.CreateNdefMessageCallback。此示例還提供了一些方法來幫助您創(chuàng)建 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 中指定的應(yīng)用始終會收到 Android Beam 消息。如果該應(yīng)用不存在,則會啟動 Google Play,請用戶下載該應(yīng)用。因此,對于搭載 Android 4.0 及更高版本的設(shè)備(如果使用了 AAR)而言,以下 Intent 過濾器在技術(shù)上是不需要的:?
<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?應(yīng)用現(xiàn)在可以在以下情況下啟動:掃描到 NFC 標(biāo)簽或通過 Android Beam 接收到類型為 的 AAR,或者在 NDEF 格式的消息包含類型為?application/vnd.com.example.android.beam?的 MIME 記錄時。
? ? ? ? 即使 AAR 能夠保證啟動或下載應(yīng)用,但我們?nèi)越ㄗh您使用 Intent 過濾器,因為它們允許您在應(yīng)用中啟動所選的 Activity,而不是始終啟動由 AAR 指定的軟件包內(nèi)的主 Activity。AAR 不具備 Activity 級別的粒度。此外,由于某些 Android 設(shè)備不支持 AAR,因此您還應(yīng)在 NDEF 消息的第一條 NDEF 記錄中嵌入標(biāo)識信息,以便在需要時進(jìn)行過濾。
?4、NFC與其他技術(shù)的比較
? ? ? ? 目前的近距離無線通信技術(shù)包括了RFID、藍(lán)牙、紅外等, NFC是一種短距離的高頻無線通訊技術(shù),電子設(shè)備之間允許進(jìn)行非接觸式點對點數(shù)據(jù)傳輸。其工作頻率為 13.56MHz,通信距離 0~20cm(實際大部分產(chǎn)品都在 10cm 以內(nèi)),傳輸速率可為106kbit/s、212kbit/s、424 kbit/s和848kbit/s。近距無線通信技術(shù)除NFC外,主要還包括射頻識別(RFID)、藍(lán)牙(Bluetooth)、紫蜂(ZigBee)、紅外、 Wi-Fi等技術(shù)。以上各項技術(shù)都有各自的特點和優(yōu)點,下圖給出了 NFC 以及其他六種幾種短距離無線通信技術(shù)在所列頻段上性能的比較。
?
? ? 可以看出,NFC 技術(shù)具有極高的安全性,在短距離通信中具有性能優(yōu)勢,更重要的是成本較低,因此自其 2003 年問世以來,得到眾多企業(yè)的關(guān)注和支持。
? ? ? ? NFC與RFID的比較
? ? ? ? 第一,工作模式不同。NFC是將點對點通信功能,讀寫器功能和非接觸卡功能集成進(jìn)一顆芯片,而RFID則有閱讀器和標(biāo)簽兩部分組成。NFC技術(shù)既可以讀取也可以寫入,而RFID只能實現(xiàn)信息的讀取以及判定。 [2]?
? ? ? ? 第二,傳輸距離不同。NFC傳輸距離比RFID小的多,NFC 的傳輸距離只有10厘米,RFID的傳輸距離可以達(dá)到幾米、甚至幾十米。NFC是一種近距離的私密通信方式,相對于RFID來說NFC具有距離近、帶寬高、能耗低、安全性高等特點。 [2]?
? ? ? ? 第三,應(yīng)用領(lǐng)域不同。NFC更多的應(yīng)用于消費類電子設(shè)領(lǐng)域,在門禁、公交、手機支付等領(lǐng)域發(fā)揮著巨大的作用;RFID則更擅長于長距離識別,更多的被應(yīng)用在生產(chǎn)、物流、跟蹤、資產(chǎn)管理上。 [2]?
? ? ? ? 近場通信NFC與藍(lán)牙的比較
? ? ? ? NFC和藍(lán)牙都是短程通信技術(shù),相對于藍(lán)牙很早就被集成到移動電話中并已經(jīng)被普及,NFC最近幾年才開始被集成進(jìn)移動電話中,并且到目前為止只集成在少數(shù)移動電話中。 [2]?
? ? ? ? 第一,建立時間不同,NFC通信設(shè)置程序簡單,通信建立時間很短,僅需0.1s左右;而藍(lán)牙通信設(shè)置程序相對復(fù)雜,通信建立時間較長,大概需要6s。 [2]?
? ? ? ? 第二,傳輸距離不同,NFC傳輸距離只有10cm,而藍(lán)牙傳輸距離可達(dá)10m。但NFC在傳輸功耗和安全性方面略優(yōu)于藍(lán)牙。 [2]?
? ? ? ? 第三,傳輸速度和工作頻率不同,NFC工作頻率為13.56MHz, 傳輸速度最大424 Kbit/s,而藍(lán)牙工作頻率為2.4GHz,傳輸速度可 達(dá)2.1 Mbit/s。 [2]?
? ? ? ? 近場通信NFC與紅外的比較
NFC和紅外傳輸相比,傳輸距離相當(dāng),但比紅外傳輸速度更快,NFC傳輸速度最大可達(dá)424 Kbit/s,而紅外傳輸速度大概 100Kbit/s。建立時間NFC比紅外略快,NFC建立時間為0.1s, 紅外傳輸建立時間為0.5s。紅外傳輸必須嚴(yán)格的對齊才能傳輸數(shù)據(jù),且中間不能有障礙物,而NFC則沒有這種限制;另外NFC比紅外更安全可靠。
總結(jié)
以上是生活随笔為你收集整理的Android NFC详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASA 第五天实验
- 下一篇: python tkinter butto