NFC读卡能力 支持安卓/iOS/鸿蒙 UTS插件

NFC读卡能力 支持安卓/iOS/鸿蒙 UTS插件

介绍

  1. 支持 Android、iOS、HarmonyOS 的 NFC 读卡能力封装,可用于读取卡片基础信息、NDEF 记录、透传 APDU 以及部分 Mifare 操作。
  2. 适用于 uni-app 与 uni-app x App 平台,不支持 Web 和各类小程序平台。
  3. 读卡流程统一为:先 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 特别说明

  1. authenticateSector 在 iOS 中不支持真实的 Mifare Classic 扇区认证。
  2. 由于很多业务会把 authenticateSector 作为后续读写流程的前置 API,为避免直接中断调用链,iOS 侧当前默认返回 true。
  3. readSector 在 iOS 中不支持,当前会直接返回失败。
  4. readBlock / writeBlock 在 iOS 中并不是完整对齐 Android 的 Mifare Classic 语义,主要依赖 CoreNFC 对 MiFare 与 ISO15693 的能力支持。

HarmonyOS 特别说明

  1. readBlock / writeBlock 当前对 ISO15693 没有直接暴露独立块读写封装,建议通过 transceive 作为兜底方案。
  2. HarmonyOS 当前实现中,卡片技术类型筛选依赖 readIso14443A、readIso14443B、readIso18092、readIso15693 的组合;如果全部关闭,不会自动回退为全卡型扫描。

Android 特别说明

  1. androidSound、androidCheckNDEF、androidReaderModeFlags、extraReaderPresenceCheckDelay 仅 Android 平台生效。
  2. 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、iso18092
  • standard:卡片协议标准
  • ndefAvailable:是否支持 NDEF
  • ndefType: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:写入一个块或页

注意事项:

  1. keyA、keyB 必须是 6 字节十六进制字符串,例如 FFFFFFFFFFFF。
  2. Mifare Classic 单块写入数据长度必须为 16 字节。
  3. 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 侧还需要注意以下事项:

  1. 插件要求 iOS 13+。
  2. 需要在项目的 UTS.entitlements 中添加 Near Field Communication Tag Reader Session Formats 能力。
  3. 需要在 Info.plist 中添加 NFCReaderUsageDescription。
  4. 根据业务需要,在 Info.plist 中添加:
    • com.apple.developer.nfc.readersession.felica.systemcodes
    • com.apple.developer.nfc.readersession.iso7816.select-identifiers
  5. 特别注意:在 iOS 14.5 及更早版本上,如果调用轮询前启用了 readIso18092 或 readIso15693,那么必须先正确配置上面的 FeliCa / ISO7816 相关项。否则受 CoreNFC 已知问题影响,设备 NFC 可能在重启前都不可用。
  6. 如果是原生工程联调,打开 Runner.xcworkspace,进入 Xcode 的项目设置页面,在 Signing & Capabilities 中为目标应用添加 Near Field Communication Tag Reading 能力。

HarmonyOS

插件已声明:

json 复制代码
{
  "requestPermissions": [
    {
      "name": "ohos.permission.NFC_TAG"
    }
  ]
}

注意事项

  1. 仅支持手机真机调试,不支持模拟器。
  2. 使用 transceive、readNDEFRecords、writeNDEFRecords、readBlock、writeBlock 前,必须先成功调用 readCard。
  3. 调用完成后建议执行 closeNFC 关闭会话,避免影响下次读卡。
  4. makeNdefReadOnly 为不可逆操作,请谨慎使用。
  5. 不同平台、不同卡型支持能力不同,业务接入前建议先通过 readCard 返回的 type、standard、ndefAvailable 等字段进行判断。
相关推荐
大圣编蚕6 小时前
初探 NDK 的世界:从零开始理解 Android 原生开发
android
云贝贝贝6 小时前
MySQL 慢查询定位与索引优化实战
android
骑着蜗牛撵大象3277 小时前
服务下线不再炸:分层关闭、TCP 存活探测与负载均衡排水的落地套路
android·tcp/ip·负载均衡·tcp·高可用·健康检查·优雅关闭
Geek_Vison7 小时前
保险APP已经用了Flutter,还能接入小程序吗?
flutter·小程序·uni-app·mpaas·小程序容器
老李IT笔记8 小时前
设备指纹由哪几个字段拼出来:换一块主板会变成新设备
ios·智能手机
三少爷的鞋9 小时前
别再这么写协程了!Marcin Moskała 剖析的 几个常见协程误区与重构
android
andyweike9 小时前
iOS App 测试
ios·测试·ad hoc·分发
mmsx10 小时前
Android 防二次打包第一道锁:签名校验与完整性校验
android·kotlin
mmsx10 小时前
Android 混淆不等于安全:二次打包链路完整走一遍
android·kotlin
小宋102112 小时前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归