Android 13下NFC写入后调用getNdefMessage返回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

