Android NFC 开发详解
1、NFC 开发概述
NFC(Near Field Communication,近场通信)是一种短距离无线通信技术,允许设备在短距离内(通常 10 厘米以内)进行数据交换。Android 从 2.3(API 9)开始支持 NFC,并在后续版本中不断完善 NFC 功能。
核心概念:
- NFC 标签:包含数据的被动设备,如 NFC 卡片、贴纸等
- NFC 读卡器模式:读取 NFC 标签数据
- NFC 写卡模式:向 NFC 标签写入数据
- NFC 点对点模式:两个 NFC 设备之间交换数据
- NDEF:NFC 数据交换格式,标准化的数据格式
应用场景:
- 门禁卡、公交卡模拟
- 移动支付
- 智能标签读取
- 设备配对
- 数据传输
设备要求:
- Android 设备需要具备 NFC 硬件
- Android 2.3 及以上版本
- 需要 NFC 相关权限
2、NFC 权限和配置
2.1、权限声明
在 AndroidManifest.xml 中添加 NFC 权限:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />2.2、Intent Filter 配置
配置 Activity 以接收 NFC Intent:
<activity android:name=".NfcActivity">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>2.3、技术过滤器配置
在 res/xml/nfc_tech_filter.xml 中配置支持的 NFC 技术:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.Ndef</tech>
<tech>android.nfc.tech.NdefFormatable</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.MifareClassic</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.MifareUltralight</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcB</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
</resources>2.4、检查 NFC 支持
在代码中检查设备是否支持 NFC:
NfcManager nfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
NfcAdapter nfcAdapter = nfcManager.getDefaultAdapter();
if (nfcAdapter == null) {
// 设备不支持 NFC
return;
}
if (!nfcAdapter.isEnabled()) {
// NFC 未开启,引导用户开启
Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);
startActivity(intent);
}3、NFC 标签读取
3.1、前台调度系统
使用前台调度系统读取 NFC 标签:
private NfcAdapter nfcAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] intentFilters;
private String[][] techLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化 NFC Adapter
NfcManager nfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
nfcAdapter = nfcManager.getDefaultAdapter();
// 创建 PendingIntent
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
PendingIntent.FLAG_IMMUTABLE);
// 创建 Intent Filter
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
intentFilters = new IntentFilter[] { ndef };
// 设置技术列表
techLists = new String[][] {
new String[] { Ndef.class.getName() },
new String[] { NfcA.class.getName() }
};
}
@Override
protected void onResume() {
super.onResume();
if (nfcAdapter != null) {
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, techLists);
}
}
@Override
protected void onPause() {
super.onPause();
if (nfcAdapter != null) {
nfcAdapter.disableForegroundDispatch(this);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
// 处理 NFC 标签
processNfcTag(intent);
}
}3.2、解析 NDEF 消息
解析 NFC 标签中的 NDEF 消息:
private void processNfcTag(Intent intent) {
// 获取 NDEF 消息
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
NdefMessage[] msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
}
// 解析 NDEF 消息
for (NdefMessage msg : msgs) {
for (NdefRecord record : msg.getRecords()) {
// 解析记录
parseNdefRecord(record);
}
}
} else {
// 处理非 NDEF 标签
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
processTag(tag);
}
}
private void parseNdefRecord(NdefRecord record) {
// 检查 MIME 类型
String mimeType = record.toMimeType();
// 解析文本记录
if (mimeType != null && mimeType.equals("text/plain")) {
byte[] payload = record.getPayload();
String text = new String(payload);
System.out.println("文本内容:" + text);
}
// 解析 URI 记录
if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN &&
Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
Uri uri = record.toUri();
System.out.println("URI:" + uri.toString());
}
}3.3、读取标签 ID 和技术
读取 NFC 标签的基本信息:
private void processTag(Tag tag) {
// 获取标签 ID
byte[] id = tag.getId();
String idString = bytesToHexString(id);
System.out.println("标签 ID:" + idString);
// 获取标签支持的技术
String[] techList = tag.getTechList();
for (String tech : techList) {
System.out.println("支持技术:" + tech);
}
// 读取 MifareClassic 卡
MifareClassic mifareClassic = MifareClassic.get(tag);
if (mifareClassic != null) {
readMifareClassic(mifareClassic);
}
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}4、NFC 标签写入
4.1、写入 NDEF 数据
向 NFC 标签写入 NDEF 数据:
private void writeNdefTag(Tag tag, String text) {
// 创建 NDEF 记录
NdefRecord textRecord = NdefRecord.createTextRecord("en", text);
// 创建 NDEF 消息
NdefMessage message = new NdefMessage(new NdefRecord[] { textRecord });
// 获取 Ndef 对象
Ndef ndef = Ndef.get(tag);
if (ndef != null) {
try {
// 连接标签
ndef.connect();
// 检查是否可写
if (!ndef.isWritable()) {
System.out.println("标签不可写");
return;
}
// 检查容量
if (ndef.getMaxSize() < message.getByteArrayLength()) {
System.out.println("标签容量不足");
return;
}
// 写入数据
ndef.writeNdefMessage(message);
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ndef.close();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
// 格式化并写入
formatAndWrite(tag, message);
}
}4.2、格式化标签
格式化未初始化的 NFC 标签:
private void formatAndWrite(Tag tag, NdefMessage message) {
NdefFormatable formatable = NdefFormatable.get(tag);
if (formatable != null) {
try {
formatable.connect();
formatable.format(message);
System.out.println("格式化并写入成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
formatable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}4.3、写入 URI
向 NFC 标签写入 URI:
private void writeUriTag(Tag tag, String uriString) {
// 创建 URI 记录
Uri uri = Uri.parse(uriString);
NdefRecord uriRecord = NdefRecord.createUri(uri);
// 创建 NDEF 消息
NdefMessage message = new NdefMessage(new NdefRecord[] { uriRecord });
// 写入标签
writeNdefMessage(tag, message);
}4.4、写入外部类型数据
写入自定义类型数据:
private void writeExternalTypeTag(Tag tag, String domain, String type, byte[] data) {
// 创建外部类型记录
NdefRecord record = NdefRecord.createExternal(domain, type, data);
// 创建 NDEF 消息
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
// 写入标签
writeNdefMessage(tag, message);
}5、实际应用与最佳实践
5.1、智能名片应用
实现 NFC 智能名片功能:
public class NfcBusinessCard {
private NfcAdapter nfcAdapter;
// 写入名片信息
public void writeBusinessCard(Tag tag, String name, String phone, String email) {
// 创建 vCard 数据
String vCard = "BEGIN:VCARD\n" +
"VERSION:3.0\n" +
"FN:" + name + "\n" +
"TEL:" + phone + "\n" +
"EMAIL:" + email + "\n" +
"END:VCARD";
// 创建 NDEF 记录
NdefRecord record = NdefRecord.createMime("text/vcard", vCard.getBytes());
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
// 写入标签
writeNdefMessage(tag, message);
}
// 读取名片信息
public void readBusinessCard(Intent intent) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null && rawMsgs.length > 0) {
NdefMessage msg = (NdefMessage) rawMsgs[0];
NdefRecord record = msg.getRecords()[0];
if (record.toMimeType().equals("text/vcard")) {
String vCard = new String(record.getPayload());
parseVCard(vCard);
}
}
}
private void parseVCard(String vCard) {
// 解析 vCard 数据
String[] lines = vCard.split("\n");
for (String line : lines) {
if (line.startsWith("FN:")) {
String name = line.substring(3);
System.out.println("姓名:" + name);
} else if (line.startsWith("TEL:")) {
String phone = line.substring(4);
System.out.println("电话:" + phone);
} else if (line.startsWith("EMAIL:")) {
String email = line.substring(6);
System.out.println("邮箱:" + email);
}
}
}
}5.2、智能标签应用
实现智能标签功能:
public class SmartTagManager {
// 写入智能标签
public void writeSmartTag(Tag tag, String action, String data) {
JSONObject json = new JSONObject();
try {
json.put("action", action);
json.put("data", data);
json.put("timestamp", System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
NdefRecord record = NdefRecord.createMime("application/json", json.toString().getBytes());
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
writeNdefMessage(tag, message);
}
// 处理智能标签
public void handleSmartTag(Intent intent) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null && rawMsgs.length > 0) {
NdefMessage msg = (NdefMessage) rawMsgs[0];
NdefRecord record = msg.getRecords()[0];
if (record.toMimeType().equals("application/json")) {
String jsonStr = new String(record.getPayload());
try {
JSONObject json = new JSONObject(jsonStr);
String action = json.getString("action");
String data = json.getString("data");
// 执行相应操作
executeAction(action, data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void executeAction(String action, String data) {
switch (action) {
case "open_url":
// 打开网页
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(data));
startActivity(intent);
break;
case "open_app":
// 打开应用
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(data);
if (launchIntent != null) {
startActivity(launchIntent);
}
break;
case "wifi_config":
// 配置 WiFi
configureWifi(data);
break;
}
}
}5.3、注意事项
权限处理:
- 在 AndroidManifest.xml 中声明 NFC 权限
- 检查设备是否支持 NFC
- 检查 NFC 是否开启
生命周期管理:
- 在 onResume() 中启用前台调度
- 在 onPause() 中禁用前台调度
- 正确处理 onNewIntent()
性能优化:
- 避免在主线程执行耗时操作
- 及时关闭 NFC 标签连接
- 缓存常用数据
错误处理:
- 处理标签连接失败
- 处理写入失败
- 处理标签容量不足
- 提供友好的错误提示
用户体验:
- 提供清晰的 NFC 操作提示
- 显示标签读取/写入进度
- 提供操作成功/失败反馈
- 支持多种标签类型
Android NFC 开发通过 NfcAdapter 和相关 API 实现,可以方便地读取和写入 NFC 标签。掌握 NDEF 格式和 NFC 标签操作方法是 NFC 开发的关键。
在实际开发中:
- 正确配置 NFC 权限和 Intent Filter
- 使用前台调度系统处理 NFC 标签
- 支持多种 NFC 标签类型
- 提供良好的用户体验和错误处理
- 注意性能优化和安全性
Android NFC 开发为移动应用提供了丰富的交互方式,通过合理的设计和实现,可以打造出功能强大、用户体验优秀的 NFC 应用。

