NFC读卡能力 支持安卓/iOS/鸿蒙 UTS插件
介绍
- 支持
Android、iOS、HarmonyOS的 NFC 读卡能力封装,可用于读取卡片基础信息、NDEF 记录、透传 APDU 以及部分 Mifare 操作。 - 适用于
uni-app与uni-app xApp 平台,不支持 Web 和各类小程序平台。 - 读卡流程统一为:先
initNFC初始化,再readCard建立卡片会话,之后调用transceive、readNDEFRecords、readBlock等方法,结束后调用closeNFC关闭会话。
平台支持
| 平台 | 支持情况 |
|---|---|
| Android | 支持 |
| iOS | 支持 |
| HarmonyOS | 支持 |
| Web | 不支持 |
| 小程序 | 不支持 |
API说明
| 方法名称 | 参数 | 返回 | 说明 |
|---|---|---|---|
| initNFC | InitNFCParams |
回调 ResponseEntity |
初始化 NFC 读卡配置,检查权限和设备能力 |
| readCard | ReadCardParams |
回调 ResponseEntity,data 为 NfcTag |
开始轮询卡片并返回卡片信息 |
| transceive | TransceiveParams |
回调 ResponseEntity,data 为十六进制字符串 |
与卡片进行 APDU 或原始指令透传 |
| readNDEFRecords | ReadNDEFParams |
回调 ResponseEntity,data 为 NdefInfo[]JSON数据 |
读取当前卡片上的 NDEF 记录 |
| writeNDEFRecords | WriteNDEFParams |
回调 ResponseEntity |
写入 NDEF 记录 |
| makeNdefReadOnly | MakeNDEFReadOnlyParams |
回调 ResponseEntity |
将当前 NDEF 标签设置为只读,操作不可逆 |
| authenticateSector | AuthenticateSectorParams |
回调 ResponseEntity,data 为 boolean |
对 Mifare Classic 扇区进行 KeyA 或 KeyB 认证 |
| readSector | ReadSectorParams |
回调 ResponseEntity,data 为十六进制字符串或 false |
读取 Mifare Classic 整个扇区 |
| readBlock | ReadBlockParams |
回调 ResponseEntity,data 为十六进制字符串或 false |
读取 Mifare Classic 块或 Mifare Ultralight 页 |
| writeBlock | WriteBlockParams |
回调 ResponseEntity,data 为 boolean |
写入 Mifare Classic 块或 Mifare Ultralight 页 |
| closeNFC | CloseNFCParams |
回调 ResponseEntity |
关闭当前 NFC 会话 |
平台差异说明
不同平台底层 NFC 能力不同,部分 API 在三端的支持范围并不完全一致,接入前建议先阅读本节。
| API | Android | iOS | HarmonyOS | 说明 |
|---|---|---|---|---|
| initNFC | 支持 | 支持 | 支持 | 三端都支持初始化,但底层参数映射不完全一致 |
| readCard | 支持 | 支持 | 支持 | 三端都支持读卡与返回基础卡信息 |
| transceive | 支持 | 支持 | 支持 | 三端都支持,但不同卡型支持范围取决于系统底层能力 |
| readNDEFRecords | 支持 | 支持 | 支持 | 当前三端实际返回的 data 为 JSON 字符串格式的记录列表 |
| writeNDEFRecords | 支持 | 支持 | 支持 | 三端都支持 NDEF 写入,但实际可写能力取决于卡片类型与系统支持 |
| makeNdefReadOnly | 支持 | 支持 | 支持 | 三端都支持,但是否允许设只读取决于标签本身 |
| authenticateSector | 支持 | 不支持,固定返回 true |
支持 | iOS 无 Mifare Classic 扇区认证能力;为兼容前置调用链,默认返回成功 |
| readSector | 支持 | 不支持 | 支持 | iOS 当前未实现整扇区读取 |
| readBlock | 支持 | 部分支持 | 部分支持 | iOS 主要支持 MiFare/ISO15693;鸿蒙当前 ISO15693 需走 transceive 兜底 |
| writeBlock | 支持 | 部分支持 | 部分支持 | iOS 主要支持 MiFare/ISO15693;鸿蒙当前 ISO15693 需走 transceive 兜底 |
| closeNFC | 支持 | 支持 | 支持 | 三端都支持关闭当前会话 |
iOS 特别说明
authenticateSector在 iOS 中不支持真实的 Mifare Classic 扇区认证。- 由于很多业务会把
authenticateSector作为后续读写流程的前置 API,为避免直接中断调用链,iOS 侧当前默认返回true。 readSector在 iOS 中不支持,当前会直接返回失败。readBlock/writeBlock在 iOS 中并不是完整对齐 Android 的 Mifare Classic 语义,主要依赖 CoreNFC 对MiFare与ISO15693的能力支持。
HarmonyOS 特别说明
readBlock/writeBlock当前对ISO15693没有直接暴露独立块读写封装,建议通过transceive作为兜底方案。- HarmonyOS 当前实现中,卡片技术类型筛选依赖
readIso14443A、readIso14443B、readIso18092、readIso15693的组合;如果全部关闭,不会自动回退为全卡型扫描。
Android 特别说明
androidSound、androidCheckNDEF、androidReaderModeFlags、extraReaderPresenceCheckDelay仅 Android 平台生效。readBlock/writeBlock在 Android 侧对Mifare Classic、Mifare Ultralight、ISO15693的支持相对更完整。
数据结构说明
ResponseEntity
typescript
type ResponseEntity = {
success: boolean
data?: any | null
message?: string | null
}
NfcTag
readCard 成功后返回的卡片信息对象,常用字段如下:
id:卡片 ID,十六进制字符串type:卡片类型,如iso7816、mifare_classic、mifare_ultralight、iso15693、iso18092standard:卡片协议标准ndefAvailable:是否支持 NDEFndefType:NDEF 标签类型ndefWritable:NDEF 是否可写ndefCanMakeReadOnly:是否可设置为只读mifareInfo:Mifare 相关信息,包含容量、块大小、块数量、扇区数量等
NdefInfo
typescript
type NdefInfo = {
identifier: string
payload: string
type: string
typeNameFormat: string
}
字段均为十六进制字符串,业务层可按需自行转为文本。
快速开始
1. 引入插件
typescript
import * as reader from "@/uni_modules/cz-nfc-reader"
2. 初始化 NFC
typescript
reader.initNFC({
readIso14443A: true,
readIso14443B: true,
readIso15693: true,
readIso18092: true,
completeListener(res) {
if (res.success) {
console.log("NFC 初始化成功")
} else {
console.log(`NFC 初始化失败: ${res.message}`)
}
}
})
3. 读卡并获取卡片信息
typescript
reader.readCard({
completeListener(res) {
if (!res.success || res.data == null) {
console.log(`读卡失败: ${res.message}`)
return
}
const tag = res.data as reader.NfcTag
console.log(`卡号: ${tag.id}`)
console.log(`标准: ${tag.standard}`)
console.log(`类型: ${tag.type}`)
console.log(`支持NDEF: ${tag.ndefAvailable}`)
}
})
4. 读取 NDEF
typescript
reader.readCard({
completeListener(card) {
if (!card.success || card.data == null) {
return
}
const tag = card.data as reader.NfcTag
if (tag.ndefAvailable != true) {
console.log("当前卡片不支持 NDEF")
reader.closeNFC({})
return
}
reader.readNDEFRecords({
cached: true,
completeListener(res) {
console.log(`NDEF 结果: ${res.data}`)
reader.closeNFC({})
}
})
}
})
5. APDU透传示例
typescript
reader.readCard({
completeListener(card) {
if (!card.success || card.data == null) {
return
}
reader.transceive({
capdu: "00A4040009A00000000386980701",
completeListener(res) {
console.log(`透传结果: ${res.success} ${res.data}`)
reader.closeNFC({})
}
})
}
})
常用方法说明
initNFC
用于初始化 NFC 能力和读卡配置。
常用参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| timeout | number |
30000 |
读卡超时时间,单位毫秒,iOS 无效 |
| readIso14443A | boolean |
true |
是否启用 ISO14443A |
| readIso14443B | boolean |
true |
是否启用 ISO14443B |
| readIso18092 | boolean |
false |
是否启用 ISO18092/FeliCa |
| readIso15693 | boolean |
true |
是否启用 ISO15693 |
| androidSound | boolean |
true |
Android 发现标签时是否播放系统音效 |
| androidCheckNDEF | boolean |
true |
Android 是否自动检查 NDEF |
| androidReaderModeFlags | `0x80 | 0x100` | 无 |
| extraReaderPresenceCheckDelay | number |
无 | Android Presence Check 额外延迟 |
| iosAlertMessage | string |
无 | iOS 会话开始提示语 |
| iosMultipleTagMessage | string |
无 | iOS 多标签提示语 |
readCard
启动一次读卡轮询,成功后返回 NfcTag。后续如果要继续调用 transceive、readNDEFRecords、writeNDEFRecords、readBlock 等方法,应保持当前会话不要提前关闭。
transceive
向当前卡片发送十六进制指令字符串并接收十六进制字符串响应。调用前必须先成功执行 readCard。
readNDEFRecords / writeNDEFRecords
用于读取或写入 NDEF 记录,参数和返回值中的 identifier、payload、type 均为十六进制字符串。
makeNdefReadOnly
将标签设置为只读,该操作不可恢复,调用前请确认卡片支持且业务允许。
authenticateSector / readSector / readBlock / writeBlock
主要用于 Mifare Classic 与部分 Mifare Ultralight 场景。
authenticateSector:对指定扇区认证readSector:读取整个扇区readBlock:读取一个块或页writeBlock:写入一个块或页
注意事项:
keyA、keyB必须是 6 字节十六进制字符串,例如FFFFFFFFFFFF。- Mifare Classic 单块写入数据长度必须为 16 字节。
- Mifare Ultralight 单页写入数据长度必须为 4 字节。
closeNFC
结束当前 NFC 会话。建议每次读卡、透传、读写 NDEF 或块操作完成后都调用一次,避免会话残留。
完整示例
typescript
import * as reader from "@/uni_modules/cz-nfc-reader"
export default {
methods: {
startRead() {
reader.initNFC({
readIso14443A: true,
readIso14443B: true,
readIso15693: true,
readIso18092: true,
completeListener: (initRes) => {
if (!initRes.success) {
uni.showModal({
content: initRes.message ?? "初始化失败",
showCancel: false
})
return
}
reader.readCard({
completeListener: (cardRes) => {
if (!cardRes.success || cardRes.data == null) {
uni.showModal({
content: cardRes.message ?? "读卡失败",
showCancel: false
})
return
}
const tag = cardRes.data as reader.NfcTag
console.log(`卡片信息: ${JSON.stringify(tag)}`)
if (tag.ndefAvailable == true) {
reader.readNDEFRecords({
cached: true,
completeListener: (ndefRes) => {
console.log(`NDEF: ${JSON.stringify(ndefRes.data)}`)
reader.closeNFC({})
}
})
} else {
reader.closeNFC({})
}
}
})
}
})
}
}
}
权限说明
Android
插件已包含 NFC 权限声明:
xml
<uses-permission android:name="android.permission.NFC"/>
iOS
插件已包含以下配置:
xml
/// Info.plist 参考配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NFCReaderUsageDescription</key>
<string>需要使用NFC读取卡片信息</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>nfc</string>
</array>
<key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
<array>
<string>88B4</string>
</array>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A00000000386980701</string>
</array>
</dict>
</plist>
/// UTS.entitlements 参考配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
<string>NDEF</string>
</array>
</dict>
</plist>
同时已预置 FeliCa 与 ISO7816 相关会话配置。
iOS 侧还需要注意以下事项:
- 插件要求
iOS 13+。 - 需要在项目的
UTS.entitlements中添加Near Field Communication Tag Reader Session Formats能力。 - 需要在
Info.plist中添加NFCReaderUsageDescription。 - 根据业务需要,在
Info.plist中添加:com.apple.developer.nfc.readersession.felica.systemcodescom.apple.developer.nfc.readersession.iso7816.select-identifiers
- 特别注意:在
iOS 14.5及更早版本上,如果调用轮询前启用了readIso18092或readIso15693,那么必须先正确配置上面的 FeliCa / ISO7816 相关项。否则受CoreNFC已知问题影响,设备 NFC 可能在重启前都不可用。 - 如果是原生工程联调,打开
Runner.xcworkspace,进入 Xcode 的项目设置页面,在Signing & Capabilities中为目标应用添加Near Field Communication Tag Reading能力。
HarmonyOS
插件已声明:
json
{
"requestPermissions": [
{
"name": "ohos.permission.NFC_TAG"
}
]
}
注意事项
- 仅支持手机真机调试,不支持模拟器。
- 使用
transceive、readNDEFRecords、writeNDEFRecords、readBlock、writeBlock前,必须先成功调用readCard。 - 调用完成后建议执行
closeNFC关闭会话,避免影响下次读卡。 makeNdefReadOnly为不可逆操作,请谨慎使用。- 不同平台、不同卡型支持能力不同,业务接入前建议先通过
readCard返回的type、standard、ndefAvailable等字段进行判断。