Android reading from NFC tag

1. Create a nfc filter xml file at res/xml/nfc_tech_filter.xml



    
        android.nfc.tech.Ndef
        
    

2. Add android.permission.NFC in AndroidManifest.xml

 

3. In AndroidManifest.xml, inside the activity tag for the activity you want to launch for reading NFC, add following filter intent and meta-data.


    
    
    

  

4. The entire AndroidManifest.xml should look like this after step 2 and step 3 are completed.




    

    
        
            
                

                
            
            
                
                
                
            
            
        
    


5. activity_main.xml, the layout file for the MainActivity with a TextView for displaying message read from NFC tag.




    


6. MainActivity.kt, the code for reading and displaying text message from NFC tag.

package com.codexpedia.nfcreader

import android.app.Activity
import android.app.PendingIntent
import android.content.Intent
import android.content.IntentFilter
import android.nfc.*
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.widget.TextView
import android.widget.Toast
import com.codexpedia.nfcreader.databinding.ActivityMainBinding
import java.io.UnsupportedEncodingException
import java.nio.charset.Charset
import kotlin.experimental.and

class MainActivity : Activity() {

    lateinit var writeTagFilters: Array
    private lateinit var tvNFCContent: TextView
    private lateinit var binding: ActivityMainBinding
    var nfcAdapter: NfcAdapter? = null
    var pendingIntent: PendingIntent? = null
    var myTag: Tag? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        tvNFCContent = binding.nfcContents
        tvNFCContent.text = "Place the back of the phone over a NFC tag to read message from NFC tag"

        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null) {
            // Stop here, we definitely need NFC
            Toast.makeText(this, "This device doesn't support NFC.", Toast.LENGTH_LONG).show()
            finish()
        }

        //This is for when the activity is launched by the intent-filter for android.nfc.action.NDEF_DISCOVERE
        readFromIntent(intent)
        pendingIntent = PendingIntent.getActivity(
            this,
            0,
            Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
            0
        )
        val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
        tagDetected.addCategory(Intent.CATEGORY_DEFAULT)
        writeTagFilters = arrayOf(tagDetected)
    }

    /******************************************************************************
     * Read From NFC Tag
     ****************************/
    private fun readFromIntent(intent: Intent) {
        val action = intent.action
        if (NfcAdapter.ACTION_TAG_DISCOVERED == action || NfcAdapter.ACTION_TECH_DISCOVERED == action || NfcAdapter.ACTION_NDEF_DISCOVERED == action) {
            myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) as Tag?
            val rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
            var msgs = mutableListOf()
            if (rawMsgs != null) {
                for (i in rawMsgs.indices) {
                    msgs.add(i, rawMsgs[i] as NdefMessage)
                }
                buildTagViews(msgs.toTypedArray())
            }
        }
    }

    private fun buildTagViews(msgs: Array) {
        if (msgs == null || msgs.isEmpty()) return
        var text = ""
        val payload = msgs[0].records[0].payload
        val textEncoding: Charset = if ((payload[0] and 128.toByte()).toInt() == 0) Charsets.UTF_8 else Charsets.UTF_16 // Get the Text Encoding
        val languageCodeLength: Int = (payload[0] and 51).toInt() // Get the Language Code, e.g. "en"
        try {
            // Get the Text
            text = String(
                payload,
                languageCodeLength + 1,
                payload.size - languageCodeLength - 1,
                textEncoding
            )
        } catch (e: UnsupportedEncodingException) {
            Log.e("UnsupportedEncoding", e.toString())
        }
        tvNFCContent.text = "Message read from NFC Tag:\n $text"
    }

    /**
     * This is for reading the NFC when the app is already launched
     */
    override fun onNewIntent(intent: Intent) {
        setIntent(intent)
        readFromIntent(intent)
        if (NfcAdapter.ACTION_TAG_DISCOVERED == intent.action) {
            myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        }
    }

    public override fun onPause() {
        super.onPause()
        disableForegroundDispatch()
    }

    public override fun onResume() {
        super.onResume()
        enableForegroundDispatch()
    }

    /**
     * enable foreground dispatch to prevent intent-filter to launch the app again
     */
    private fun enableForegroundDispatch() {
        nfcAdapter!!.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null)
    }

    /**
     * disable foreground dispatch to allow intent-filter to launch the app
     */
    private fun disableForegroundDispatch() {
        nfcAdapter!!.disableForegroundDispatch(this)
    }
}

7. Find a NFC tag contain text messages, install the app on an android phone, place the back of the android phone over the NFC tag, the phone should vibrate and launches the app. If there is any message on the NFC tag, it should be displayed on the screen.

Complete code example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search