更新记录

1.0.0(2026-08-21)

  • 初版发布:一套面向 uni-app / uni-app x 的跨端 NFC 能力插件(UTS API 插件)。
  • 对外 API 契约统一语义化命名:类型 NfcError / TagSnapshot / NfcResult / NdefRecordInput / DispatchDiagnostics / ScannerRuntime / IosWorkbench / TagListener;函数如 isNfcSupported / startTagScan / readMifareClassicSector / transceiveIsoDep / writeNdefRecords / startSession 等。
  • Android 原生层:NfcBridge(桥接)、NfcKernel(NFC 引擎)、NfcTransitActivity(前台分发中转)。
  • iOS 原生层:NfcBridgeIOS(CoreNFC)。
  • HarmonyOS 原生层:NfcBridge(@ohos.nfc.tag / controller)。
  • 微信小程序(Android):基于 wx.getNFCAdapter() 实现标签扫描/监听与 NDEF 文本写入,读写类接口提供 *Async 异步变体;iOS 微信返回 9010007。
  • 三端均提供同步函数与 *Async 异步变体。

平台兼容性

uni-app(5.13)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - -

uni-app x(5.13)

Chrome Safari Android iOS 鸿蒙 微信小程序

lime-nfc

面向 uni-app / uni-app x 的跨端 NFC 能力插件(以函数式 UTS API 为主,附一个演示组件便于快速预览)。提供标签发现、NDEF 读写、Mifare Classic/Ultralight 读写、IsoDep/NfcV 透传等能力,覆盖 Android、iOS、HarmonyOS、微信小程序(Android)。

安装

插件市场导入,在页面引入,自定义基座。

自定义基座说明

  • 本插件使用 UTS 原生能力,必须在自定义基座中运行,标准基座无法使用。
  • CLI 项目特别注意:请检查根目录 package.json,确保所有 @dcloudio/* 相关包的版本号一致,且与当前 HBuilderX 版本对齐。版本不一致会导致自定义基座编译失败或运行异常。

代码演示

// TS 环境:导入所需的选项/数据类型,并用 `as` 标注选项对象以获得类型校验
import type {
  ActionOptions,
  WatchOptions,
  TextWriteOptions,
  TagSnapshot
} from '@/uni_modules/lime-nfc'
import {
  isNfcSupported,
  isNfcEnabled,
  openSystemNfcSettings,
  startTagScan,
  setTagListener,
  writeTextToTag
} from '@/uni_modules/lime-nfc'

// 建议放在页面 onLoad / 按钮回调等函数内执行,避免顶层直接 return
function runNfcDemo() {
  if (!isNfcSupported()) {
    console.log('设备不支持 NFC')
    return
  }

  if (!isNfcEnabled()) {
    openSystemNfcSettings({
      fail: (err) => console.log(err.errMsg)
    } as ActionOptions)
  }

  // 方式一:回调监听
  startTagScan({
    success: (tag: TagSnapshot) => {
      console.log('发现标签', tag.serialHex, tag.textContent)
    },
    fail: (err) => {
      console.log('监听失败', err.errCode, err.errMsg)
    }
  } as WatchOptions)

  // 方式二:设置全局监听
  setTagListener((tag: TagSnapshot) => {
    console.log('标签到达', tag)
  })

  // 写入文本
  writeTextToTag({
    content: 'hello lime-nfc',
    success: () => console.log('写入成功'),
    fail: (err) => console.log('写入失败', err.errMsg)
  } as TextWriteOptions)
}

TS 与非 TS 的差异:在 TypeScript / uni-app x 中,选项对象建议用对应的选项类型(ActionOptions / WatchOptions / TextWriteOptions 等)做 as 标注;在非 TS 环境(普通 JS / 纯 UTS)中,无需 import type 这些类型,也不必写 as,直接传对象即可。

演示组件:导入后也可直接使用内置演示组件查看效果(代码位于 uni_modules/lime-nfc/components/lime-nfc):

<lime-nfc />

能力索引(意图 → 函数)

不确定用哪个函数时,先在这里按「你想做什么」定位。带「异步版本」的函数在微信小程序等异步平台必须用其 *Async 形态。

你想做什么 推荐函数 异步版本 备注
判断设备是否支持 NFC isNfcSupported 返回 false 时其余接口返回 9010001
判断 NFC 是否已开启 isNfcEnabled 关闭时读写失败 9010002(iOS 上该路径不可达,见下文)
引导用户打开 NFC 设置 openSystemNfcSettings 失败 9010006
开始监听标签(回调式) startTagScan 发现即回调 TagSnapshot
设置全局常驻监听 setTagListener null 解除
停止标签监听 stopTagScan 彻底停止并释放
恢复挂起的监听 resumeTagScan 沿用上次回调
主动读取最近一次标签 getLastTag clearAfterRead 防重复
清空标签缓冲 clearTagBuffer 批处理后调用
获取上次触碰时间 getLastTapTime 毫秒时间戳
写入 NDEF 文本 writeTextToTag 最常见写入
写入多条 NDEF 记录 writeNdefRecords writeNdefRecordsAsync 文本/URI 混合
写 Mifare Classic 块 writeMifareClassicBlock writeMifareClassicBlockAsync 需密钥认证
写 Mifare Ultralight 页 writeMifareUltralightPage writeMifareUltralightPageAsync 每页 4 字节
读 Mifare Classic 扇区 readMifareClassicSector readMifareClassicSectorAsync 整扇区
读 Mifare Classic 块 readMifareClassicBlock readMifareClassicBlockAsync 单块 16 字节
读 Mifare Ultralight 页 readMifareUltralightPages readMifareUltralightPagesAsync 连续多页
发送 APDU 透传(IsoDep) transceiveIsoDep transceiveIsoDepAsync 自定义/金融卡底层
发送指令透传(NfcV) transceiveNfcV transceiveNfcVAsync ISO 15693
配置扫描调度策略 configureScanner 防抖/去重/租约
批量取出标签 getTagBatch 配合 clearAfterRead
探测待处理 Intent probeTagIntent Android 冷启动补处理
暂停/恢复前台扫描 pauseForegroundScan / resumeForegroundScan 临时挂起
排查调度问题 getDispatchDiagnostics 为何没收到标签
查看运行时状态 getScannerRuntime 含已生效策略
查看 iOS 工作台 getIosWorkbench 仅 iOS 有意义
开启/结束会话 startSession / stopSession iOS 需显式开启

错误码

错误码 含义
9010001 当前设备不支持 NFC 功能
9010002 当前设备的 NFC 开关未开启
9010003 启动标签监听失败
9010004 写入标签失败
9010005 读取/透传失败(标签不支持、密钥认证失败或连接失败)
9010006 无法打开系统 NFC 设置页
9010007 当前平台暂未提供此能力
9010008 没有可用的活动标签
9010009 传入参数不合法

平台支持与权限

平台 状态
Android 完整实现(原生 NFC 引擎)
iOS 完整实现(CoreNFC)
HarmonyOS 完整实现(@ohos.nfc.tag / controller)
微信小程序 Android 微信可用(wx.getNFCAdapter 标签读写监听);iOS 微信返回 9010007
Web 兜底实现(返回 9010007 当前平台暂未提供此能力)

iOS 上 Mifare Classic 相关接口按平台能力返回占位错误,与系统 CoreNFC 限制一致。微信小程序读写底层为异步回调模型,读写为 *Async 异步接口,同步读写接口返回“请改用 *Async”提示。

  • Android:宿主工程 manifest.json 需声明 android.permission.NFC,插件已内置前台分发 Activity 与 tech 列表(res/xml/nfc_tech_routes.xml)。
  • iOS:需在 Info.plist 配置 NFC 读取权限描述与 Near Field Communication Tag Reading 能力(插件已内置示例),并部署到 iOS 13+。
  • HarmonyOS:模块已声明 ohos.permission.NFC_TAG 权限。
  • 微信小程序:使用 wx.getNFCAdapter(),需在微信开发者工具中开启 NFC 接口权限;仅 Android 微信支持标签读写。

API 参考

下面以函数为列表逐一说明:每个函数写明用途参数(含 options 的实际字段)返回

设备与状态

isNfcSupported(): boolean

判断当前设备是否支持 NFC。返回 false 时其余接口会返回 9010001,建议在调用任何读写/监听前先调用。

isNfcEnabled(): boolean

判断 NFC 是否已开启。返回 false 时扫描/写入会失败并返回 9010002,应先引导用户开启。

iOS 上 isNfcEnabledisNfcSupported 等价:CoreNFC 没有单独查询「系统 NFC 开关是否打开」的公开 API(仅 NFReaderSession.readingAvailable 合并了硬件 / 权限 / 限制),二者取同一来源。详见平台差异速记

openSystemNfcSettings(options: ActionOptions): void

跳转系统 NFC 设置页,引导用户开启 NFC。失败时 fail 携带 9010006

标签扫描与监听

startTagScan(options: WatchOptions): void

开始标签监听(回调式)。发现标签即触发 success(tag: TagSnapshot),同时 complete 也会触发。内部先校验 isNfcSupported(不支持 → 9010001)与 isNfcEnabled(未开启 → 9010002),启动失败 → 9010003

在 iOS 上由于 isNfcEnabledisNfcSupported 等价,9010002 路径实际不可达;装置缺失或受限会走 9010001,其余连接 / 权限问题由 beginWatcher 失败转为 9010003

stopTagScan(options: ActionOptions): void

彻底停止标签监听并释放前台分发。

resumeTagScan(): void

恢复此前被挂起的监听,沿用上一次 startTagScan 注册的回调。

setTagListener(listener: TagListener): void

设置全局常驻监听。传入回调函数后,任意标签到达都会回调;传入 null 解除监听。

getLastTag(clearAfterRead: boolean): TagSnapshot | null

主动取出最近一次发现的标签快照;clearAfterReadtrue 时取走即清空,避免重复处理。无可用标签返回 null

clearTagBuffer(): void

清空标签缓冲队列,通常在批量处理(getTagBatch)后调用。

getLastTapTime(): number

返回上次触碰标签的毫秒时间戳。

标签写入

writeTextToTag(options: TextWriteOptions): void

最简单的文本写入:将 options.content 作为 NDEF 文本写入标签。失败 fail 携带 9010004

writeNdefRecords(records: NdefRecordInput[]): NfcResult

写入多条 NDEF 记录(文本 / URI 混合等)。返回 NfcResult,成功 payload{ recordCount };记录为空 → 9010009,写入失败 → 9010004

writeMifareClassicBlock(block: number, keySlot: string, keyHex: string, dataHex: string): NfcResult

写入 Mifare Classic 指定块(16 字节)。keySlot'A''B'(密钥槽),keyHex 为 6 字节(12 位十六进制)密钥,dataHex 为 16 字节(32 位十六进制)数据。密钥非 12 位 → 9010009,认证失败 → 9010005

writeMifareUltralightPage(page: number, dataHex: string): NfcResult

写入 Mifare Ultralight 指定页(每页 4 字节)。dataHex 为 4 字节(8 位十六进制)数据。

标签读取与透传

readMifareClassicSector(sector: number, keySlot: string, keyHex: string): NfcResult

读取 Mifare Classic 整个扇区。成功 payload{ sector, blocks: string[] }(每块 16 字节十六进制)。无标签 → 9010008,不支持/认证失败 → 9010005

微信小程序端当前固定读取 4 块/扇区(标准 1K 卡即整扇区;4K 卡的大扇区含 16 块时可能读不全);iOS 该接口返回 9010007 占位,仅 Android / HarmonyOS 原生实现按实际扇区大小完整读取。

readMifareClassicBlock(block: number, keySlot: string, keyHex: string): NfcResult

读取 Mifare Classic 单块(16 字节)。成功 payload{ block, hex }

readMifareUltralightPages(startPage: number, pageCount: number): NfcResult

读取 Mifare Ultralight 连续多页(每次以 4 页为单位读取)。成功 payload{ startPage, packets: string[] }

transceiveIsoDep(apduHex: string): NfcResult

向 IsoDep 标签透传 APDU 指令(金融卡 / 自定义协议底层)。apduHex 为十六进制指令。成功 payload{ hex }(响应)。

transceiveNfcV(commandHex: string): NfcResult

向 NfcV(ISO 15693)标签透传指令。成功 payload{ hex }

异步变体(Async)

微信小程序等异步平台必须使用以下 *Async 版本;同步版本在微信小程序会直接提示「请改用 *Async」。它们返回 Promise<NfcResult>,可直接 await

  • readMifareClassicSectorAsync(sector, keySlot, keyHex): Promise<NfcResult>
  • readMifareClassicBlockAsync(block, keySlot, keyHex): Promise<NfcResult>
  • readMifareUltralightPagesAsync(startPage, pageCount): Promise<NfcResult>
  • transceiveIsoDepAsync(apduHex): Promise<NfcResult>
  • transceiveNfcVAsync(commandHex): Promise<NfcResult>
  • writeNdefRecordsAsync(records): Promise<NfcResult>
  • writeMifareClassicBlockAsync(block, keySlot, keyHex, dataHex): Promise<NfcResult>
  • writeMifareUltralightPageAsync(page, dataHex): Promise<NfcResult>

参数与返回结构与对应的同步版本一致。

调度治理

configureScanner(options: ScanPolicy | null): void

配置扫描调度策略(防抖、去重、前台通道等)。传入 null 为安全空操作:不改变任何策略、直接返回(各端实现均为 no-op)。ScanPolicy 字段:

字段 类型 含义
frontScanLane 'reader' \| 'dispatch' 前台扫描通道
omitNdefSurvey boolean 跳过 NDEF 探测
echoShieldMs number 回声屏蔽时长(毫秒)
sessionLeaseMs number 会话租约时长
inboxCap number 收件箱容量上限
repeatWindowMs number 重复去重窗口
hotTagHoldMs number 热标签保持时长
pendingLimit number 待处理上限

getTagBatch(clearAfterRead: boolean, maxCount: number): TagSnapshot[]

批量取出当前缓冲的标签(最多 maxCount 条),clearAfterReadtrue 时取走即清空。配合 configureScanner 的去重与 clearTagBuffer 使用。

probeTagIntent(): boolean

探测并补偿处理待处理的 Android 系统 NFC Intent(常用于冷启动后补处理),返回是否有待处理 Intent。

resumeForegroundScan(): boolean

恢复前台扫描,返回是否成功恢复。

pauseForegroundScan(): void

临时挂起前台扫描(不释放监听),可用 resumeForegroundScan 恢复。

诊断与运行时

getDispatchDiagnostics(): DispatchDiagnostics | null

获取调度诊断信息,用于排查「为何没收到标签」:lastIngressAt / lastIngressSource / lastIngressSerial / lastIngressAction / cachedCount / foregroundArmed

getScannerRuntime(): ScannerRuntime | null

获取扫描运行时状态,含已生效策略 appliedPolicy、最近一次触碰信息、bridgeLane 等。

getIosWorkbench(): IosWorkbench | null

获取 iOS 工作台信息(仅 iOS 有意义):系统版本、阅读器可达性、会话/观察者/监听器绑定状态、当前驻留标签、队列深度与已配置的去重/保持窗口等。

会话

iOS 上 NFC 需显式开启会话(弹出系统扫描 sheet),其他平台可忽略。

startSession(): void

开启 NFC 会话(iOS 弹窗)。

stopSession(): void

结束 NFC 会话。

数据类型(数据模型)

所有类型均可在 TS 环境下通过 import type 引入:

import type {
  NfcError, TagSnapshot, NfcResult, NdefRecordInput,
  DispatchDiagnostics, ScannerRuntime, IosWorkbench,
  ActionOptions, WatchOptions, TextWriteOptions, ScanPolicy, TagListener
} from '@/uni_modules/lime-nfc'

通用回调语义:操作类函数的 options 均含 success / fail / complete 三个回调字段。fail 携带 NfcError{ errCode, errSubject, errMsg }),complete 无论成败都会触发。

类型 含义 / 关键字段
NfcError 失败回调携带的错误:{ errCode, errSubject, errMsg }errCode错误码errSubject 为出错子系统(如 dispatch / ndef / classic);errMsg 为可读描述。
NdefRecordInput 构造 NDEF 记录的输入:{ kind: string, value: string }kind 为记录类型(text / uri 等),value 为对应内容。
TagSnapshot 标签快照:serialHex(UID 十六进制)、techNames: string[]textContent: string \| nulllinkContent: string \| nullndefLines: string[]actionName: stringdetectedAt: numberextraBag: UTSJSONObject \| null
NfcResult 读写/透传类函数的返回值:{ ok, code, message, payload }code0 表示成功,非 0 为错误码;payload 为业务数据(见各函数说明)。
DispatchDiagnostics 调度诊断:lastIngressAt / lastIngressSource / lastIngressSerial / lastIngressAction / cachedCount / foregroundArmed
ScannerRuntime 运行时状态:appliedPolicy(已生效策略)、最近一次触碰信息、bridgeLane 等。
IosWorkbench iOS 工作台:系统版本、阅读器可达性、会话/观察者/监听器状态、驻留标签、队列深度与去重/保持窗口等。
ActionOptions { success?, fail?, complete? },用于无业务返回值的操作。
WatchOptions ActionOptions,但 success 携带 TagSnapshot
TextWriteOptions { content: string, success?, fail?, complete? },文本写入专用。
ScanPolicy configureScanner() 入参,null 表示不修改。字段见调度治理
TagListener (snapshot: TagSnapshot) => voidsetTagListener 的监听器类型。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。