就上下文而言,我正在创建一个 Android 应用程序,该应用程序需要从 NFC A 型卡读取 NDEF 文本消息。我想通过我的基于 Android 的销售点系统阅读此内容,该系统需要通过 PICC 和 APDU 命令(因此我无法使用默认的 Android NDEF 库)。
要写入 NFC 标签,我只需使用 Google Play 商店中的 NFC 工具。您将能够看到我已将“123456789”写入标签,但我的代码实际上读取的是“1234567123456789123456789”。我希望这是有道理的,并且有人可以看到出了什么问题。谢谢!
代码:
private fun extractNdef(tag: Tag): String? {
val nfcA = NfcA.get(tag) ?: return null
nfcA.use {
nfcA.connect()
// Read blocks 4-8
val allData = StringBuilder()
for (block in 4..8) {
val response = try {
val rawResponse = nfcA.transceive(byteArrayOf(0x30.toByte(), block.toByte()))
rawResponse.joinToString("") { "%02x".format(it) }
} catch (e: IOException) {
Log.e("NFC", "Failed to read block $block", e)
return null
}
allData.append(response)
Log.d("NFC", "Block $block Data: $response")
}
val ndefData = allData.toString()
Log.d("NFC", "Combined NDEF Data: $ndefData")
return parseNdefData(ndefData)
}
}
fun parseNdefData(hexData: String): String {
// Convert hex data to bytes
val bytes = hexData.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
// Search for the text record identifier and language code prefix
val textRecordType = 0x54.toByte() // "T" for text records in NDEF
val langCodeLength = 3 // Length of 'T' + length of "en" (2 bytes)
// Locate and decode the text content
val contentBuilder = StringBuilder()
for (i in bytes.indices) {
if (bytes[i] == textRecordType && i + langCodeLength < bytes.size) {
// Start extracting bytes after 'T' and "en" prefix (language code)
val textContentBytes = bytes.drop(i + langCodeLength + 1)
.takeWhile { it != 0xFE.toByte() && it != 0x00.toByte() } // Stop at `FE` or padding `00`
// Convert to string and filter only ASCII digits
contentBuilder.append(
textContentBytes
.toByteArray()
.toString(Charsets.UTF_8)
.filter { it.isDigit() }
)
}
}
return contentBuilder.toString()
}
日志:
2024-10-29 12:27:25.226 27321-27339 NFC com.passentry.nfc_reader_libraries D Block 4 Data: 0310d1010c5402656e31323334353637
2024-10-29 12:27:25.238 27321-27339 NFC com.passentry.nfc_reader_libraries D Block 5 Data: 0c5402656e313233343536373839fe00
2024-10-29 12:27:25.253 27321-27339 NFC com.passentry.nfc_reader_libraries D Block 6 Data: 6e313233343536373839fe0000000000
2024-10-29 12:27:25.266 27321-27339 NFC com.passentry.nfc_reader_libraries D Block 7 Data: 343536373839fe000000000000000000
2024-10-29 12:27:25.284 27321-27339 NFC com.passentry.nfc_reader_libraries D Block 8 Data: 3839fe00000000000000000000000000
2024-10-29 12:27:25.285 27321-27339 NFC com.passentry.nfc_reader_libraries D Combined NDEF Data: 0310d1010c5402656e313233343536370c5402656e313233343536373839fe006e313233343536373839fe0000000000343536373839fe0000000000000000003839fe00000000000000000000000000
2024-10-29 12:27:25.349 27321-27339 MainActivity com.passentry.nfc_reader_libraries D Pass ID: 1234567123456789123456789
来自NTAG215数据表第10.2节命令
0x30
是“READ”,它从指定的起始地址返回4个块(16字节)。
因此,由于您总共只读取 4 个块,因此只需删除
for (block in 4..8) {
循环,因为您实际上只需要读取一个读取命令返回的 4 个块。
或者您可以在 NTAG215 上使用“FAST_READ”命令
0x3A
并指定要读取的起始块和结束块,只要您读取的数据小于最大收发长度,这就会比多个“READ”命令更容易、更快。