如何在不使用底层指令的情况下为NDEF标签设置写入保护?
免责声明:我是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的内容才被视为有效,同时在写入后标记标签为"已激活":
- 写入NDEF记录时添加
locked状态字段:
val mRecord: NdefRecord = NdefRecord.createTextRecord("en", "securityCode:"+ resources.getString(R.string.security_code_cards)+";Version:1;locked:true")
- 读取时强化验证逻辑:
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() } }
现有代码优化建议
- 不要依赖捕获
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]" } }
- 在
onPause中关闭ReaderMode,避免后台耗电:
override fun onPause() { super.onPause() nfcAdapter?.disableReaderMode(this) }
内容的提问来源于stack exchange,提问作者Aglo

