Android NFC Read and Write Example
NFC stands for Near Field Communication, it is a short-range wireless technology that enables the communication between devices over a distance of less than 10 cm. The NFC standard is defined in ISO/IEC 18092. NFC tag is a sticker or some small objects embeded with a chip that can store small amount of data.Depending on how the chip is programmed for the smartphone, it can change various settings, launch apps and perform certain actions just by holding your phone close to it.
The following are the bare minimum code for creating an Android Application for reading from a NFC tag and writing to it. You will need to know the basics of creating an Android application and you need to have NFC enabled device and a NFC tag. To enable NFC on your android device, go to settings -> More -> and enable it. NFC tags costs from $1 to $2.
In manifest.xml, add the following. The uses-permission and uses-feature tags should belong to the manifest tag. The intent-filter and meta-data tags should go into the activity tag of the Main Activity.
nfc_tech_filter.xml, this file should go into the xml folder in the res, create the xml directory in the res if it is not yet created.
android.nfc.tech.Ndef
activity_main.xml, the layout file for the MainActivity
MainActivity.kt
import android.app.Activity
import android.app.PendingIntent
import android.content.Intent
import android.content.IntentFilter
import android.nfc.*
import android.nfc.tech.Ndef
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import com.codexpedia.nfcreadwrite.databinding.ActivityMainBinding
import java.io.IOException
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 message: TextView
private lateinit var btnWrite: Button
private lateinit var binding: ActivityMainBinding
var nfcAdapter: NfcAdapter? = null
var pendingIntent: PendingIntent? = null
var writeMode = false
var myTag: Tag? = null
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
tvNFCContent = binding.nfcContents
message = binding.editMessage
btnWrite = binding.button
btnWrite.setOnClickListener {
try {
if (myTag == null) {
Toast.makeText(this, ERROR_DETECTED, Toast.LENGTH_LONG).show()
} else {
write(message.text.toString(), myTag)
Toast.makeText(this, WRITE_SUCCESS, Toast.LENGTH_LONG).show()
}
} catch (e: IOException) {
Toast.makeText(this, WRITE_ERROR, Toast.LENGTH_LONG).show()
e.printStackTrace()
} catch (e: FormatException) {
Toast.makeText(this, WRITE_ERROR, Toast.LENGTH_LONG).show()
e.printStackTrace()
}
}
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()
}
//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"
}
/******************************************************************************
* Write to NFC Tag
****************************************************************************/
@Throws(IOException::class, FormatException::class)
private fun write(text: String, tag: Tag?) {
val records = arrayOf(createRecord(text))
val message = NdefMessage(records)
// Get an instance of Ndef for the tag.
val ndef = Ndef.get(tag)
// Enable I/O
ndef.connect()
// Write the message
ndef.writeNdefMessage(message)
// Close the connection
ndef.close()
}
@Throws(UnsupportedEncodingException::class)
private fun createRecord(text: String): NdefRecord {
val lang = "en"
val textBytes = text.toByteArray()
val langBytes = lang.toByteArray(charset("US-ASCII"))
val langLength = langBytes.size
val textLength = textBytes.size
val payload = ByteArray(1 + langLength + textLength)
// set status byte (see NDEF spec for actual bits)
payload[0] = langLength.toByte()
// copy langbytes and textbytes into payload
System.arraycopy(langBytes, 0, payload, 1, langLength)
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength)
return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), payload)
}
/**
* 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()
WriteModeOff()
}
public override fun onResume() {
super.onResume()
WriteModeOn()
}
/******************************************************************************
* Enable Write and foreground dispatch to prevent intent-filter to launch the app again
****************************************************************************/
private fun WriteModeOn() {
writeMode = true
nfcAdapter!!.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null)
}
/******************************************************************************
* Disable Write and foreground dispatch to allow intent-filter to launch the app
****************************************************************************/
private fun WriteModeOff() {
writeMode = false
nfcAdapter!!.disableForegroundDispatch(this)
}
companion object {
const val ERROR_DETECTED = "No NFC tag detected!"
const val WRITE_SUCCESS = "Text written to the NFC tag successfully!"
const val WRITE_ERROR = "Error during writing, is the NFC tag close enough to your device?"
}
}
Search within Codexpedia
Search the entire web