You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用底层指令的情况下为NDEF标签设置写入保护?

NFC标签写入保护实现问题

免责声明:我是NFC领域新手,正在开发测试APP学习相关技术

据我所知,NDEF标签仅能设置写入保护,且该功能似乎只能通过复杂的底层指令实现。但我的代码仅使用Ndef、NdefMessage和NdefFormatable类,未涉及任何底层操作。请问能否在不使用底层指令的前提下实现这一保护需求?

测试APP代码

override fun onResume() {
    super.onResume()

    if (nfcAdapter != null) {
        val options = Bundle()
        // Work around for some broken Nfc firmware implementations that poll the card too fast
        options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250)

        // Enable ReaderMode for all types of card and disable platform sounds
        nfcAdapter!!.enableReaderMode(
            this,
            this::onTagDiscovered,
            NfcAdapter.FLAG_READER_NFC_A or
                    NfcAdapter.FLAG_READER_NFC_B or
                    NfcAdapter.FLAG_READER_NFC_F or
                    NfcAdapter.FLAG_READER_NFC_V or
                    NfcAdapter.FLAG_READER_NFC_BARCODE or
                    NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
            options
        )
    }
}

override fun onPause() {
    super.onPause()
}
fun NFC_siempre_puesto(tag: Tag?){

}
fun onTagDiscovered(tag: Tag?) {

    // Read and or write to Tag here to the appropriate Tag Technology type class
    // in this example the card should be an Ndef Technology Type

    try {
        val mNdef: Ndef = Ndef.get(tag)
        val mNdefMessage: NdefMessage = mNdef.getCachedNdefMessage()
        Log.d("TestNFC",String(mNdefMessage.records[0].payload, Charsets.UTF_8).split(";")[0])
        Log.d("TestNFC",("ensecurityCode:"+ resources.getString(R.string.security_code_cards)))

        if(String(mNdefMessage.records[0].payload, Charsets.UTF_8).split(";")[0].contains("securityCode:"+ resources.getString(R.string.security_code_cards))){
            text_view_nfc!!.text = String(mNdefMessage.records[0].payload, Charsets.UTF_8)
        }else{
            text_view_nfc!!.text = "[Esta carta no pertenece a esta App]"
        }


    }catch (e: FormatException) {
            // if the NDEF Message to write is malformed
        } catch (e: TagLostException) {
            // Tag went out of range before operations were complete
    } catch (e: NullPointerException) {
        text_view_nfc!!.text = "[Error de lectura. Intentando reiniciar etiqueta...]"
        val mRecord: NdefRecord = NdefRecord.createTextRecord("en", "securityCode:"+ resources.getString(R.string.security_code_cards)+";Version:1")
        val mMsg = NdefMessage(mRecord)
        val mNdef: NdefFormatable = NdefFormatable.get(tag)
        mNdef.connect()
        mNdef.format(mMsg)
            // Success if got to here
            runOnUiThread {
                Toast.makeText(
                    getApplicationContext(),
                    "Etiqueta reiniciada con éxito. Reeleyendo...",
                    Toast.LENGTH_SHORT
                ).show()
            }
        mNdef.close()
        nfcAdapter!!.disableReaderMode(this)

        val options = Bundle()
        options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250)
        nfcAdapter!!.enableReaderMode(
            this,
            this::onTagDiscovered,
            NfcAdapter.FLAG_READER_NFC_A or
                    NfcAdapter.FLAG_READER_NFC_B or
                    NfcAdapter.FLAG_READER_NFC_F or
                    NfcAdapter.FLAG_READER_NFC_V or
                    NfcAdapter.FLAG_READER_NFC_BARCODE or
                    NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
            options
        )
        } catch (e: IOException) {
            // if there is an I/O failure, or the operation is cancelled
        } finally {
            // Be nice and try and close the tag to
            /* Disable I/O operations to the tag from this TagTechnology object, and release resources.
            try {
                mNdef.close()
            } catch (e: IOException) {
                // if there is an I/O failure, or the operation is cancelled
            }*/
        }

}

补充说明

上述代码是我使用的测试APP逻辑:检测NFC标签并验证内部是否包含指定代码;若标签为空或无效,则尝试写入指定代码重置标签。

我需要防止其他APP修改这些标签,确保仅我的APP可对其进行修改(这些标签专为我的APP设计)。我的标签是NFC Type 2类标签(类似MIFARE Ultralight)。

(注:标签为空时,Ndef技术会转为NdefFormatable,因此我在调用Ndef时捕获NullPointerException,并用NdefFormatable写入内容)

我找到一篇介绍底层指令实现保护的帖子,但完全不知道如何在我的代码中实现该逻辑。


解决方案

核心结论

没有完全不依赖底层指令的硬件级写入保护方案——因为Ndef/NdefFormatable这些高层API并没有封装写入保护的功能,标签的锁闭是硬件层面的操作,必须通过对应标签技术的底层指令实现。但可以把底层指令封装成简单的工具方法,不用你手动处理复杂的指令细节。

另外,如果你暂时不想碰底层指令,可以先做应用层的验证逻辑(虽然不能阻止其他APP改写标签,但能确保只有你的APP识别有效内容),之后再逐步加上硬件级锁。


方案1:应用层验证(快速实现,软保护)

针对你的现有代码,可以优化验证逻辑,确保只有包含你专属securityCode的内容才被视为有效,同时在写入后标记标签为"已激活":

  1. 写入NDEF记录时添加locked状态字段:
val mRecord: NdefRecord = NdefRecord.createTextRecord("en", "securityCode:"+ resources.getString(R.string.security_code_cards)+";Version:1;locked:true")
  1. 读取时强化验证逻辑:
val payloadStr = String(mNdefMessage.records[0].payload, Charsets.UTF_8)
val payloadMap = payloadStr.split(";").associate { 
    val parts = it.split(":")
    parts[0] to parts.getOrElse(1) { "" }
}

if (payloadMap["securityCode"] == resources.getString(R.string.security_code_cards)) {
    text_view_nfc!!.text = payloadStr
} else {
    text_view_nfc!!.text = "[Esta carta no pertenece a esta App]"
}

这种方式的缺点是无法真正阻止其他APP改写标签,但其他APP改写后,你的APP会直接判定为无效标签,相当于实现了应用层面的专属识别。


方案2:硬件级写入保护(真正防改写,需底层指令)

根据你的NFC Type 2标签类型,可以通过NfcA技术类发送底层指令锁定标签。以下是封装好的工具方法,可直接集成到代码中:

1. 添加锁定标签的工具方法

private fun lockNfcType2Tag(tag: Tag): Boolean {
    val nfcA = NfcA.get(tag) ?: return false
    return try {
        nfcA.connect()
        // 针对MIFARE Ultralight类标签的锁定指令:写入第12页锁定全部可写区域
        // 不同标签的指令参数需参考官方 datasheet 调整
        val lockCommand = byteArrayOf(0xA2.toByte(), 0x0C.toByte(), 0x0F.toByte(), 0x00.toByte(), 0x00.toByte())
        val response = nfcA.transceive(lockCommand)
        // 响应为0x0A表示锁定成功
        response.isNotEmpty() && response[0] == 0x0A.toByte()
    } catch (e: IOException) {
        false
    } finally {
        try {
            nfcA.close()
        } catch (e: IOException) {
            // 忽略关闭异常
        }
    }
}

2. 在代码中调用锁定方法

在成功写入NDEF内容后调用:

// 原写入逻辑完成后添加
mNdef.close()
// 锁定标签
val isLocked = lockNfcType2Tag(tag!!)
if (isLocked) {
    runOnUiThread {
        Toast.makeText(applicationContext, "Etiqueta bloqueada con éxito", Toast.LENGTH_SHORT).show()
    }
}

现有代码优化建议

  1. 不要依赖捕获NullPointerException判断标签类型,改用显式检查:
val mNdef = Ndef.get(tag)
if (mNdef != null) {
    // 处理已格式化的NDEF标签
} else {
    val mNdefFormatable = NdefFormatable.get(tag)
    if (mNdefFormatable != null) {
        // 格式化并写入内容
    } else {
        text_view_nfc!!.text = "[Etiqueta no compatible]"
    }
}
  1. 在onPause中关闭ReaderMode,避免后台耗电:
override fun onPause() {
    super.onPause()
    nfcAdapter?.disableReaderMode(this)
}

内容的提问来源于stack exchange,提问作者Aglo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:10:37