You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 13下NFC写入后调用getNdefMessage返回null问题求助

Android 13 NFC写入后即时读取NdefMessage返回null问题

问题背景

我开发的NFC应用支持写入指令后无需让标签离开设备NFC字段就能读取NdefMessage,这个逻辑在Android 12及以下所有测试设备上都正常,但到了Android 13设备上彻底失效——写入后调用ndef.getNdefMessage()直接返回null。

核心代码如下:

val message = NdefMessage(NdefRecord.createTextRecord("en", command))

ndef.connect()
ndef.writeNdefMessage(message)

val ndefMessage = ndef.getNdefMessage() // Android 13返回null,其他系统版本正常

已尝试的无效方案

  • 启用前台调度(Foreground Dispatch)
  • 调整阅读器模式的EXTRA_READER_PRESENCE_CHECK_DELAY参数
  • 写入后加线程休眠、循环读取逻辑
  • 把读写操作放到单独后台线程执行
  • 禁用设备上其他NFC和支付类应用

关键验证点:标签实际是写入成功的——只要断开重连再读取,或者用第三方NFC应用读取,都能拿到正确内容。而且同一台设备升级Android 13前完全正常,确定是系统版本变更导致的问题。

可行解决方案及分析

1. 写入后强制重新连接

Android 13的NFC栈对读写后的状态同步做了调整,写入完成后系统并没有即时更新标签的缓存状态,所以直接读取会拿到null。最稳妥的解决方式是写入后关闭连接再重新建立:

val message = NdefMessage(NdefRecord.createTextRecord("en", command))

ndef.connect()
ndef.writeNdefMessage(message)
ndef.close() // 主动关闭连接
ndef.connect() // 重新建立连接
val ndefMessage = ndef.getNdefMessage() // 此时能正常读取

这个方案兼容性最好,唯一的缺点是需要短暂断开连接,如果你的业务逻辑允许,优先用这个。

2. 直接读取标签原始数据块

绕过系统封装的getNdefMessage(),直接用transceive()发送NFC指令读取原始数据。不同标签的指令不同,以MIFARE Ultralight为例:

ndef.writeNdefMessage(message)
// 发送读取块0的指令(根据标签类型调整)
val readCmd = byteArrayOf(0x30, 0x00)
val rawData = ndef.transceive(readCmd)
// 把原始数据解析为NdefMessage
val ndefMessage = NdefMessage(rawData)

这个方案不需要断开连接,但需要针对不同标签类型做适配,适合必须保持连接的场景。

3. 适配Android 13的权限与PendingIntent要求

Android 13新增了NEARBY_WIFI_DEVICES权限,部分厂商的NFC实现可能依赖这个权限,先在Manifest里加上:

<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />

另外,Android 12+对PendingIntent的flag要求更严格,前台调度的PendingIntent要加上FLAG_MUTABLE:

val pendingIntent = PendingIntent.getActivity(
    context,
    0,
    Intent(context, YourNFCActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
    PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

4. 临时切换标签只读状态(部分标签支持)

部分NFC标签支持写入后临时设置为只读,这个操作会触发标签状态同步,之后再读取就能拿到数据:

ndef.writeNdefMessage(message)
ndef.makeReadOnly() // 临时设为只读
val ndefMessage = ndef.getNdefMessage()
// 如果需要保持标签可写,部分标签支持调用ndef.setWritable(true)恢复,需测试兼容性

注意:不是所有标签都支持恢复可写,这个方案局限性较大,仅作为备选。

内容的提问来源于stack exchange,提问作者Dejan Panjkovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 00:21:26