java - 如何正确写入 MifareUltralight NFC 标签?

标签 java android kotlin nfc mifare

使用 MifareUltralight.writePage() 方法的正确方法是什么?

查询getMaxTransceiveLength()方法返回253字节。然而tag广告大小为 888 字节。 transceive()writePage() 是否应该被调用多次?正在写入的有效负载大小为 457 字节。

        val jsonString = Gson().toJson(casualty)  
        val casualtyBytes = toBlob(casualty)
        var currentPage = PAGE_OFFSET
        val pageBytes = ByteArray(MifareUltralight.PAGE_SIZE)
        var byteIndex = 0
        for(i in 0 until casualtyBytes.size){
            pageBytes[byteIndex] = casualtyBytes[i]
            byteIndex++
            if(byteIndex == 4 || i == (casualtyBytes.size-1)) {
                tag.writePage(currentPage, pageBytes)
                currentPage++
                byteIndex = 0
            }
        }

fun toBlob(item : Any) : ByteArray{
    val bos = ByteArrayOutputStream()
    val gzip = GZIPOutputStream(bos) //compress
    val oos = ObjectOutputStream(gzip)
    oos.writeObject(item)
    oos.close()
    return bos.toByteArray()
}

异常

java.io.IOException: Transceive failed
    at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52)
    at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151)
    at android.nfc.tech.MifareUltralight.writePage(MifareUltralight.java:193)
    at some.package.nfc.NfcCasualtyPublisher.writeToTag(NfcCasualtyPublisher.kt:42)
    at some.package.nfc.NfcCasualtyPublisher.access$writeToTag(NfcCasualtyPublisher.kt:11)
    at some.package.nfc.NfcCasualtyPublisher$publishCasualty$1.run(NfcCasualtyPublisher.kt:21)
    at java.lang.Thread.run(Thread.java:818)

最佳答案

MIFARE Ultralight 和 NTAG 标签的内存按每页 4 字节的页进行组织。因此,WRITE 命令 (MifareUltralight.writePage()) 一次写入 4 个字节。 (请注意,READ 命令 (MifareUltralight.readPages()) 一次读取 4 页(= 16 字节)。

因此,当您想要写入 NTAG216 标签时,您需要将数据拆分为 4 字节的 block 。您似乎已经使用代码中的 for 循环做到了这一点(尽管您会遇到一些问题,因为如果数据未页面对齐,您不会清除最后一页的未使用字节)。

并非 MIFARE Ultralight/NTAG 标签的所有页面都可自由用于数据存储。只有第 4 至 225 页(对于 NTAG216)中的用户存储区是。前 2 页(页 0 和 1)是只读的,并为标签序列号保留。接下来的 2 页(第 2 页和第 3 页)包含一次写入存储器(即,一旦写入 1 的位就无法再次更改为 0 的存储器区域)。具体来说,第 2 页中有锁定位(也在第 226 页中,但如果您的数据只有 457 字节,则不应触及它们)。如果设置锁定位,则会阻止对部分用户内存页的写访问,这将导致“收发失败”异常。因此,如果 PAGE_OFFSET 的值小于 4,您可能会通过将数据写入保留的内存区域来使标记不可用。

一般来说,如果您只想存储(自由可读)数据并且不会使用标签的附加功能(例如密码保护),我强烈建议您不要使用低级 IO访问 NFC 标签的方法。相反,坚持使用 NDEF 抽象层并将数据存储在 NDEF 记录中。然后,Android 将负责将数据放入任何 NFC 标签上的适当内存位置。

最后,收发长度是在一个命令或响应中可以传输的字节数。例如,对于 WRITE 命令,总共为 6 个字节(4 个字节的数据有效负载、1 个地址字节和 1 个命令代码字节)。对于 READ 响应,这将是 16 字节的数据有效负载。 getMaxTransceiveLength() 的值表示底层库、HAL 和硬件理论上可能的最大收发长度。

关于java - 如何正确写入 MifareUltralight NFC 标签?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51756210/

相关文章:

java.sql.SQLSyntaxErrorException : You have an error in your SQL syntax; when inserting data into SQL database through JAVA

java - 需要字符串匹配器正则表达式

java - Maven 在没有互联网连接的情况下无法执行目标

java - JNI eclipse Javah 自动生成

java.lang.NoClassDefFoundError(libgdx)

android - 如何通过 USB 在 Android 设备和 Windows 上运行的机器之间进行通信

android - android studio中drawable文件夹的路径

android - 如何在 Kotlin 中合并流和 channel ?

java - 如何从 kotlin 中的辅助构造函数调用 'super()'?

kotlin - kotlin中如何使用子类调用父静态方法?