通过APDU读取NDEF标签

问题描述 投票:0回答:1

就上下文而言,我正在创建一个 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

NFC 标签 NFC Tools Screenshot NFC Tools Screenshot 2

android kotlin nfc ndef
1个回答
0
投票

来自NTAG215数据表第10.2节命令

0x30
是“READ”,它从指定的起始地址返回4个块(16字节)。

因此,由于您总共只读取 4 个块,因此只需删除

for (block in 4..8) {
循环,因为您实际上只需要读取一个读取命令返回的 4 个块。

或者您可以在 NTAG215 上使用“FAST_READ”命令

0x3A
并指定要读取的起始块和结束块,只要您读取的数据小于最大收发长度,这就会比多个“READ”命令更容易、更快。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.