高級NFC(Advanced NFC)
這篇文檔介紹了高級NFC主題,例如使用各種標籤技術,允許一個應用在前臺處理intent哪怕是其他應用過濾了同一個的前臺分發。
與被支持的標籤協作(Working with Supported Tag Technologies)
當安卓設備和NFC標籤交互的時候,大多數時候你在標籤上讀、寫的主要格式是NDEF。當設備掃描到NDEF數據,Android支持在NdefMessage中解析和傳遞消息,在可能的情況下。但是仍然有很多時候你掃描到的標籤不包含NDEF數據或者NDEF數據不能被映射到一個MIME類型或URI。在這些情況下,你需要使用你自己的協議直接與標籤通訊和讀寫信息(在原始字節)。Android通過android.nfc.tech包支持這些情形,在表1有具體描述。你可以使用getTechList()方法確定被支持的標籤技術,用android.nfc.tech包下的類建立相應的TagTechnology對象。
表1. 支持的標籤技術
類(Class) |
描述(Description) |
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 |
提供訪問被格式化的NFC標籤上的NDEF數據和操作 |
NdefFormatable |
提供可能被NDEF格式化的標籤的格式化操作 |
接下來的標籤技術不是被安卓設備支持的。
表2. 可選的支持標籤
類(Class) |
描述(Description) |
MifareClassic |
提供訪問MIFARE傳統屬性和I/O操作,如果安卓設備支持MIFARE. |
MifareUltralight |
提供訪問MIFARE的Ultralight屬性和I/O操作,如果安卓設備支持MIFARE. |
使用標籤技術和ACTION_TECH_DISCOVERED intent(Working with tag technologies and the ACTION_TECH_DISCOVERED intent)
當設備掃描到一個帶有NDEF數據但不能被映射到一個MIME或者URI的標籤,tag dispatch system會試着通過ACTION_TECH_DISCOVERED intent啓動一個activity。當被掃描到帶有non-NDEF數據的標籤的時候ACTION_TECH_DISCOVERED也會被使用。這種保守策略使得當tag dispatch system不能解析你的標籤的時候你仍然能正確處理標籤上的數據。使用標籤技術的基本步驟如下所示:
2. 當你的應用接收到一個intent,得到裏面的Tag對象:
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
3. 得到一個TagTechnology的實例,通過調用android.nfc.tech包下的類的工廠方法:get。你在調用get工廠方法之前可以調用getTechList()列舉被支持的標籤。例如得到一個Tag中的MifareUltralight的實例,像下面這樣:
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
讀寫標籤(Reading and writing to tags)
讀寫NFC標籤包括從標籤中得到intent和跟標籤通訊。你必須定義你自己的協議棧來向標籤讀寫數據。然後需要注意的是,當正確處理了一個標籤你仍然可以讀寫NDEF數據。這取決於你如何組織事務。下面的例子展示瞭如何使用MIFARE Ultralight標籤。
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 closing 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 writing MifareUltralight
message...", e);
} finally {
if (mifare != null) {
try {
mifare.close();
}
catch (IOException e) {
Log.e(TAG, "Error closing tag...", e);
}
}
}
return null;
}
}
使用前臺發佈系統(Using the Foreground Dispatch System)
前臺發佈系統允許activity攔截一個intent並且聲明對處理同一個intent的比其他activity更高的優先權。使用這個系統涉及到構建一些使安卓系統能向你的應用發送合適的intent的數據結構。啓用前臺調度系統:
1. 添加如下代碼到你activity的onCreate()方法中:
1). 創建一個PendingIntent對象使得當標籤被掃描的時候安卓系統可以用標籤描述來填充它。
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
2). 聲明一個intent filter來處理你想攔截的intent。前臺發佈系統在設備掃描標籤的時候通過收到的intent檢查被規定的intent filter。如果匹配,你的應用就處理這個intent。如果不匹配,前臺發佈系統落回intent發佈系統。指定一個intent過濾器和technology過濾器的空數組,指定所有回落到TAG_DISCOVERED intent的你想過濾的標籤。下面的代碼片段處理了所有NDEF_DISCOVERED的MIME類型。你應該只處理你需要的那些。
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, };
3). 創建你的應用程序想處理的標籤技術的數組。調用Object.class.getName()方法來得到你想支持的技術的類。
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
2. 重寫下面的activity生命週期方法,在當activity失去(onPause())和重新獲得(onResume())焦點的時候添加邏輯來啓用和禁用前臺發佈系統。enableForegroundDispatch()必須在主線程中且activity在前臺(在onReaume()中調用以保證效果)的時候調用。你也必須實現onNewIntent回調來處理從NFC標籤中的數據。
public void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
mAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//do something with tagFromIntent
}