NFC 基礎知識(NFC Basics) 根據官網個人翻譯

此文爲我一時興起花費將近兩天翻譯,肯定問題多多,慢慢完善,敬請諒解。

官網原文鏈接:https://developer.android.com/guide/topics/connectivity/nfc/nfc.html#creating-records

NFC 基礎知識(NFC Basics


NFC : Near Field Communication 近場通訊

這篇文檔介紹了你在安卓裏運行的NFC的基本任務。它解釋瞭如何在NDEF消息形式下發送和接收NFC數據,並且描述了支持此項功能的Android框架層的API。更多高級的主題,包括處理non-NDEF數據的討論,請參閱高級NFC

這裏有兩個在Android中處理NDEF數據的主要的案例 
  • 從NFC tag裏讀取數據
  • 通過Android Beam將NDEF消息從一臺設備發送到另一臺設備

從NFC tag讀取到的數據將被tag dispatch system(標籤調度/發佈系統)處理,分析發現的NFC  tag併爲其適當的分類,然後啓動一個與分類數據相匹配的應用。想要處理掃描到的NFC 標籤的應用會聲明一個intent filter(意圖過濾器)並要求處理數據。

Android Beam功能允許一個設備通過(by physically tapping the devices together)推送NDEF消息給另一個設備。這種交互提供了一種更爲簡單的方式,相比其他無線技術例如藍牙,有了NFC,無需手動去發現和配對設備。這種連接會在兩個設備進入相互範圍之內的時候自動啓動。Android Beam可以通過設置一組NFC API得到,所以兩個設備間的任何應用都可以傳輸數據。例如,聯繫人、瀏覽器或者是YouTuBe應用通過Android Beam與其他設備共享聯繫人,網頁或者視頻。

標籤發佈系統(The Tag Dispatch System)

安卓設備通常在屏幕已解鎖的情況下來尋找NFC  tag,除非NFC功能在設備的設置菜單中被關閉。當安卓設備發現了NFC tag,通常的行爲是讓一個最合適的activity來處理這個intent而不會詢問用戶啓動哪一個應用。因爲設備掃描NFC tag是在一個非常小的範圍內,讓用戶手動選擇一個activity會迫使他們移動設備並更有可能讓設備遠離tag 也因此導致連接被斷開。你應該讓你的activity只處理其所關心的NFC tag,避免出現選擇Activity(Activity Chooser)的狀況。

爲了幫助你達到目標,Androidi提供了一個特殊的tag發佈系統來分析掃描的NFC tag,解析他們,並嘗試定位/找出與掃描數據最匹配的應用。大致是通過:
  1. 解析NFC tag並找出MIME類型或者標識一個tag有效負載的URI。
  2. 將MIME類型或者URI以及有效負載封裝到一個intent。前兩個步驟在How NFC tags are mapped to MIME types and URIs裏描述了。
  3. 通過intent啓動一個activity。這個在 How NFC Tags are Dispatched to Applications有說明。

NFC tag如何映射MIME 類型和URI(How NFC tags are mapped to MIME types and URIs)

在你開始寫你的NFC應用之前,理解NFC tag之間的差異很重要,tag diapatch system如何解析tag,以及它發現NDEF消息之後所做的工作。NFC tag在一系列廣泛的技術中流行(come in),也能讓數據通過不同的方式被寫入。Android最大程度的支持NFC論壇定義的NDEF標準。

NDEF數據被封裝到一個包含一個或多個記錄的消息(message)裏。每一個NDEF記錄必須符合類型記錄的相關規範,如果你想創建創建一個的話。Android也支持其它不包含NDEF數據的tag,而這些你可以通過使用android.nfc.tech包下面的類來實現。想學習更多這方面的技術,可以參看高級NFC主題。使用其他類型的 tag意味着你要書寫自己的協議來和這些 tag通訊,所以我們建議使用NDEF類型,在追求儘可能簡單的開發情況下,並且它被大多數安卓設備所支持。
  1. 記錄:要下載完整的NDEF規範請到NFC Forum Specification Download網址,通過查閱Creating common types of NDEF records得知如何構建NDEF記錄。
既然你已經有了一定的背景知識,那麼接下來的章節更多的要描述Android怎樣處理NDEF格式化標籤。當安卓設備掃描到包含NDEF格式化標籤的NFC tag,它解析消息並找出數據的MIME類型或者標誌性URI。爲了做到這一點,系統會讀取到NdefMessage裏面的第一條NdefRecord來決定怎麼解釋整個NDEF消息(一個NDEF消息可以包含許多NDEF記錄)。一個形式良好的NDEF消息第一條NdefRecord包含如下的幾個字段:

3字節的TNF(格式化類型名字)(3-bit TNF (Type Name Format)

        標示怎樣解釋可變長度類型字段。有效值請見表1。

可變長度類型(Variable length type

        描述記錄的類型。如果使用TNF_WELL_KNOWN,用這個字段指定記錄類型定義(RTD: Record Type Definition )。
        有效的RTD值請見表2.

可變長度的ID(Variable length ID

       記錄唯一的標識。這個字段不常被使用,但那時如果你需要唯一標識一個tag,你可以爲它創建一個ID.

可變長度的有效負載(Variable length payload

        你想讀或寫的真實數據有效負載。一個NDEF消息能包含許多NDEF記錄,所以不要佔用NDEF消息的第一條NDEF記錄的所有有效負載。

標籤發佈系統( tag dispatch system)使用TNF和類型字段來(試着)映射MIME類型或者URI到相應的MDEF消息。如果成功了,它會將信息連同有效負載一起壓縮到一個ACTION_NDEF_DISCOVER的intent中。然而,也會有許多標籤發佈系統根據第一條NDEF記錄不能完全確定數據類型的情況。這種情況發生在MDEF數據不能映射到一個MIME類型或URI,或者NFC tag的沒有以包含NDEF數據作爲起始。在這種情況下,一個包含tag技術和有效負載相關信息的Tag對象會被封裝到一個ACTION_NDEF_DISCOVER的intent中instaead)。

表1.描述了tag dispatch system如何映射TNF和類型字段到MIME類型或者URI。它也描述了那些TNF不能被映射到MIME類型或者URI。在這些情況下,tag dispatch system(falls back to)ACTION_TECH_DISCOVER.。

例如,當tag dispatch system遇到一個TNF_ABSOLUTE_URI類型的記錄,它映射這條記錄的可變長度類型字段到URI。tag dispatch system壓縮ACTION_DNEF_DISCOVER類型的intent的數據字段中的URI連同有關這個tag的其他信息,如有效負載。另一方面,如果遇到TNF_UNKNOWN類型的記錄,它將創建一個壓縮了tag技術的intent來替代。

表1.支持的TNF和他們的映射。
類型名稱(Type Name Format)(TNF) 映射(Mapping)
TNF_ABSOLUTE_URI 基於該類型字段的URI.
TNF_EMPTY 回落到ACTION_TECH_DISCOVERED
TNF_EXTERNAL_TYPE 基於該類型字段的URN的URI。URN以一種簡短的形式被編碼到NDEF類型字段中:<domain_name>:<service_name> 。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),參閱表2。獲取更多可獲得的RTD值和對應的映射。

表2.支持的TNF爲TNF_WELL_KNOWN時的RTD和對應的映射。
Record Name Definition(RTD) Mapping
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

NFC 標籤如何被分派到應用程序(How NFC Tags are Dispatched to Applications)

當 tag dispatch system創建完一個封裝有NFC tag和它的標識信息的intent之後,它會將該intent發送給通過此intent過濾出來並與之匹配的應用程序。如果有多個應用可以處理該intent,會彈出選擇界面以供用戶選擇。tag dispatch system 定義了三種intent,按優先級高低分別爲:
1. ACTION_NDEF_DISCOVER:這個intent在掃描到一個包含NDEF有效負載的tag時通常會啓動一個Activity,並且是公認的一種類型。它的優先級最高,因此tag dispatch system不管在任何情況下都會用這個intent並在其它intent之前 盡全力去啓動一個Activity(即:只要有這個intent,任何情況下都優先處理它)。
2. ACTION_TECH_DISCOVER:如果沒有activity要去處理ACTION_NDEF_DISCOVER類型的intent(即:沒有這種intent),tag dispatch system會通過這個intent(即ACTION_TECH_DISCOVER類型的)去啓動一個應用程序。在掃描到包含不能被映射到MIME類型或者URI的NDEF數據或者不包含NDEF數據但是是一種已知的tag技術的tag時,這種intent立即就會被啓動(前提是沒有ACTION_NDEF_DISCOVER類型的)。
3. ACTION_TAG_DISCOVER:這種intent在既沒有ACTION_NDEF_DISCOVER也沒有ACTION_TECH_DISCOVER的時候會被啓動。

tag dispatch system工作的基本流程如下:
1. 通過在解析NFC tag時由它自己創建的intent去啓動一個Activity(ACTION_NDEF_DISCOVER或ACTION_TECH_DISCOVER)。
2. 如果沒有與intent匹配的activity,那麼就嘗試通過下一個最低優先級的intent啓動Activity(ACTION_TECH_DISCOVER或ACTION_TAG_DISCOVER),直到找出匹配的應用程序或者它嘗試所有可能intent但沒有匹配結果。
3. 如果最終都沒有找到匹配的應用程序,就什麼都不做。

                                                                            圖1. Tag Dispatch System

儘可能使用NDEF消息和ACTION_NDEF_DISCOVER類型的intent,因爲它是最特殊的一個。這個intent相比其他兩種intent允許你在更合適的時間啓動你的應用程序,給用戶更好的體驗。

在Manifest文件中聲明NFC權限(Requesting NFC Access in the Android Manifest)

在你得到一個帶有NFC功能的設備並正確處理NFC intent之前,先在你的AndroidManifest.xml文件中聲明這些項:
  • NFC用戶權限 以用來訪問NFC硬件:
  1. <uses-permission android:name="android.permission.NFC" />
  • 你的應用程序支持的最小SDK版本。API 9僅僅支持ACTION_TAG_DISCOVERED,而且只允許ERTRA_NDEF_MESSAGE類型的NDEF消息。沒有其他標籤屬性或者I/O操作可以做到。API 10支持讀/寫以及前臺NDEF推送,而到API 14則提供了一種更簡單的 即通過Android Beam來推送NDEF消息,還有其他一些便利的創建NDEF記錄的方法。
  1. <uses-sdk android:minSdkVersion="10"/>
  • uses-feature元素能讓你的應用在谷歌商店中顯示在有NFC硬件的設備上:
  1. <uses-feature android:name="android.hardware.nfc" android:required="true" />
如果你的應用是用的NFC功能,但是它對你又不是那麼重要,那你就可以忽略uses-feature元素,只是需要在運行時通過判斷getDefaultAdapter()是否爲空來檢測設備是否支持NFC。

NFC intent過濾(Filtering for NFC Intents)

爲了在掃描到你希望處理的NFC tag並啓動你的應用,你可以在你應用的Android Manifeat裏面過濾一種、兩種或者是三種全部的NFC intent。然而,你通常需要在你的應用啓動時爲ACTION_NDEF_DISCOVER intent篩選。ACTION_TECH_DISCOVER類型的intent是ACTION_NDEF_DISCOVER 在沒有找到與它(的 intent)相匹配的應用程序或者有效負載不是NDEF的時候的備用選擇。而 ACTION_TAG_DISCOVER類型通常用於對過於籠統的類別進行過濾。 許多應用程序會在ACTION_TAG_DISCOVER之前過濾出ACTION_NDEF_DISCOVER 或者ACTION_TECH_DISCOVER,所以你的應用被啓動的可能性更低。ACTION_TAG_DISCOVER是在應用程序沒有ACTION_NDEF_DISCOVER 和ACTION_TECH_DISCOVER類型intent的時候的最後手段。
因爲NFC tag部署多樣並且經常不受控制,這並不總是出現,但這是爲什麼在必要的時候你要依靠其他兩種intent。當你掌握了各種類型的標籤和數據寫入,建議你用NDEF格式化你的標籤。接下來的章節描述瞭如何過濾各種類型的intent。

ACTION_NDEF_DISCOVERED

爲了ACTION_NDEF_DISCOVER類型的intent過濾,根據你想過濾的數據類型聲明intent-filter。接下來是MIME type爲textview/plain的ACTION_NDEF_DISCOVERED 類型的intent的filter示例:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  3. <category android:name="android.intent.category.DEFAULT"/>
  4. <data android:mimeType="text/plain" />
  5. </intent-filter>
下面是形如【http://developer.android.com/index.html】的URI的filter示例:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  3. <category android:name="android.intent.category.DEFAULT"/>
  4. <data android:scheme="http"
  5. android:host="developer.android.com"
  6. android:pathPrefix="/index.html" />
  7. </intent-filter>

ACTION_TECH_DISCOVERED

如果你activity的filter是爲了ACTION_TECH_DISCOVERED類型的intent,那你必須要創建一個通過tech-list集合來指定你的activity支持的技術的XML資源文件。如果你的tech-list是被tag支持技術集合的一個子集,那麼你的activity會被考慮匹配,這個技術集合你可以通過getTechList()得到。
例如,如果被掃描的tag支持MifareClasic、MdefFormatable和NfcA,那麼爲了你的activity被匹配上 你的tech-list必須指定這三個技術而不是兩個、一個或者一個都不指定。
下面的例子定義了所有的技術。你可以移除你不需要的。保存這個文件(你可以爲它隨意命名)到<project-root>/res/xml路徑下邊。
  1. <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  2. <tech-list>
  3. <tech>android.nfc.tech.IsoDep</tech>
  4. <tech>android.nfc.tech.NfcA</tech>
  5. <tech>android.nfc.tech.NfcB</tech>
  6. <tech>android.nfc.tech.NfcF</tech>
  7. <tech>android.nfc.tech.NfcV</tech>
  8. <tech>android.nfc.tech.Ndef</tech>
  9. <tech>android.nfc.tech.NdefFormatable</tech>
  10. <tech>android.nfc.tech.MifareClassic</tech>
  11. <tech>android.nfc.tech.MifareUltralight</tech>
  12. </tech-list>
  13. </resources>
你可以指定多個tech-list集合。每一個都會被單獨考慮,只要任何一個是getTechList()的子集你的activity都會被考慮匹配。這裏還提供了 AND  OR 運算來匹配技術。下面的例子可以匹配支持NfcA和Ndef或者MfcB和Ndef技術的tag。
  1. <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  2. <tech-list>
  3. <tech>android.nfc.tech.NfcA</tech>
  4. <tech>android.nfc.tech.Ndef</tech>
  5. </tech-list>
  6. </resources>
  7. <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  8. <tech-list>
  9. <tech>android.nfc.tech.NfcB</tech>
  10. <tech>android.nfc.tech.Ndef</tech>
  11. </tech-list>
  12. </resources>
在你的AndroidManifest.xml文件的<activity>元素下的<meta-data>的元素中指定了資源文件(的路徑),如下所示:
  1. <activity>
  2. ...
  3. <intent-filter>
  4. <action android:name="android.nfc.action.TECH_DISCOVERED"/>
  5. </intent-filter>
  6. <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
  7. android:resource="@xml/nfc_tech_filter" />
  8. ...
  9. </activity>
更多關於tag技術和 ACTION_TECH_DISCOVERED的intent請到高級NFC文檔中參閱Working with Supported Tag Technologies

ACTION_TAG_DISCOVERED

爲了過濾ACTION_TAG_DISCOVERED類型的需像下面這樣定義intent-filter:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.TAG_DISCOVERED"/>
  3. </intent-filter>


得到intent中的信息(Obtaining information from intents)

如果一個activity是因爲NFC intent而啓動,那麼你可以從這個intent中得到掃描的NFC tag的信息。intent根據掃描到的tag可以包含以下extras:
  • EXTRA_TAG(必需的):一個表示掃描到的tag的Tag對象。
  • EXTRA_NDEF_MESSAGE(可選的):一個從tag中解析到的NDEF信息的數組。這個extra強制託管在ACTION_NDEF_DISCOVERED類型的intent中。
  • EXTRA_ID(可選的):標籤的低級別 ID。

爲了拿到這些extras,需要檢查你的activity是否是由NFC intent啓動的以確保tag掃描成功,然後才能從intent中拿到這些extras。下面的例子檢查了ACTION_NDEF_DISCOVER類型的intent並從它的extra中得到NDEF信息。
  1. public void onResume() {
  2. super.onResume();
  3. ...
  4. if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
  5. Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
  6. if (rawMsgs != null) {
  7. msgs = new NdefMessage[rawMsgs.length];
  8. for (int i = 0; i < rawMsgs.length; i++) {
  9. msgs[i] = (NdefMessage) rawMsgs[i];
  10. }
  11. }
  12. }
  13. //process the msgs array
  14. }
作爲選擇之一的,你可以從intent中得到一個包含有效負載並允許你列舉標籤的技術的Tag對象。
  1. Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

創建常見類型的NDEF記錄(Creating Common Types of NDEF Records)

此章節描述了怎樣創建常見類型的NDEF記錄,在你寫NFC tag或者通過Android Beam發送數據的時候幫助你。從Android 4.0(API 14)開始,createUri()方法能幫你自動創建URI記錄。從Android 4.1(API 16)開始,createExternal()和createMime()能幫助你創建MIME和外部類型的NDEF記錄。使用這些幫助方法讓你在手動創建NDEF記錄的時候儘可能避免出錯。
這個章節也描述瞭如何爲記錄創建相應的intent。所有的NDEF記錄示例應該在你寫或者發送的tag的NDEF消息裏的第一條NDEF記錄中。

TNF_ABSOLUTE_URI

注意:我們建議你使用RTD_URI來代替TNF_ABSOLUTE_URI,因爲它效率更高。
你可以通過下面的方法創建TNF_ABSOLUTE_URI類型的NDEF記錄:
  1. NdefRecord uriRecord = new NdefRecord(
  2. NdefRecord.TNF_ABSOLUTE_URI ,
  3. "http://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),
  4. new byte[0], new byte[0]);
以前的NDEF記錄的intent-filter看起來像下面這個樣子:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <data android:scheme="http"
  5. android:host="developer.android.com"
  6. android:pathPrefix="/index.html" />
  7. </intent-filter>

TNF_MIME_MEDIA

你可以通過如下示例創建TNF_MIME_MEDIA的NDEF記錄:
使用 createMime() 方法:
  1. NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
  2. "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
手動創建 NdefRecord
  1. NdefRecord mimeRecord = new NdefRecord(
  2. NdefRecord.TNF_MIME_MEDIA ,
  3. "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
  4. new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));
以前的NDEF記錄的intent-filter看起來像下面這個樣子:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <data android:mimeType="application/vnd.com.example.android.beam" />
  5. </intent-filter>

TNF_WELL_KNOWN with RTD_TEXT

你可以通過如下示例創建TNF_WELL_KNOWN的NDEF記錄:
  1. public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
  2. byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
  3. Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
  4. byte[] textBytes = payload.getBytes(utfEncoding);
  5. int utfBit = encodeInUtf8 ? 0 : (1 << 7);
  6. char status = (char) (utfBit + langBytes.length);
  7. byte[] data = new byte[1 + langBytes.length + textBytes.length];
  8. data[0] = (byte) status;
  9. System.arraycopy(langBytes, 0, data, 1, langBytes.length);
  10. System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
  11. NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
  12. NdefRecord.RTD_TEXT, new byte[0], data);
  13. return record;
  14. }
intent-filter看起來像下面這個樣子:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <data android:mimeType="text/plain" />
  5. </intent-filter>

TNF_WELL_KNOWN with RTD_URI

你可以通過如下示例創建TNF_WELL_KNOWN的NDEF記錄:
使用 createUri(String) 方法:
  1. NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");
使用 createUri(Uri) 方法:
  1. Uri uri = new Uri("http://example.com");
  2. NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
手動創建 NdefRecord 
  1. byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
  2. byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix
  3. byte payload[0] = 0x01; //prefixes http://www. to the URI
  4. System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload
  5. NdefRecord rtdUriRecord = new NdefRecord(
  6. NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
intent-filter看起來像下面這個樣子:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <data android:scheme="http"
  5. android:host="example.com"
  6. android:pathPrefix="" />
  7. </intent-filter>

TNF_EXTERNAL_TYPE

你可以通過如下示例創建TNF_EXTERNAL_TYPE的NDEF記錄:
使用 createExternal() 方法:
  1. byte[] payload; //assign to your data
  2. String domain = "com.example"; //usually your app's package name
  3. String type = "externalType";
  4. NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
手動創建 NdefRecord 
  1. byte[] payload;
  2. ...
  3. NdefRecord extRecord = new NdefRecord(
  4. NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType", new byte[0], payload);
intent-filter看起來像下面這個樣子:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <data android:scheme="vnd.android.nfc"
  5. android:host="ext"
  6. android:pathPrefix="/com.example:externalType"/>
  7. </intent-filter>
使用更通用的NFC TNF_EXTERNAL_TYPE類型的NFC tag部署更好地支持安卓設備和non-Android-powered設備。
注意:對於TNF_EXTERNAL_TYPE的URN有一個標準的格式:urn:nfc:ext:example.com:externalType,然而NFC論壇的RTD規範聲明URN的一部分【urn:nfc:ext:】必須在NDEF記錄中被省略。所以你需要提供的是被冒號分隔的域名(example.com in the example)和類型(externalType in the example)。當分發TNF_EXTERNAL_TYPE的時候,Android將【urn:nfc:ext:example.com:externalType】URN轉換爲【vnd.android.nfc://ext/example.com:externalType】的URL,這些在例子中的intent-filter有聲明。

Android應用程序記錄(Android Application Records)

在Android 4.0(API 14)中有介紹,Android Application Record (AAR)使得在掃描到NFC tag時啓動你的應用程序有了更好的保證。一個帶有應用包名的AAR被嵌入一個NFC記錄。你能添加一個AAR到任意一個NDEF消息中,因爲Android會爲AAR搜尋整個NDEF消息。如果找到一個,Google Play會被啓動下載該應用程序。

AAR能有效的預防通過同一個intent過濾的其他應用程序 處理被你部署的特定的tags的可能性。  AAR是application支持級別的,因爲包名限制,不是帶有intent-filter的Activity級別。如果你想在Activity級別處理一個intent,請使用 intent filters.
 
如果一個tag包含AAR,tag diapatch system通過如下方式分發:
1. 像往常一樣通過intent-filter啓動一個Activity。如果一個Activity匹配這個intent並且同時匹配這個AAR,那麼啓動它。
2. 如果intent-filter過濾出的Activity不匹配AAR,並且有多個Activity能處理這個intent,或者沒有Activity能處理,那麼啓動AAR指定的應用程序。
3. 如果通過AAR沒有應用程序被啓動,那麼根據AAR到谷歌應用商店裏下載一個應用。

注意:你可以重寫AAR和前臺分發系統的intent發佈系統,這允許一個前臺Activity在發現NFC tag時擁有優先級。通過這個方法,activity必須在前臺重寫AAR和intent發佈系統。

如果你想爲掃描的tag過濾出不包含AAR的,你可以像往常一樣聲明intent-filter。這對於當你的應用程序對其他不包含AAR的tag感興趣的時候是有用的。例如,你可能想保證你的應用程序處理你部署的優先級tag或者其他第三方開發的。請記住,AAR對於Android 4.0或者之後的設備是特殊的,所以當你開發tag的時候,你或許會想使用一個AAR和MIME type或者URI的組合以支持大多數的設備。另外,當你部署NFC tag時,想想如何寫NFC tag才能讓你的tag支持大多數設備(安卓設備或者其他設備)。你可以通過定義一個相關且唯一的MIME類型或者URI來使得應用程序更好的區分。
Android提供一個簡單的API來創建AAR, 即 createApplicationRecord()。你需要做的只是在你的 NdefRecord 的任何的地方嵌入AAR。你不會想使用你的 NdefRecord  的第一條記錄,除非這個AAR是這個NdefRecord 的唯一記錄。這是因爲Android系統通過檢查NdefRecord 的第一條記錄來確定tag的MIME類型或者URI,這被用來爲應用創建一個intent來過濾。下面的代碼向你展示瞭如何創一個AAR:
  1. NdefMessage msg = new NdefMessage(
  2. new NdefRecord[] {
  3. ...,
  4. NdefRecord.createApplicationRecord("com.example.android.beam")}

發送NDEF消息到其他設備(Beaming NDEF Messages to Other Devices)

Android Beam允許兩個設備之間簡單的點對點數據交換。應用程序必須在數據發送方的設備的前臺,接收方要處於解鎖狀態。當發送設備離接收設備足夠近的聯繫時,發送設備會呈現“點擊發送”(Touch To Beam)的界面。用戶可以選擇發送或者不發送(到接收設備)。
注意:前臺NDEF推送在API 10才支持,提供了跟Android Beam相類似的功能。這些API被棄用,但仍然在較老設備上被支持。更多信息參閱 enableForegroundNdefPush() .

你能在應用中通過調用下面兩個方法中的一個使得Android Beam有效:
  • setNdefPushMessage():( Accepts an NdefMessage to set as the message to beam)。當兩設備足夠靠近的時候自動發送消息。
  • setNdefPushMessageCallback():接收一個包含createNdefMessage() 並當消息接收設備在範圍內就會調用 該方法的回調。這回調讓你在需要的時候才創建NDEF消息。

一個Activity一次只能推送一條NDEF消息,所以當兩個都被設置的時候setNdefPushMessageCallback()會優先於setNdefPushMessage()。爲了使用Android beam,下面的常規指導必須閱讀:

  • 發送數據的activity必須處於前臺。所有設備都必須處於解鎖狀態。
  • 你必須將你要發送的信息封裝到 NdefMessage 對象裏。
  • 數據接收設備必須支持 com.android.npp 的NDEF推送協議或者NFC論壇的SNEP(Simple NDEF Exchange Protocol:簡單NDEF交換協議)。com.android.npp 協議要求設備在API 9(Android 2.3)到API 13(Android 3.2)。com.android.npp 和 SNDP都要求API 14(Android 4.0)或以上。
注意:如果你的應用是能夠Android Beam並且在前臺,那麼標準的intent分發系統將失效。然而,如果你的應用同時支持 前臺分發( foreground dispatching),那麼它仍然能在前臺調度掃描與intent-filter匹配的tag。

爲了使用Android Beam:
  1. 創建一個包含你想推送到其他設備的 NdefRecord  NdefMessage 
  2. 通過一個NdefMessage調用 setNdefPushMessage(),或者在你的 activity的onCteate()方法中通過一個NfcAdapter.CreateNdefMessageCallback的對象調用 setNdefPushMessageCallback。這些方法要求至少一個activity(that you want to enable with Android Beam),伴隨着被激活的其它activity的可選列表。
        綜上所述,如果在兩個設備在交流範圍內時,你的Activity總是發送同樣的NDEF消息,那你通常使用 setNdefPushMessage() 就可以。如果你的應用關注當前應用的context並且想根據當前用戶所做的來決定推送的NDEF消息,那麼使用setNdefPushMessageCallback

接下來的例子展示了一個簡單的activity在onCreate()中調用 NfcAdapter.CreateNdefMessageCallback(完整的AndroidBeamDem例子在這裏)。這個例子也有方法幫助你創建MIME記錄:
  1. package com.example.android.beam;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.nfc.NdefMessage;
  5. import android.nfc.NdefRecord;
  6. import android.nfc.NfcAdapter;
  7. import android.nfc.NfcAdapter.CreateNdefMessageCallback;
  8. import android.nfc.NfcEvent;
  9. import android.os.Bundle;
  10. import android.os.Parcelable;
  11. import android.widget.TextView;
  12. import android.widget.Toast;
  13. import java.nio.charset.Charset;
  14. public class Beam extends Activity implements CreateNdefMessageCallback {
  15. NfcAdapter mNfcAdapter;
  16. TextView textView;
  17. @Override
  18. public void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.main);
  21. TextView textView = (TextView) findViewById(R.id.textView);
  22. // Check for available NFC Adapter
  23. mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
  24. if (mNfcAdapter == null) {
  25. Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
  26. finish();
  27. return;
  28. }
  29. // Register callback
  30. mNfcAdapter.setNdefPushMessageCallback(this, this);
  31. }
  32. @Override
  33. public NdefMessage createNdefMessage(NfcEvent event) {
  34. String text = ("Beam me up, Android!\n\n" +
  35. "Beam Time: " + System.currentTimeMillis());
  36. NdefMessage msg = new NdefMessage(
  37. new NdefRecord[] { createMime(
  38. "application/vnd.com.example.android.beam", text.getBytes())
  39. /**
  40. * The Android Application Record (AAR) is commented out. When a device
  41. * receives a push with an AAR in it, the application specified in the AAR
  42. * is guaranteed to run. The AAR overrides the tag dispatch system.
  43. * You can add it back in to guarantee that this
  44. * activity starts when receiving a beamed message. For now, this code
  45. * uses the tag dispatch system.
  46. */
  47. //,NdefRecord.createApplicationRecord("com.example.android.beam")
  48. });
  49. return msg;
  50. }
  51. @Override
  52. public void onResume() {
  53. super.onResume();
  54. // Check to see that the Activity started due to an Android Beam
  55. if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
  56. processIntent(getIntent());
  57. }
  58. }
  59. @Override
  60. public void onNewIntent(Intent intent) {
  61. // onResume gets called after this to handle the intent
  62. setIntent(intent);
  63. }
  64. /**
  65. * Parses the NDEF Message from the intent and prints to the TextView
  66. */
  67. void processIntent(Intent intent) {
  68. textView = (TextView) findViewById(R.id.textView);
  69. Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
  70. NfcAdapter.EXTRA_NDEF_MESSAGES);
  71. // only one message sent during the beam
  72. NdefMessage msg = (NdefMessage) rawMsgs[0];
  73. // record 0 contains the MIME type, record 1 is the AAR, if present
  74. textView.setText(new String(msg.getRecords()[0].getPayload()));
  75. }
  76. }
注意你可以移除在AAR之外的代碼註釋。如果你使AAR生效了,那麼被AAR指定的應用總是能收到Android Beam的消息。如果應用沒有被呈現,谷歌商店會去下載這個應用。因此,下面的intent-filter在Android 4.0或之後使用AAR不是技術上必要的:
  1. <intent-filter>
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  3. <category android:name="android.intent.category.DEFAULT"/>
  4. <data android:mimeType="application/vnd.com.example.android.beam"/>
  5. </intent-filter>
通過這個intent-filter,com.example.android.beam 這個應用能夠在掃描到NFC tag或者接收到com.example.android.beam這種AAR的Android Beam發送的消息,或者當一個NDEF格式的消息包含MIME類型爲application/vnd.com.example.android.beam 的記錄。

儘管AAR保證一個應用被啓動或者下載,intent-filter仍然是被推薦的,因爲他們讓你啓動一個你的應用程序中你選擇的Activity,而不是總是啓動被AAR指定包名的應用的mian Activity。AAR沒有Activity級別區分。因此,一些安卓設備不支持AAR,爲了以防萬一,你應該在你的NDEF消息的第一條NDEF記錄中嵌入識別信息,也爲了過濾。如何創建記錄請參閱創建常規類型的NDEF記錄Creating Common Types of NDEF records.




































發佈了30 篇原創文章 · 獲贊 13 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章