Android NFC详解(高级)
Posted 三杯五岳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android NFC详解(高级)相关的知识,希望对你有一定的参考价值。
上一章节讲到了 android NFC的基本应用(Android NFC详解),这章延伸一下,介绍各种高级 NFC 应用,例如如何使用各种标签技术、如何写入 NFC 标签以及如何执行前台调度(借助前台调度,在前台运行的应用即使在其他应用过滤某些 Intent 时也能优先处理这些 Intent)。
使用支持的标签技术
将 NFC 标签与 Android 设备结合使用时,用于读取和写入标签数据的主要格式是 NDEF。当设备扫描具有 NDEF 数据的标签时,Android 会尽可能在解析消息和通过 NdefMessage 传递该消息方面提供支持。不过,在某些情况下,您扫描的标签可能不包含 NDEF 数据,或者 NDEF 数据无法映射为 MIME 类型或 URI。在这些情况下,您需要直接开启与标签的通信,并使用自己的协议(以原始字节形式)对标签执行读写操作。Android 通过 android.nfc.tech 软件包对这些用例提供一般性支持,如表 1 所述。您可以使用 getTechList() 方法确定标签支持的技术,还可以使用 android.nfc.tech 提供的一个类来创建相应的 TagTechnology 对象。
类 | 说明 |
---|---|
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 Classic 属性和 I/O 操作的访问权限(如果此 Android 设备支持 MIFARE)。 |
MifareUltralight | 提供对 MIFARE Ultralight 属性和 I/O 操作的访问权限(如果此 Android 设备支持 MIFARE)。 |
将标签技术和 ACTION_TECH_DISCOVERED Intent 结合使用
当设备扫描包含 NDEF 数据但无法映射为 MIME 或 URI 的标签时,标签调度系统会尝试使用 ACTION_TECH_DISCOVERED Intent 来启动 Activity。在扫描到包含非 NDEF 数据的标签时,也会使用 ACTION_TECH_DISCOVERED。如果标签调度系统无法解析标签数据,此回退功能可让您直接处理标签数据。使用标签技术的基本步骤如下:
- 过滤一个 ACTION_TECH_DISCOVERED Intent,指定您要处理的标签技术。如需了解详情,请参阅过滤 NFC Intent。通常,如果 NDEF 消息无法映射为 MIME 类型或 URI,或者扫描到的标签不包含 NDEF 数据,那么标签调度系统会尝试启动 ACTION_TECH_DISCOVERED Intent。如需详细了解具体的确定方式,请参阅标签调度系统。
- 应用收到 Intent 时,会从该 Intent 获取 Tag 对象:
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- 通过调用 android.nfc.tech 软件包中类的 get 工厂方法,获取 TagTechnology 的实例。您可以枚举支持的标签技术,只需在调用 get 工厂方法之前调用 getTechList() 即可。例如,要从 Tag 获取 MifareUltralight 的实例,请执行以下操作:
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
对标签执行读写操作
对 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 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;
使用前台调度系统
借助前台调度系统,Activity 可以拦截 Intent 并声明自己可优先于其他 Activity 处理同一 Intent。使用此系统涉及为 Android 系统构造一些数据结构,以便将合适的 Intent 发送到您的应用。要启用前台调度系统,请执行以下操作:
a、在 Activity 的 onCreate()
方法中添加以下代码:
- 创建一个 PendingIntent 对象,这样 Android 系统会使用扫描到的标签的详情对其进行填充。
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
- 声明 Intent 过滤器,以处理您要拦截的 Intent。前台调度系统会对照设备扫描标签时所获得的 Intent 来检查所指定的 Intent 过滤器。如果匹配,那么应用会处理该 Intent。如果不匹配,那么前台调度系统会回退到 Intent 调度系统。指定 Intent 过滤器和技术过滤器的
null
数组,以指明要过滤所有回退到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, ;
- 设置应用要处理的一组标签技术。调用
Object.class.getName()
方法以获取要支持的技术的类。techListsArray = new String[][] new String[] NfcF.class.getName() ;
b、替换以下 Activity 生命周期回调,并添加相应逻辑,以分别在 Activity 失去 (onPause()) 焦点和重新获得 (onResume()) 焦点时启用和停用前台调度。enableForegroundDispatch() 必须从主线程调用,并且只能在 Activity 在前台运行时调用(在 onResume() 中调用可确保这一点)。您还需要实现 onNewIntent 回调以处理扫描到的 NFC 标签中的数据。
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
以上是关于Android NFC详解(高级)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Arduino MFRC522 进行 Android NFC 卡仿真
Android 10 NFC 应用程序 - 在 MS Intune Kiosk 模式下手机睡眠时停止工作