Kotlin开发NDEF标签写入:避免内容转换的技术问题
问题
开发一款Demo应用,实现读取NDEF标签记录并覆盖写入的功能。目前已实现readNdef、writeNdef和readTag三个核心函数,其中readNdef与readTag功能正常,但writeNdef函数存在异常:使用NdefRecord.createTextRecord方法写入记录时,内容会被自动转换,希望能够原样写入令牌内容。
相关代码实现
readNdef函数
private fun readNdef(tag: Tag?) { val ndef = Ndef.get(tag) try { ndef.connect() val inNdef = ndef.ndefMessage Log.d("fdsfsdfsdf", inNdef.toString()) val inNdefRecords = ndef.ndefMessage.records Log.d("fdsfsdfsdf", inNdefRecords.toString()) // convert the payload to string and drop 3 characters to get // rid of the " en" prefix val payload = inNdefRecords[0].payload Log.d("fdsfsdfsdf", payload.toString()) // figure out if we need to take out the " en" at the beginning val textEncoding = if (payload[0] and 128.toByte() == 0.toByte()) "UTF-8" else "UTF-16" val langCodeLength = payload[0] and 63.toByte() // create a string starting by skipping the first 3 characters // based on the language code length var inMessage = String( payload, langCodeLength + 1, payload.count() - langCodeLength - 1, charset(textEncoding) ) // try to convert the message to json try { val json = inMessage Log.d("fdsfsdfsdf", json) //val json = JsonParser().parse(inMessage) // ... use json or whatever here } catch (error: Exception) { Log.d( "fdsfsdfsdf", "NFC tag data seems to invalid:\n\n$inMessage\n\n${error.localizedMessage}" ) } // ... do whatever } catch (error: Exception) { Log.d("fdsfsdfsdf", "Error attempting to pull tag info: ${error.localizedMessage}") } finally { ndef.close() } }
readTag函数
fun readTag(tag: Tag?) { Coroutines.default(this@MainViewModel) { readNdef(tag) Log.d(TAG, "readTag(${tag} ${tag?.techList})") postNFCStatus(NFCStatus.Process) val stringBuilder: StringBuilder = StringBuilder() val id: ByteArray? = tag?.id Log.d("fdsfsdfsdf", "$id") stringBuilder.append("Tag ID (hex): ${bytesToHex(id!!)} \n") stringBuilder.append("Tag ID (dec): ${getDec(id)} \n") stringBuilder.append("Tag ID (reversed): ${getReversed(id)} \n") stringBuilder.append("Technologies: ") tag.techList.forEach { tech -> stringBuilder.append(tech.substring(prefix.length)) stringBuilder.append(", ") } stringBuilder.delete(stringBuilder.length - 2, stringBuilder.length) tag.techList.forEach { tech -> if (tech.equals(MifareClassic::class.java.name)) { stringBuilder.append('\n') val mifareTag: MifareClassic = MifareClassic.get(tag) val type: String if (mifareTag.type == MifareClassic.TYPE_CLASSIC) type = "Classic" else if (mifareTag.type == MifareClassic.TYPE_PLUS) type = "Plus" else if (mifareTag.type == MifareClassic.TYPE_PRO) type = "Pro" else type = "Unknown" stringBuilder.append("Mifare Classic type: $type \n") stringBuilder.append("Mifare size: ${mifareTag.size} bytes \n") stringBuilder.append("Mifare sectors: ${mifareTag.sectorCount} \n") stringBuilder.append("Mifare blocks: ${mifareTag.blockCount}") } if (tech.equals(MifareUltralight::class.java.name)) { stringBuilder.append('\n'); val mifareUlTag: MifareUltralight = MifareUltralight.get(tag); val type: String if (mifareUlTag.type == MifareUltralight.TYPE_ULTRALIGHT) type = "Ultralight" else if (mifareUlTag.type == MifareUltralight.TYPE_ULTRALIGHT_C) type = "Ultralight C" else type = "Unkown" stringBuilder.append("Mifare Ultralight type: "); stringBuilder.append(type) } } Log.d(TAG, "Datum: $stringBuilder") Log.d(ContentValues.TAG, "dumpTagData Return \n $stringBuilder") postNFCStatus(NFCStatus.Read) liveTag.emit("${getDateTimeNow()} \n $stringBuilder") } }
writeNdef函数
fun writeNdef(tag: Tag?, context: Context) { val ndef = Ndef.get(tag) try { ndef.connect() val textRecord1 = NdefRecord.createTextRecord( "en", // language code (ISO 639-1) "00000111111222222333333444444555555AABBEF" // context.getString(R.string.ndef_rcrd1) // text to send ) val textRecord2 = NdefRecord.createTextRecord( "en", // language code (ISO 639-1) "00000111111222222333333444444555555AABBEF" // context.getString(R.string.ndef_rcrd2) // text to send ) val textRecord3 = NdefRecord.createTextRecord( "en", // language code (ISO 639-1) "00000111111222222333333444444555555AABBEF" // context.getString(R.string.ndef_rcrd3) // text to send ) val textRecord4 = NdefRecord.createTextRecord( "en", // language code (ISO 639-1) "00000111111222222333333444444555555AABBEF" //context.getString(R.string.ndef_rcrd4) // text to send ) val ndefMessage = NdefMessage(textRecord1, textRecord2, textRecord3, textRecord4) ndef.writeNdefMessage(ndefMessage) Coroutines.default(this@MainViewModel){ postNFCStatus(NFCStatus.Write) } Log.d("fdsfsdfsdf","Edited: ${ndef.ndefMessage}") } catch (e: Exception) { Log.d("fdsfsdfsdf", "Error write: ${e.localizedMessage}") } finally { ndef.close() } }
解决方案
NdefRecord.createTextRecord是专门用于创建NDEF文本类型记录的方法,它会自动在payload头部添加语言编码标识和字符编码信息(比如你读取时跳过的"en"前缀相关字节),导致原始令牌内容被包装转换。要实现无转换的原样写入,需要直接构造自定义NDEF记录,跳过文本格式的自动包装。
修改后的writeNdef函数
fun writeNdef(tag: Tag?, context: Context) { val ndef = Ndef.get(tag) try { ndef.connect() // 原始令牌内容 val tokenContent = "00000111111222222333333444444555555AABBEF" // 将字符串转为UTF-8字节数组,作为原始payload val payload = tokenContent.toByteArray(Charsets.UTF_8) // 构造自定义NDEF记录:使用MIME类型标识纯文本,避免自动格式转换 val customRecord = NdefRecord( NdefRecord.TNF_MIME_MEDIA, // 类型名称格式:MIME媒体类型 "text/plain".toByteArray(), // MIME类型 ByteArray(0), // 记录ID(空即可) payload // 原始内容字节数组 ) // 创建包含4个相同记录的NDEF消息 val ndefMessage = NdefMessage(customRecord, customRecord, customRecord, customRecord) ndef.writeNdefMessage(ndefMessage) Coroutines.default(this@MainViewModel){ postNFCStatus(NFCStatus.Write) } Log.d("fdsfsdfsdf","Edited: ${ndef.ndefMessage}") } catch (e: Exception) { Log.d("fdsfsdfsdf", "Error write: ${e.localizedMessage}") } finally { ndef.close() } }
对应读取逻辑调整
如果使用上述方式写入,读取时无需再跳过语言编码前缀,直接将payload转为字符串即可:
// 在readNdef函数中替换原有的inMessage生成逻辑 val inMessage = String(inNdefRecords[0].payload, Charsets.UTF_8)
说明
- 如果你需要写入的是二进制令牌(而非字符串),直接传入对应的
ByteArray作为payload即可。 - 也可以根据需求选择其他TNF类型,比如
TNF_ABSOLUTE_URI(用于URI记录)或TNF_UNKNOWN(通用未知类型),只要不使用createTextRecord就不会触发自动格式转换。
内容的提问来源于stack exchange,提问作者Tural Sufan
相关产品推荐
相关产品推荐

