高级NFC Advanced NFC
这篇介绍高级NFC主题,比如说使用各种不同的标签诗句,写入nfc标签,和前台派发。前台派发可以让有其他的应用也注册了过滤该intent的过滤器的时候,前台的应用可以截获intent。
使用支持的标签技术 Working with Supported Tag Technologies
当使用NFC标签和Android设备的时候,使用的主要的格式是ndef格式。当扫描到一个NDEF标签,Android系统会提供解析消息成为NdefMessage的支持。但是有一些情况下你会扫描到不包含NDEF格式数据的标签,或者NDEF数据不能为转化成为MIMIE类型或者URI。这种情况下,你需要直接与标签建立连接,并使用你自己定义的协议栈,使用原始字节和标签读写通信。 Android 使用android.nfc.tech包对这种非ndef情况进行提供支持,如表1中所示。你可以使用getTechList方法来判断标签支持的的技术,并且使用android.nfc.tech的类创建与之对应的TagTechnology对象。
表1.
Table 1. 支持的NFC标签技术
Class | Description |
The interface that all tag technology classes must implement. | |
Provides access to NFC-A (ISO 14443-3A) properties and I/O operations. | |
Provides access to NFC-B (ISO 14443-3B) properties and I/O operations. | |
Provides access to NFC-F (JIS 6319-4) properties and I/O operations. | |
Provides access to NFC-V (ISO 15693) properties and I/O operations. | |
Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations. | |
Provides access to NDEF data and operations on NFC tags that have been formatted as NDEF. | |
Provides a format operations for tags that may be NDEF formattable. |
下面是不强求android设备支持的技术。
Table 2. 可选技术
Class | Description |
Provides access to MIFARE Classic properties and I/O operations, if this Android device supports MIFARE. | |
Provides access to MIFARE Ultralight properties and I/O operations, if this Android device supports MIFARE. |
Working with tag technologies and the ACTION_TECH_DISCOVERED intent
当设备扫描到包含NDEF的数据,但是无法将其转化为MIME类型或者URI的时候,或者没有NDEF格式的时候,就会让标签派发系统产生一个ACTION_TECH_DISCOVERED的intent来启动activity。这个备选项可以在系统不能为你解析标签的时候,让你可以直接处理标签。下面是使用标签技术的基本步骤:
1.过滤你想处理的标签技术的ACTION_TECH_DISCOVERED intent。细节可以查看 Filtering for NFC intents。当不含有NDEF格式或者无法转换为MIME或者URI类型的时候,就会启动这种intent,系统如何判定的,可以参见Tag Dispatch System。
2.app接收到intent的时候,从中获取Tag对象。
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
Reading and writing to tags
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的更高的优先级。使用这个系统需要构建一些数据结构,从而使得android的系统可以向你的应用发送正确的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建立过滤器。出现标签时,系统会用过滤器进行匹配,如果成功则activity获得intent,
如果失败则前台派发系统退化为之前的intent派发系统。声明一个null的Filter的数组,和标签技术个过滤器
的数组,然后填入当回退为TAG_DISVOERED intent的时候你想要捕获的intent的类型。下面的代码片是
拦截所有MIME类型的NDEF_DISCOVERED类型的intent的例子,你应该根据你的需要拦截几种。
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.设置你的app想拦截的标签技术的数组。调用Object.class.getName方法来获得你想支持的技术的类。
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
2.重写activity声明周期的回到函数,并且加入随着activity获取焦点(onPause)和失去焦点(onResume)的时候启用和禁用前台派发的逻辑。enableForegroundDispatch一定要从主线程中调用,并且仅当activity在前台的时候才可以(使用onResume来保证)。你还需要实现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
}