Android NFC Programming Guide

<\/script>\n
'; }, get iframeSnippet() { const domain = '{ SITE_DOMAIN }'; const type = '{ embed_type }'; const slug = '{ embed_slug }'; return ''; }, get activeSnippet() { return this.method === 'script' ? this.scriptSnippet : this.iframeSnippet; }, copySnippet() { navigator.clipboard.writeText(this.activeSnippet).then(() => { this.copied = true; setTimeout(() => { this.copied = false; }, 2000); }); } }" @keydown.escape.window="open = false" @click.outside="open = false">

Embed This Widget

Theme


      
    

Widget powered by . Free, no account required.

From Intent Filters to NDEF

Complete Android NFC development guide from setting up intent filters to reading and writing NDEF messages. Covers manifest configuration, foreground dispatch, HCE, and best practices for Kotlin apps.

| 3 min read

Android NFC Programming Guide

Android has supported NFC since API level 10 (Gingerbread) and provides a mature, well-documented NFC stack. This guide covers the essential APIs, intent filters, and foreground dispatch patterns needed to read and write tags in a production Android app.

Android NFC API Overview

The core classes live in android.nfc and android.nfc.tech:

Class Purpose
NfcAdapter Entry point; check availability, enable/disable foreground dispatch
NdefMessage Container for one or more NdefRecords
NdefRecord Single record: TNF + type + ID + payload
Tag Represents a discovered physical tag
Ndef NDEF operations on a Tag (read, write, makeReadOnly)
IsoDep ISO 14443-4 transport (needed for DESFire / nfcip-1)

Declare permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />

Foreground Dispatch

Foreground dispatch gives your activity priority over the system NFC dispatcher while it is in the foreground — essential for readers that must handle tags while your app is open.

class MainActivity : AppCompatActivity() {
    private lateinit var nfcAdapter: NfcAdapter
    private lateinit var pendingIntent: PendingIntent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        pendingIntent = PendingIntent.getActivity(
            this, 0,
            Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
            PendingIntent.FLAG_MUTABLE
        )
    }

    override fun onResume() {
        super.onResume()
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null)
    }

    override fun onPause() {
        super.onPause()
        nfcAdapter.disableForegroundDispatch(this)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        if (intent.action == NfcAdapter.ACTION_NDEF_DISCOVERED) {
            val rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
            val ndefMessage = rawMessages?.get(0) as? NdefMessage
            ndefMessage?.records?.forEach { record -> processRecord(record) }
        }
    }
}

NDEF Intent Filters

For background launch (without foreground dispatch), declare intent filters in the manifest. The system dispatches in priority order: ACTION_NDEF_DISCOVEREDACTION_TECH_DISCOVEREDACTION_TAG_DISCOVERED.

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https" android:host="nfcfyi.com" />
</intent-filter>

This filter triggers only when a tag contains an ndef-message with an ndef-uri pointing to https://nfcfyi.com/*. Use android:mimeType instead of android:scheme for MIME-type records.

Reading and Writing Records

fun writeUrl(tag: Tag, url: String) {
    val record = NdefRecord.createUri(Uri.parse(url))
    val message = NdefMessage(arrayOf(record))
    val ndef = Ndef.get(tag) ?: return
    ndef.connect()
    ndef.writeNdefMessage(message)
    ndef.close()
}

For nfc-a (Type 2) tags like NTAG, the Ndef tech handles formatting automatically if the tag is blank. For ISO 14443-4 (card-emulation-mode or DESFire), use IsoDep and exchange raw APDUs.

Host Card Emulation (HCE)

hce lets an Android app emulate a contactless card without a hardware secure-element. Extend HostApduService, register an AID in the manifest, and respond to processCommandApdu(). HCE is the backbone of Google Pay's software-based payment path.

Use the NDEF Message Encoder to prototype message structures, and the NDEF Message Decoder to inspect raw payloads captured during development.

See also: iOS Core NFC Programming Guide and Web NFC API Guide.

Frequently Asked Questions

NFC support was introduced in Android API level 9 (Android 2.3). The foreground dispatch system and NdefMessage/NdefRecord classes are available from API 9+. enableReaderMode() — the preferred modern approach that avoids activity restarts — requires API 19 (Android 4.4 KitKat). For new projects, target API 19+ to use enableReaderMode() with callback-based tag delivery.

Foreground dispatch (enableForegroundDispatch) routes NFC intents to the active Activity via Intent extras, causing the Activity to restart if not already running. Reader Mode (enableReaderMode) delivers tags via a callback on a dedicated NFC thread without restarting the Activity, making it simpler to handle in modern Kotlin coroutine-based architectures. Reader Mode is preferred for new Android NFC development.

Use NdefRecord.createUri(Uri.parse("https://example.com")) to create the record, wrap it in an NdefMessage, then call Ndef.get(tag).writeNdefMessage(message) inside a coroutine or background thread. Always call connect() before write() and close() in a finally block. Check Ndef.isWritable() and that the payload fits within Ndef.getMaxSize() bytes before attempting the write.

Use the IsoDep technology class (android.nfc.tech.IsoDep) for ISO 7816-4 APDU communication with Type 4 tags like MIFARE DESFire. Call IsoDep.get(tag), then isoDep.connect() followed by isoDep.transceive(apduBytes) to exchange raw command/response pairs. Parse the response status words (0x9000 = success). IsoDep supports both contactless (ISO 14443-4) and contact-based ISO 7816 cards when used with a USB NFC reader.

Our guides cover a range of experience levels. Getting Started guides are written for beginners with no prior NFC knowledge. Programming guides target developers integrating NFC into mobile apps or embedded systems. Security guides are for engineers designing secure NFC deployments for payments, access control, or authentication.

Most guides require only an NFC-enabled smartphone (iPhone 7+ or any modern Android device) and a few NFC tags (NTAG213 or NTAG215 recommended for beginners, available for under $1 each). Advanced guides may reference USB NFC readers like the ACR122U or Proxmark3 for development and testing.

Yes. Programming guides include code examples for Android (Kotlin/Java with the Android NFC API), iOS (Swift with Core NFC), and web-based tools (Web NFC API for Chrome on Android). All code samples are tested and include inline comments explaining each step.