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

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

介绍

  1. 支持 AndroidiOSHarmonyOS 的 NFC 读卡能力封装,可用于读取卡片基础信息、NDEF 记录、透传 APDU 以及部分 Mifare 操作。
  2. 适用于 uni-appuni-app x App 平台,不支持 Web 和各类小程序平台。
  3. 读卡流程统一为:先 initNFC 初始化,再 readCard 建立卡片会话,之后调用 transceivereadNDEFRecordsreadBlock 等方法,结束后调用 closeNFC 关闭会话。

猛戳这里去插件市场看看

平台支持

平台 支持情况
Android 支持
iOS 支持
HarmonyOS 支持
Web 不支持
小程序 不支持

API说明

方法名称 参数 返回 说明
initNFC InitNFCParams 回调 ResponseEntity 初始化 NFC 读卡配置,检查权限和设备能力
readCard ReadCardParams 回调 ResponseEntitydataNfcTag 开始轮询卡片并返回卡片信息
transceive TransceiveParams 回调 ResponseEntitydata 为十六进制字符串 与卡片进行 APDU 或原始指令透传
readNDEFRecords ReadNDEFParams 回调 ResponseEntitydataNdefInfo[]JSON数据 读取当前卡片上的 NDEF 记录
writeNDEFRecords WriteNDEFParams 回调 ResponseEntity 写入 NDEF 记录
makeNdefReadOnly MakeNDEFReadOnlyParams 回调 ResponseEntity 将当前 NDEF 标签设置为只读,操作不可逆
authenticateSector AuthenticateSectorParams 回调 ResponseEntitydataboolean 对 Mifare Classic 扇区进行 KeyA 或 KeyB 认证
readSector ReadSectorParams 回调 ResponseEntitydata 为十六进制字符串或 false 读取 Mifare Classic 整个扇区
readBlock ReadBlockParams 回调 ResponseEntitydata 为十六进制字符串或 false 读取 Mifare Classic 块或 Mifare Ultralight 页
writeBlock WriteBlockParams 回调 ResponseEntitydataboolean 写入 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 对 MiFareISO15693 的能力支持。

HarmonyOS 特别说明

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

Android 特别说明

  1. androidSoundandroidCheckNDEFandroidReaderModeFlagsextraReaderPresenceCheckDelay 仅 Android 平台生效。
  2. readBlock / writeBlock 在 Android 侧对 Mifare ClassicMifare UltralightISO15693 的支持相对更完整。

数据结构说明

ResponseEntity

typescript 复制代码
type ResponseEntity = {
  success: boolean
  data?: any | null
  message?: string | null
}

NfcTag

readCard 成功后返回的卡片信息对象,常用字段如下:

  • id:卡片 ID,十六进制字符串
  • type:卡片类型,如 iso7816mifare_classicmifare_ultralightiso15693iso18092
  • 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。后续如果要继续调用 transceivereadNDEFRecordswriteNDEFRecordsreadBlock 等方法,应保持当前会话不要提前关闭。

transceive

向当前卡片发送十六进制指令字符串并接收十六进制字符串响应。调用前必须先成功执行 readCard

readNDEFRecords / writeNDEFRecords

用于读取或写入 NDEF 记录,参数和返回值中的 identifierpayloadtype 均为十六进制字符串。

makeNdefReadOnly

将标签设置为只读,该操作不可恢复,调用前请确认卡片支持且业务允许。

authenticateSector / readSector / readBlock / writeBlock

主要用于 Mifare Classic 与部分 Mifare Ultralight 场景。

  • authenticateSector:对指定扇区认证
  • readSector:读取整个扇区
  • readBlock:读取一个块或页
  • writeBlock:写入一个块或页

注意事项:

  1. keyAkeyB 必须是 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 及更早版本上,如果调用轮询前启用了 readIso18092readIso15693,那么必须先正确配置上面的 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. 使用 transceivereadNDEFRecordswriteNDEFRecordsreadBlockwriteBlock 前,必须先成功调用 readCard
  3. 调用完成后建议执行 closeNFC 关闭会话,避免影响下次读卡。
  4. makeNdefReadOnly 为不可逆操作,请谨慎使用。
  5. 不同平台、不同卡型支持能力不同,业务接入前建议先通过 readCard 返回的 typestandardndefAvailable 等字段进行判断。
相关推荐
刮风那天1 小时前
Android 常驻进程如何被查杀?
android
刮风那天3 小时前
Android 如何降低进程优先级可以被查杀?
android
资源分享助手4 小时前
超级改图P图改字无限制版教程(安卓)AI改图软件、图片改字软件、安卓修图APP、智能消除工具、图片拼接APP、超级改图下载
android·人工智能
Lehjy5 小时前
【Linux】文件系统磁盘存储结构
android·linux·运维
sweet丶5 小时前
iOS应用启动过程深度分析与优化实践
ios
西洼工作室5 小时前
UniApp云开发笔记
前端·笔记·uni-app
BU摆烂会噶5 小时前
【LangGraph】节点内调用与状态隔离
android·人工智能·python·ui·langchain·人机交互
Martin -Tang5 小时前
uniapp 实现录音操作,长按录音,放开取消
前端·javascript·vue.js·uni-app·css3·录音
BU摆烂会噶6 小时前
【LangGraph】作为节点添加与状态共享
android·人工智能·python·ui·langchain·人机交互