本文說明您在 Android 中執行的基本 NFC 工作。說明如何以 NDEF 訊息格式傳送及接收 NFC 資料,並說明支援這些功能的 Android 架構 API。如要進一步瞭解其他進階主題,包括如何處理非 NDEF 資料,請參閱進階 NFC 相關說明。
系統會透過標記調度系統處理從 NFC 標記讀取 NDEF 資料的作業,該系統會分析所偵測到的 NFC 標記,適當分類資料,並啟動感興趣的應用程式,以便處理分類資料。如要處理已掃描的 NFC 標記,應用程式可以宣告意圖篩選器,並要求處理資料。
代碼調度系統
除非在裝置的「設定」選單中停用 NFC,否則 Android 裝置通常會在螢幕解鎖時尋找 NFC 標記。當 Android 裝置偵測到 NFC 標記時,所需的行為是讓最適合的活動處理意圖,而不需要詢問使用者要使用哪個應用程式。由於裝置掃描 NFC 標記的距離非常短,因此使用者手動選取活動可能會強制讓他們將裝置移出標記,並中斷連線。您應該開發活動,以只處理活動關注的 NFC 標記,以免活動選擇器出現。
為協助您達成這個目標,Android 提供了特殊的標記分派系統,可分析掃描的 NFC 標記、剖析這些標記,並嘗試找出對掃描資料感興趣的應用程式。這項功能的運作方式如下:
- 剖析 NFC 標記,並識別 MIME 類型,或識別標記中資料酬載的 URI。
- 將 MIME 類型或 URI 和酬載封裝至意圖。想瞭解前兩個步驟,請參閱NFC 標記如何對應至 MIME 類型和 URI。
- 根據意圖啟動活動。詳情請參閱如何將 NFC 標記分派給應用程式。
NFC 標記如何對應至 MIME 類型和 URI
開始撰寫 NFC 應用程式前,請務必先瞭解不同類型的 NFC 標記、標記調度系統剖析 NFC 標記的方式,以及標記調度系統偵測到 NDEF 訊息時執行的特殊工作。NFC 標記有各式各樣的技術,也可以用多種方式寫入資料。Android 支援的 NDEF 標準最多,這些標準是由 NFC 論壇定義。
NDEF 資料會封裝在包含一或多筆記錄 (NdefRecord
) 的訊息中 (NdefMessage
)。每筆 NDEF 記錄都必須根據您要建立的記錄類型指定正確格式。Android 也支援其他不含 NDEF 資料的標記類型,您可以使用 android.nfc.tech
套件中的類別使用這些標記。如要進一步瞭解這些技術,請參閱「進階 NFC」主題。使用這些其他類型的標記時,您必須自行編寫通訊協定堆疊來與標記通訊,因此如果可能的話,建議您使用 NDEF,以便進行開發作業的便利性,同時盡可能獲得 Android 裝置的支援。
注意:如要下載完整的 NDEF 規格,請前往 NFC 論壇規格與應用程式文件網站,參閱「建立常見類型的 NDEF 記錄」一文,瞭解如何建構 NDEF 記錄。
現在您已瞭解 NFC 標記的一些背景,以下各節將詳細說明 Android 如何處理 NDEF 格式標記。當 Android 裝置掃描含有 NDEF 格式資料的 NFC 標籤時,會剖析訊息,並嘗試找出資料的 MIME 類型或識別 URI。為此,系統會讀取 NdefMessage
中的首個 NdefRecord
,以決定如何解讀整個 NDEF 訊息 (NDEF 訊息可包含多個 NDEF 記錄)。在格式正確的 NDEF 訊息中,第一個 NdefRecord
包含下列欄位:
- 3 位元 TNF (類型名稱格式)
- 表示如何解讀變長型別欄位。如需有效值的說明,請參閱表 1。
- 可變長度類型
- 說明記錄類型。如果使用
TNF_WELL_KNOWN
,請使用這個欄位指定記錄類型定義 (RTD)。如需有效的 RTD 值說明,請參閱表 2。 - 變數長度 ID
- 記錄的專屬 ID。這個欄位不常使用,但如果您需要明確識別代碼,可以為其建立 ID。
- 變長度酬載
- 您要讀取或寫入的實際資料酬載。NDEF 訊息可以包含多個 NDEF 記錄,因此請不要假設完整酬載位於 NDEF 訊息的第一個 NDEF 記錄中。
標記調度系統會使用 TNF 和類型欄位,嘗試將 MIME 類型或 URI 對應至 NDEF 訊息。如果成功,就會封裝 ACTION_NDEF_DISCOVERED
意圖中的資訊及實際酬載。但在某些情況下,標記分派系統無法根據第一筆 NDEF 記錄判斷資料類型。當 NDEF 資料無法對應至 MIME 類型或 URI,或是 NFC 標籤不含開頭為 NDEF 的資料時,就會發生這種情況。在這種情況下,系統會改為將包含標記技術和酬載的 Tag
物件封裝至 ACTION_TECH_DISCOVERED
意圖中。
表 1 說明標記分派系統如何將 TNF 和類型欄位對應至 MIME 類型或 URI。並說明哪些 TNF 無法對應至 MIME 類型或 URI。在這些情況下,標記調度系統會改為使用 ACTION_TECH_DISCOVERED
。
舉例來說,如果標記調度系統遇到 TNF_ABSOLUTE_URI
類型的記錄,就會將該記錄的可變長度類型欄位對應至 URI。標記分派系統會將該 URI 封裝在 ACTION_NDEF_DISCOVERED
意圖的資料欄位中,以及標記的其他資訊,例如酬載。另一方面,如果遇到 TNF_UNKNOWN
類型的記錄,則會改為建立包裝標記技術的意圖。
類型名稱格式 (TNF) | 對應 |
---|---|
TNF_ABSOLUTE_URI |
根據類型欄位產生的 URI。 |
TNF_EMPTY |
改回 ACTION_TECH_DISCOVERED 。 |
TNF_EXTERNAL_TYPE |
根據類型欄位的 URN 建立的 URI。URN 會以簡寫形式編碼至 NDEF 類型欄位:<domain_name>:<service_name> 。Android 會將這個值對應至格式為 vnd.android.nfc://ext/<domain_name>:<service_name> 的 URI。 |
TNF_MIME_MEDIA |
根據類型欄位指定的 MIME 類型。 |
TNF_UNCHANGED |
在第一筆記錄中無效,因此會改回 ACTION_TECH_DISCOVERED 。 |
TNF_UNKNOWN |
回復為 ACTION_TECH_DISCOVERED 。 |
TNF_WELL_KNOWN |
MIME 類型或 URI,取決於您在 type 欄位中設定的記錄類型定義 (RTD)。如要進一步瞭解可用的 RTD 及其對應項目,請參閱 表 2。 |
記錄類型定義 (RTD) | 對應 |
---|---|
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 標記如何分派給應用程式
當代碼調度系統完成建立包裝 NFC 代碼及其識別資訊的意圖後,就會將意圖傳送至感興趣的應用程式,讓該應用程式篩選意圖。如果有多個應用程式可以處理意圖,系統會顯示活動選擇器,讓使用者選取活動。標記調度系統定義了三個意圖,依優先順序由高至低列出如下:
-
ACTION_NDEF_DISCOVERED
:在掃描包含 NDEF 酬載的標記屬於可辨識的類型時,此意圖會用來啟動活動。這是優先順序最高的意圖,且標記調度系統會盡可能在任何其他意圖之前,嘗試以此意圖啟動活動。 ACTION_TECH_DISCOVERED
:如果沒有註冊活動來處理ACTION_NDEF_DISCOVERED
意圖,標記調度系統會嘗試使用此意圖啟動應用程式。如果掃描到的標籤包含無法對應至 MIME 類型或 URI 的 NDEF 資料,或是標籤不含 NDEF 資料,但屬於已知的標籤技術,則也會直接啟動此意圖 (不必先啟動ACTION_NDEF_DISCOVERED
)。ACTION_TAG_DISCOVERED
:如果沒有活動處理ACTION_NDEF_DISCOVERED
或ACTION_TECH_DISCOVERED
意圖,系統就會啟動這個意圖。
代碼分派系統的基本運作方式如下:
- 嘗試使用標記調度系統在剖析 NFC 標記 (
ACTION_NDEF_DISCOVERED
或ACTION_TECH_DISCOVERED
) 時建立的意圖,啟動活動。 - 如果沒有任何活動篩選器可用於該意圖,請嘗試使用下一個優先順序最低的意圖 (
ACTION_TECH_DISCOVERED
或ACTION_TAG_DISCOVERED
) 啟動活動,直到應用程式篩選器可用於該意圖,或標記調度系統嘗試所有可能的意圖為止。 - 如果沒有任何應用程式篩選任何意圖,則不採取任何行動。
請盡可能使用 NDEF 訊息和 ACTION_NDEF_DISCOVERED
意圖,因為這三項意圖最明確。這個意圖可讓您在比其他兩個意圖更適當的時機啟動應用程式,為使用者提供更優質的體驗。
在 Android 資訊清單中要求 NFC 存取權
您必須先在 AndroidManifest.xml
檔案中宣告下列項目,才能存取裝置的 NFC 硬體並正確處理 NFC 意圖:
- 用於存取 NFC 硬體的 NFC
<uses-permission>
元素:<uses-permission android:name="android.permission.NFC" />
- 應用程式支援的最低 SDK 版本。API 級別 9 僅支援透過
ACTION_TAG_DISCOVERED
進行有限的標記調度,且僅會透過EXTRA_NDEF_MESSAGES
額外項目提供 NDEF 訊息存取權。無法存取其他代碼屬性或 I/O 作業。API 級別 10 提供完整的讀取者/寫入者支援和前景 NDEF 推送功能,而 API 級別 14 則提供額外的便利方法建立 NDEF 記錄。<uses-sdk android:minSdkVersion="10"/>
uses-feature
元素,讓您的應用程式只在具備 NFC 硬體的裝置上顯示在 Google Play 中:<uses-feature android:name="android.hardware.nfc" android:required="true" />
如果應用程式使用 NFC 功能,但該功能對應用程式並非必要,您可以省略
uses-feature
元素,並檢查getDefaultAdapter()
是否為null
,以便在執行階段檢查 NFC 是否可用。
篩選 NFC 意圖
如要在掃描要處理的 NFC 標記時啟動應用程式,應用程式可以篩選 Android 資訊清單中的一個、兩個或三個 NFC 意圖。不過,您通常會想要篩選 ACTION_NDEF_DISCOVERED
意圖,盡可能控管應用程式啟動時間。當沒有應用程式篩選 ACTION_NDEF_DISCOVERED
,或是酬載不是 NDEF 時,ACTION_TECH_DISCOVERED
意圖是 ACTION_NDEF_DISCOVERED
的備用方案。篩選 ACTION_TAG_DISCOVERED
通常會過於籠統,無法篩選出所需類別。許多應用程式會在 ACTION_TAG_DISCOVERED
之前篩選 ACTION_NDEF_DISCOVERED
或 ACTION_TECH_DISCOVERED
,因此應用程式啟動的可能性不高。ACTION_TAG_DISCOVERED
只能用於應用程式在沒有其他已安裝應用程式可處理 ACTION_NDEF_DISCOVERED
或 ACTION_TECH_DISCOVERED
意圖的情況下,作為篩選的最後手段。
由於 NFC 標記部署方式各不相同,且很多時候無法由您控制,因此這項做法不一定可行,因此您可在必要時改用其他兩種意圖。當您可以控制寫入的標記類型和資料時,建議您使用 NDEF 格式化標記。以下各節說明如何篩選每種意圖。
ACTION_NDEF_DISCOVERED
如要篩選 ACTION_NDEF_DISCOVERED
意圖,請宣告意圖篩選器,並指定要篩選的資料類型。以下範例篩選 ACTION_NDEF_DISCOVERED
意圖,其 MIME 類型為 text/plain
:
<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="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter>
ACTION_TECH_DISCOVERED
如果活動篩選 ACTION_TECH_DISCOVERED
意圖,您必須建立 XML 資源檔案,指定活動在 tech-list
集合中支援的技術。如果 tech-list
集合是代碼支援的技術子集,系統就會將您的活動視為符合條件,您可以透過呼叫 getTechList()
取得該集合。
舉例來說,如果掃描的標籤支援 MifareClassic、NdefFormatable 和 NfcA,則 tech-list
集合必須指定三種、兩種或一種技術 (且不得指定其他技術),才能讓活動相符。
以下範例會定義所有技術。請務必移除 NFC 標記不支援的外掛程式。將這個檔案儲存在 <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()
傳回的技術子集,系統就會將您的活動視為相符。這提供 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
意圖,請參閱進階 NFC 說明文件中的「使用支援的標籤技術」。
ACTION_TAG_DISCOVERED
如要篩選 ACTION_TAG_DISCOVERED
,請使用下列意圖篩選器:
<intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> </intent-filter>
從意圖取得資訊
如果活動是因為 NFC 意圖而啟動,您可以從意圖取得掃描的 NFC 標籤相關資訊。意圖可包含下列額外項目,具體取決於掃描的標記:
EXTRA_TAG
(必要):代表掃描到的標記的Tag
物件。EXTRA_NDEF_MESSAGES
(選用):從標籤解析的 NDEF 訊息陣列。此額外內容是ACTION_NDEF_DISCOVERED
意圖的必要條件。EXTRA_ID
(選用):代碼的低層級 ID。
為了取得這些額外功能,請檢查活動是否已使用其中一個 NFC 意圖啟動,確保系統已掃描標記,然後從意圖中取得其他額外項目。下列範例會檢查 ACTION_NDEF_DISCOVERED
意圖,並從意圖額外項目取得 NDEF 訊息。
Kotlin
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) ... if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) { intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages -> val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage } // Process the messages array. ... } } }
Java
@Override protected 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. ... } } }
或者,您也可以從意圖取得 Tag
物件,該物件會包含酬載,並讓您列舉標記的技術:
Kotlin
val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
建立常見類型的 NDEF 記錄
本節將說明如何建立常見類型的 NDEF 記錄,以利您寫入 NFC 標籤。從 Android 4.0 (API 級別 14) 開始,您可以使用 createUri()
方法自動建立 URI 記錄。自 Android 4.1 (API 級別 16) 起,createExternal()
和 createMime()
可協助您建立 MIME 和外部類型的 NDEF 記錄。盡可能使用這些輔助方法,以免在手動建立 NDEF 記錄時發生錯誤。
本節也會說明如何為記錄建立對應的意圖篩選器。所有這些 NDEF 記錄範例都必須位於您將寫入標記的 NDEF 訊息的第一個 NDEF 記錄中。
TNF_ABSOLUTE_URI
注意:建議您改用 RTD_URI
類型,而非 TNF_ABSOLUTE_URI
,因為前者效率更高。
您可以按照下列方式建立 TNF_ABSOLUTE_URI
NDEF 記錄:
Kotlin
val uriRecord = ByteArray(0).let { emptyByteArray -> NdefRecord( TNF_ABSOLUTE_URI, "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")), emptyByteArray, emptyByteArray ) }
Java
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-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter>
TNF_MIME_MEDIA
您可以透過下列方式建立 TNF_MIME_MEDIA
NDEF 記錄:
使用 createMime()
方法:
Kotlin
val mimeRecord = NdefRecord.createMime( "application/vnd.com.example.android.beam", "Beam me up, Android".toByteArray(Charset.forName("US-ASCII")) )
Java
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam", "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
手動建立 NdefRecord
:
Kotlin
val mimeRecord = Charset.forName("US-ASCII").let { usAscii -> NdefRecord( NdefRecord.TNF_MIME_MEDIA, "application/vnd.com.example.android.beam".toByteArray(usAscii), ByteArray(0), "Beam me up, Android!".toByteArray(usAscii) ) }
Java
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-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>
TNF_WELL_KNOWN 搭配 RTD_TEXT
您可以按照下列方式建立 TNF_WELL_KNOWN
NDEF 記錄:
Kotlin
fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord { val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII")) val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16") val textBytes = payload.toByteArray(utfEncoding) val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7 val status = (utfBit + langBytes.size).toChar() val data = ByteArray(1 + langBytes.size + textBytes.size) data[0] = status.toByte() System.arraycopy(langBytes, 0, data, 1, langBytes.size) System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size) return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data) }
Java
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) { byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII")); Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16"); byte[] textBytes = payload.getBytes(utfEncoding); int utfBit = encodeInUtf8 ? 0 : (1 << 7); char status = (char) (utfBit + langBytes.length); byte[] data = new byte[1 + langBytes.length + textBytes.length]; data[0] = (byte) status; System.arraycopy(langBytes, 0, data, 1, langBytes.length); System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); return record; }
先前的 NDEF 記錄的意圖篩選器如下所示:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter>
TNF_WELL_KNOWN 搭配 RTD_URI
您可以透過下列方式建立 TNF_WELL_KNOWN
NDEF 記錄:
使用 createUri(String)
方法:
Kotlin
val rtdUriRecord1 = NdefRecord.createUri("https://example.com")
Java
NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");
使用 createUri(Uri)
方法:
Kotlin
val rtdUriRecord2 = Uri.parse("https://example.com").let { uri -> NdefRecord.createUri(uri) }
Java
Uri uri = Uri.parse("https://example.com"); NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
手動建立 NdefRecord
:
Kotlin
val uriField = "example.com".toByteArray(Charset.forName("US-ASCII")) val payload = ByteArray(uriField.size + 1) //add 1 for the URI Prefix payload [0] = 0x01 //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.size) //appends URI to payload val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)
Java
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII")); byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix payload[0] = 0x01; //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload NdefRecord rtdUriRecord = new NdefRecord( NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
上一個 NDEF 記錄的意圖篩選器如下所示:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="example.com" android:pathPrefix="" /> </intent-filter>
TNF_EXTERNAL_TYPE
您可以透過下列方式建立 TNF_EXTERNAL_TYPE
NDEF 記錄:
使用 createExternal()
方法:
Kotlin
var payload: ByteArray //assign to your data val domain = "com.example" //usually your app's package name val type = "externalType" val extRecord = NdefRecord.createExternal(domain, type, payload)
Java
byte[] payload; //assign to your data String domain = "com.example"; //usually your app's package name String type = "externalType"; NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
手動建立 NdefRecord
:
Kotlin
var payload: ByteArray ... val extRecord = NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".toByteArray(Charset.forName("US-ASCII")), ByteArray(0), payload )
Java
byte[] payload; ... NdefRecord extRecord = new NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")), new byte[0], payload);
上一個 NDEF 記錄的意圖篩選器如下所示:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="vnd.android.nfc" android:host="ext" android:pathPrefix="/com.example:externalType"/> </intent-filter>
使用 TNF_EXTERNAL_TYPE
進行更通用的 NFC 標記部署,以便更好地支援 Android 和非 Android 裝置。
注意:TNF_EXTERNAL_TYPE
的 URN 標準格式為:urn:nfc:ext:example.com:externalType
,但 NFC 論壇 RTD 規格宣告,URN 的 urn:nfc:ext:
部分必須從 NDEF 記錄中省略。因此,您只需提供網域 (範例中的 example.com
) 和類型 (範例中為 externalType
),並以半形冒號分隔。在調度 TNF_EXTERNAL_TYPE
時,Android 會將 urn:nfc:ext:example.com:externalType
URN 轉換為 vnd.android.nfc://ext/example.com:externalType
URI,這正是範例中意圖篩選器宣告的內容。
Android 應用程式記錄
Android 4.0 (API 級別 14) 推出後,Android 應用程式記錄 (AAR) 可讓系統在掃描 NFC 標記時更安全地啟動應用程式。AAR 包含 NDEF 記錄內嵌的應用程式套件名稱。您可以在 NDEF 訊息的任何 NDEF 記錄中新增 AAR,因為 Android 會搜尋整個 NDEF 訊息中的 AAR。如果找到 AAR,系統會根據 AAR 中的套件名稱啟動應用程式。如果裝置上沒有應用程式,系統會啟動 Google Play 下載應用程式。
如果不想讓其他應用程式篩選相同意圖,且可能會處理您已部署的特定標記,「AAR」就非常實用。由於套件名稱限制,只有應用程式層級支援 AAR,且在活動層級 (與意圖篩選方式相同) 不支援 AAR。如果您想在活動層級處理意圖,請使用意圖篩選器。
如果代碼包含 AAR,代碼調度系統會以以下方式調度:
- 嘗試照常使用意圖篩選器啟動 Activity。如果與意圖相符的活動也符合 AAR,請啟動活動。
- 如果篩選意圖的「活動」與 AAR 不符、如果多個活動可以處理意圖,或者沒有活動處理該意圖,請啟動 AAR 指定的應用程式。
- 如果沒有任何應用程式可以從 AAR 啟動,請前往 Google Play 下載以 AAR 為基礎的應用程式。
注意:您可以使用前景分派系統覆寫 AAR 和意圖分派系統,這樣一來,當 NFC 標籤被偵測到時,前景活動就會具有優先順序。使用這個方法時,活動必須在前景執行,才能覆寫 AAR 和意圖調度系統。
如果您仍想篩選不含 AAR 的掃描標記,您可以按照一般方式宣告意圖篩選器。如果應用程式對不含 AAR 的其他標記感興趣,這項功能就很實用。舉例來說,您可能想確保應用程式會處理您部署的專屬標記,以及第三方部署的一般標記。請注意,AAR 僅適用於 Android 4.0 以上版本的裝置,因此在部署代碼時,您很可能會想同時使用 AAR 和 MIME 類型/URI,以便支援最廣泛的裝置。此外,在部署 NFC 標記時,請考量如何寫入 NFC 標記,以便支援多數裝置 (Android 裝置和其他裝置)。您可以透過定義相對獨特的 MIME 類型或 URI,讓應用程式更容易區分。
Android 提供簡單的 API 來建立 AAR,createApplicationRecord()
。您只需將 AAR 嵌入 NdefMessage
中的任何位置即可。您不想使用 NdefMessage
的第一筆記錄,除非 AAR 是 NdefMessage
中唯一的記錄。這是因為 Android 系統會檢查 NdefMessage
的第一個記錄,以判斷標記的 MIME 類型或 URI,並用於建立應用程式用於篩選的意圖。以下程式碼說明如何建立 AAR:
Kotlin
val msg = NdefMessage( arrayOf( ..., NdefRecord.createApplicationRecord("com.example.android.beam") ) )
Java
NdefMessage msg = new NdefMessage( new NdefRecord[] { ..., NdefRecord.createApplicationRecord("com.example.android.beam")} ); )