NFC 标签贴在手机后面没动,为什么应用连续收到多次发现事件?

事件链路图

做 NFC 应用的时候,最开始的思路很简单:标签贴上来,收到一次回调,处理业务。

结果真做的时候发现不对:标签一直贴在手机后面没动,应用却连续收到好几次标签发现事件。一次贴卡,触发了好几次业务逻辑。

这时候才意识到:NFC 标签发现不是"贴一次回调一次",是系统一直在轮询。标签还在那里,系统就会反复发现它。

一、先想清楚:NFC 是怎么发现标签的

先把最基础的问题想明白。

NFC 不是被动等标签来。是手机一直在主动发射频信号,轮询周围有没有标签。

阶段做什么
射频轮询手机不断发射频信号
标签响应标签收到信号,回响应
发现事件系统检测到标签,触发回调
回调业务应用收到 TagInfo,处理业务

问题就在这里:轮询是持续的。标签一直在那里,每次轮询都能发现它,每次都触发回调。

二、普通 Reader Mode 和带 interval 的有什么区别

普通 Reader Mode:一发现标签就回调。标签一直在,就一直回调。

带 interval 的 Reader Mode:可以设置回调间隔。比如设置 1 秒,那 1 秒内最多回调一次。

对比普通 Reader Mode带 interval
回调频率每次轮询发现都回调按间隔回调
适合场景一次性读卡连续读卡
业务负担很重可控

interval 就是用来控制回调频率的。不是让系统不轮询,是让系统别那么频繁地通知你。

这段代码解决什么问题: 注册带间隔的 Reader Mode。
文件: nfc/NfcReader.ets
用途: NFC 标签发现控制
接入位置: 页面启动时

import { readerMode } from '@kit.ConnectivityKit';

// 注册 Reader Mode,设置 500ms 间隔
readerMode.readerModeWithInterval({
  techs: [nfc.NFC_A, nfc.NFC_B],
  interval: 500,  // 每 500ms 最多回调一次
  callback: (err, tagInfo) => {
    if (err) return;
    console.log('tag found:', tagInfo.tagId);
  }
});

这里 interval 就是关键。设成 0 就是普通模式,设大一点就控制频率。

三、为什么会连续收到同一个标签

现在做个实验:把一张 NFC 标签一直贴在手机后面不动。

日志会是什么样?

10:00:00.100  tag found: AABBCC
10:00:00.600  tag found: AABBCC
10:00:01.100  tag found: AABBCC
10:00:01.600  tag found: AABBCC

同一个标签,UID 都一样,连续回调了四次。为什么?

因为轮询一直在跑。标签还在,每次轮询都能发现,每次都触发回调。interval 设了 500ms,所以每 500ms 回调一次。

NFC测试效果图

四、业务层为什么要自己做去重

系统的 interval 只是控制回调频率,不代表系统帮你判断"这个标签已经处理过了"。

系统不知道你业务上要做什么。它只知道:标签在,回调你。

所以业务层要自己做去重:同一个 UID,之前处理过了,这次就不用再处理了。

层做什么
系统层射频轮询,发现标签,按 interval 回调
业务层判断是不是同一个标签,要不要处理

系统管发现,业务管处理。分工要清楚。

五、几个容易踩的坑

第一个坑:一次回调就认为标签已经离场。不对,标签可能还在那里。

第二个坑:同一 UID 连续触发重复业务。贴一次卡,扣款扣了四次。

第三个坑:interval 设置过小导致业务层频繁执行。interval 越小,回调越频繁。

第四个坑:所有 NFC 技术类型全部监听。你只需要 NFC-A,就别监听 NFC-B、NFC-F。

第五个坑:页面退出后 Reader Mode 未关闭。一直轮询,耗电。

第六个坑:回调中直接执行数据库或网络耗时操作。回调要快,重操作放后台。

第七个坑:用时间防抖代替真正的标签状态管理。不是等一段时间不回调就算离场,要主动判断。

时间轴对比图

这次做 NFC 最大的体会是:NFC 标签发现不是事件驱动,是轮询驱动。系统一直在跑,标签一直在,回调就一直在。

真正做的时候,最容易忽略的不是怎么读卡,而是怎么处理重复事件。贴一次卡,可能触发十次回调,你业务上要处理十次还是一次?这个要自己想清楚。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐