本文件說明進階 NFC 主題,例如使用各種標記技術。 以及前景調度,讓前景的應用程式能 處理意圖,即使其他應用程式篩選相同項目也是如此。
使用支援的代碼技術
使用 NFC 標記和 Android 裝置時,系統會使用用於讀取的主要格式
並將標記資料寫入 NDEF當裝置掃描含有 NDEF 資料的標記時,Android 提供了相關支援
剖析訊息並在 NdefMessage
中傳送
但在某些情況下,掃描的廣告代碼會不包含
NDEF 資料,或是 NDEF 資料無法對應至 MIME 類型或 URI。
在這些情況下,您必須直接與標記進行溝通,然後使用標記讀取及寫入該標記
您自己的通訊協定 (以原始位元組為單位)Android 針對這些用途提供一般支援。
android.nfc.tech
套件 (相關說明請見表 1)。你可以
使用 getTechList()
方法判斷技術
,並建立對應的TagTechnology
具有 android.nfc.tech
提供的任一類別的物件
類別 | 說明 |
---|---|
TagTechnology |
所有代碼技術類別都必須導入的介面。 |
NfcA |
提供 NFC-A (ISO 14443-3A) 屬性和 I/O 作業的存取權。 |
NfcB |
提供 NFC-B (ISO 14443-3B) 屬性和 I/O 作業的存取權。 |
NfcF |
提供 NFC-F (JIS 6319-4) 屬性和 I/O 作業的存取權。 |
NfcV |
提供 NFC-V (ISO 15693) 屬性和 I/O 作業的存取權。 |
IsoDep |
提供 ISO-DEP (ISO 14443-4) 屬性和 I/O 作業的存取權。 |
Ndef |
讓您存取 NDEF 資料和作業,對採用以下格式的 NFC 標記執行操作: NDEF。 |
NdefFormatable |
為可能是 NDEF 格式的代碼提供格式作業。 |
Android 裝置不必支援下列標記技術。
類別 | 說明 |
---|---|
MifareClassic |
可讓 MIFARE 傳統屬性 (如果這部 Android 裝置) 存取 MIFARE 傳統屬性和 I/O 作業 支援 MIFARE。 |
MifareUltralight |
提供 MIFARE Ultralight 屬性和 I/O 作業 (如果這個 Android 裝置) 裝置支援 MIFARE。 |
使用標記技術和 ACTION_TECH_DISCOVERED 意圖
當裝置掃描含有 NDEF 資料,但無法對應至 MIME 或 URI 的標記時,
代碼分派系統會嘗試使用 ACTION_TECH_DISCOVERED
啟動活動
意圖。當標記時,也會使用 ACTION_TECH_DISCOVERED
掃描非 NDEF 資料設定這種備用值後,您就能使用代碼上的資料
(廣告代碼分派系統無法為您剖析)。基本步驟
代碼技術如下:
- 篩選一個
ACTION_TECH_DISCOVERED
意圖,並指定該意圖 要處理的代碼技術請參閱篩選 NFC 意圖。一般來說,在收到 NDEF 訊息時,標記分派系統會嘗試啟動ACTION_TECH_DISCOVERED
意圖 無法對應至 MIME 類型或 URI,或是掃描的標記不含 NDEF 資料。適用對象 如要進一步瞭解判定方式,請參閱標記調度系統。 - 應用程式收到意圖時,請從以下位置取得
Tag
物件: 意圖:Kotlin
var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- 如要取得
TagTechnology
的例項,請呼叫android.nfc.tech
套件中類別的get
工廠方法。你可以 請在呼叫get
工廠方法之前呼叫getTechList()
,列舉標記支援的技術。例如:如要取得執行個體 來自Tag
的MifareUltralight
,請執行以下操作:Kotlin
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
Java
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
讀取及寫入標記
讀取和寫入 NFC 標記時,您必須從意圖取得該標記,並 和代碼展開通訊您必須定義自己的通訊協定堆疊,才能讀取及寫入資料 加入廣告代碼不過請記住,您在工作時仍可讀取及寫入 NDEF 資料 直接加上代碼要如何建構內容,完全由您決定。 以下範例說明如何使用 MIFARE Ultralight 代碼。
Kotlin
package com.example.android.nfc import android.nfc.Tag import android.nfc.tech.MifareUltralight import java.io.IOException import java.nio.charset.Charset class MifareUltralightTagTester { fun writeTag(tag: Tag, tagText: String) { MifareUltralight.get(tag)?.use { ultralight -> ultralight.connect() Charset.forName("US-ASCII").also { usAscii -> ultralight.writePage(4, "abcd".toByteArray(usAscii)) ultralight.writePage(5, "efgh".toByteArray(usAscii)) ultralight.writePage(6, "ijkl".toByteArray(usAscii)) ultralight.writePage(7, "mnop".toByteArray(usAscii)) } } } fun readTag(tag: Tag): String? { return MifareUltralight.get(tag)?.use { mifare -> mifare.connect() val payload = mifare.readPages(4) String(payload, Charset.forName("US-ASCII")) } } }
Java
package com.example.android.nfc; import android.nfc.Tag; import android.nfc.tech.MifareUltralight; import android.util.Log; import java.io.IOException; import java.nio.charset.Charset; public class MifareUltralightTagTester { private static final String TAG = MifareUltralightTagTester.class.getSimpleName(); public void writeTag(Tag tag, String tagText) { MifareUltralight ultralight = MifareUltralight.get(tag); try { ultralight.connect(); ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII"))); } catch (IOException e) { Log.e(TAG, "IOException while writing MifareUltralight...", e); } finally { try { ultralight.close(); } catch (IOException e) { Log.e(TAG, "IOException while closing MifareUltralight...", e); } } } public String readTag(Tag tag) { MifareUltralight mifare = MifareUltralight.get(tag); try { mifare.connect(); byte[] payload = mifare.readPages(4); return new String(payload, Charset.forName("US-ASCII")); } catch (IOException e) { Log.e(TAG, "IOException while reading MifareUltralight message...", e); } finally { if (mifare != null) { try { mifare.close(); } catch (IOException e) { Log.e(TAG, "Error closing tag...", e); } } } return null; } }
使用前景調度系統
前景調度系統可讓活動攔截意圖和聲明 優先順序高於處理相同意圖的其他活動。使用這個系統牽涉到 為 Android 系統建構一些資料結構,以便傳送適當的資料 意圖傳送至您的應用程式如何啟用前景調度系統:
- 在活動的
onCreate()
方法中加入下列程式碼:- 建立可變動的
PendingIntent
物件,讓 Android 系統填入該物件 以及標籤詳細資料Kotlin
val intent = Intent(this, javaClass).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) } var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE);
- 宣告意圖篩選器以處理要攔截的意圖。前景
派出系統,會根據收到的意圖檢查指定的意圖篩選器
裝置就會掃描標記如果相符,應用程式就會處理該意圖。需要的話
不相符,前景調度系統會改回使用意圖調度系統。
指定意圖篩選器和技術篩選器的
null
陣列,並指定 篩選出所有會傳回TAG_DISCOVERED
的代碼 意圖。以下程式碼片段會處理NDEF_DISCOVERED
的所有 MIME 類型。個人中心 應該只處理您需要的工作負載Kotlin
val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply { try { addDataType("*/*") /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (e: IntentFilter.MalformedMimeTypeException) { throw RuntimeException("fail", e) } } intentFiltersArray = arrayOf(ndef)
Java
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndef.addDataType("*/*"); /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (MalformedMimeTypeException e) { throw new RuntimeException("fail", e); } intentFiltersArray = new IntentFilter[] {ndef, };
- 設定應用程式要處理的代碼技術陣列。在
Object.class.getName()
方法,取得所需的技術類別 機構帳戶Kotlin
techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
Java
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
- 建立可變動的
- 覆寫以下活動生命週期回呼,並新增邏輯以啟用及停用
活動遺失時 (
onPause()
) 執行前景調度 並重新取得 (onResume()
) 對焦。必須從以下位置呼叫enableForegroundDispatch()
: 主執行緒,且只在活動於前景運作時 (在onResume()
中呼叫可保證此情況)。您也需要實作onNewIntent
回呼,以便處理掃描的 NFC 資料 標記之前。
Kotlin
public override fun onPause() { super.onPause() adapter.disableForegroundDispatch(this) } public override fun onResume() { super.onResume() adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray) } public override fun onNewIntent(intent: Intent) { val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) // do something with tagFromIntent }
Java
public void onPause() { super.onPause(); adapter.disableForegroundDispatch(this); } public void onResume() { super.onResume(); adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); } public void onNewIntent(Intent intent) { Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // do something with tagFromIntent }