Android写入Ntag系列标签后NFC数据格式不符问题咨询
问题分析与修复方案
你的核心问题出在NDEF URI记录的构造逻辑不符合NFC Forum标准,导致写入的数据无法被NfcTools正确识别。以下是具体问题和修复步骤:
1. 关键错误点拆解
(1) URI标识符字节非法
你代码中使用的0x55不是合法的NDEF URI标识符。NFC标准中,URI标识符是0x00~0x1F的字节,用于缩写常见的URI前缀(比如0x03代表http://,0x04代表https://),而0x55是ASCII字符'U',完全不符合规范。
(2) Payload长度计算错误
你用subsUri.length作为NDEF记录的长度字段,这是错误的。NDEF记录头中D1 01后的长度字段,应该是整个URI Payload的长度(1字节标识符 + 缩写后剩余URI的字节数),而非仅host的长度。
(3) URI未按标准缩写
直接将完整URI转成字节写入,没有利用NDEF URI的缩写规则,既浪费存储空间,也会导致记录结构不符合标准。
2. 修复后的代码
下面是严格遵循NDEF规范的修正版writePages方法:
fun writePages(msg: String, mifare: MifareUltralight) { val uri = Uri.parse(msg).normalizeScheme() val (uriCode, trimmedUri) = getUriCodeAndTrimmedUri(uri.toString()) // 构造合法的NDEF URI记录 val payloadLength = 1 + trimmedUri.length // 1字节标识符 + 剩余URI长度 val ndefRecord = byteArrayOf( 0xD1.toByte(), 0x01.toByte(), payloadLength.toByte(), uriCode.toByte() ) + trimmedUri.toByteArray(Charsets.US_ASCII) // 包装成NDEF Message TLV块:0x03(TLV标签) + 数据长度 + NDEF记录 + 0xFE(终止TLV) val tlvEncodedData = byteArrayOf(0x03.toByte(), ndefRecord.size.toByte()) + ndefRecord + byteArrayOf(0xFE.toByte()) var currentPage = 4 for (i in tlvEncodedData.indices step 4) { val endIndex = min(i + 4, tlvEncodedData.size) val data = tlvEncodedData.sliceArray(i until endIndex) // 构造写页命令:A2 [页地址] [4字节数据],不足补0 val command = byteArrayOf(0xA2.toByte(), currentPage.toByte()) + data if (command.size < 6) { command += ByteArray(6 - command.size) } mifare.transceive(command) currentPage += 1 } } // 匹配URI前缀,返回对应的标识符和裁剪后的URI private fun getUriCodeAndTrimmedUri(uri: String): Pair<Int, String> { return when { uri.startsWith("http://www.") -> 0x01 to uri.substring(11) uri.startsWith("https://www.") -> 0x02 to uri.substring(12) uri.startsWith("http://") -> 0x03 to uri.substring(7) uri.startsWith("https://") -> 0x04 to uri.substring(8) uri.startsWith("tel:") -> 0x05 to uri.substring(4) uri.startsWith("mailto:") -> 0x06 to uri.substring(7) // 其他常见前缀可参考NFC Forum规范补充 else -> 0x00 to uri // 0x00代表不使用缩写,完整写入URI } }
3. 额外注意事项
- 密码验证:如果Ntag启用了密码保护,写入前必须先执行密码验证命令:
mifare.transceive(byteArrayOf(0x1B.toByte(), *passwordBytes)),否则写入操作会静默失败。 - 字符编码:URI必须使用US-ASCII编码,避免非ASCII字符,否则部分设备无法识别。
- 存储空间限制:不同型号Ntag的用户页容量不同(比如Ntag213有42个用户页),确保写入的TLV数据不超出设备容量。
4. 验证
修复后用NfcTools扫描标签,应该能正确识别URI记录,且未安装对应APP时会自动触发浏览器打开目标链接。
内容的提问来源于stack exchange,提问作者foxie fox
相关产品推荐
相关产品推荐

