Home > Blockchain >  How to guarantee an NFC does not crash when writing to a tag (when no tag is there)
How to guarantee an NFC does not crash when writing to a tag (when no tag is there)

Time:11-25

I am trying to guarantee that my Android application will not crash when I try to write to an NFC tag. The edge case I am working on is: What if I try to write but there is nothing to write to?

I created this write() method, which checks the NFC status in checkNFCStatus()... It prevents some cases (like when a user had a card against the device but removed it before writing). But it does not prevent the case when the user never had a tag to begin with.

@Throws(IOException::class, FormatException::class)
fun write(text: String, tag: Tag?, context: Context): Boolean {
    val records = arrayOf(createRecord(text))
    val message = NdefMessage(records)
    **val ndef = Ndef.get(tag)**
    if (checkNFCStatus(tag)) {
        ndef.connect()
        val ndefMessage = ndef.ndefMessage
        Log.d(TAG, "ndef is : "   ndef.type)
        Log.d(TAG, "ndef message is : $ndefMessage")
        if (ndef.isWritable) {
            Log.d("MAIN", "NDEF is writable.")
        }
        if (!ndef.isWritable) {
            Log.d("MAIN", "NDEF is read-only.")
        }
        if (!ndef.isConnected) {
            Log.d("MAIN", "NDEF is not connected.")
        }
        if (ndef.isConnected) {
            ndef.writeNdefMessage(message)
            ndef.close()
            return true
        }
        ndef.close()
    }
    DebugUtils().showToast(
        context,
        "Try repositioning the card/chip. It is not close enough to the device.")
    return false
}

private fun checkNFCStatus(myTag: Tag?): Boolean {
    try {
        if (myTag != null) {
            val ndefTag = Ndef.get(myTag)
            ndefTag.connect()
            return if (ndefTag.isConnected) {
                Log.d("network", "NFC connected")
                ndefTag.close()
                true
            } else {
                Log.d("network", "NFC disconnected")
                false
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
        Log.d("network", "NFC disconnected")
    }
    return false
}

The problematic line of code is: val ndef = Ndef.get(tag) Basically if there never was a tag to begin with, this throws an NPE:

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.nfc.Tag.hasTech(int)' on a null object reference

CodePudding user response:

Kotlin has a null safety feature, so whenever you know there is a chance for a variable to be null, you should use safe calls :

val a : Boolean?  // now this variable can be null

so replace this :

val ndef = Ndef.get(tag)

with :

val ndef : Boolean? = Ndef.get(tag)

now you will not get this NullPointer error and whenever you want to check the value of ndef you should check it is null or not.

CodePudding user response:

Okay.... so I first went the approach of null safety, but it wasn't working. The answer should have been more obvious.

First check if the tag is null!

if (tag != null) {
        var ndef = Ndef.get(tag)
        if (checkNFCStatus(tag)) {....}
  • Related