nfc_tag_reader

pub package license: MIT

A small, hand-written Flutter plugin that reads NFC tags on Android. No off-the-shelf NFC package is used — the bridge is a Kotlin implementation on top of NfcAdapter.enableReaderMode, wired to Dart through a MethodChannel and an EventChannel.

It decodes multiple NDEF record types (plain text, URI, MIME, external, empty) and always exposes the raw payload bytes, so it is useful for real work (contactless cards, tags, ID) rather than a single-tag toy.

Why this exists

I hit a native-only problem in an app (reading contactless NFC tags), solved it with a hand-written Flutter ↔ Kotlin channel, then extracted the bridge into this reusable plugin. NFC read maps directly to fintech use cases: contactless cards, tags and ID.

Features

  • isAvailable() — is NFC present and switched on?
  • startSession() / stopSession() — reader-mode lifecycle, tied correctly to the Android Activity lifecycle (no leaks, survives rotation).
  • Stream<NfcTag> tags — one structured event per tap.
  • Typed models — NfcTag, NdefRecord, NdefRecordType, NfcException. No dynamic leaks to consumers.
  • Graceful handling of "no NFC hardware" and "NFC turned off".

Supported record types

Record NdefRecordType Decoded field
Well-known text (RTD_TEXT) text text, languageCode
Well-known URI (RTD_URI) uri uri
Absolute URI uri uri
MIME media mime mimeType (+ raw payload)
External type external mimeType (+ raw payload)
Empty empty
Anything else unknown raw payload

Install

dependencies:
  nfc_tag_reader: ^0.1.0

Then:

flutter pub get

Android setup

The plugin's manifest already contributes the NFC permission, so it is merged into your app automatically:

<uses-permission android:name="android.permission.NFC" />

If you want the Play Store to hide your app on devices without NFC hardware, add the feature declaration to your app's AndroidManifest.xml (the plugin intentionally does not force this):

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

minSdkVersion must be 19 or higher (enableReaderMode requirement). The plugin targets minSdk 24.

Usage

import 'package:nfc_tag_reader/nfc_tag_reader.dart';

final nfc = NfcTagReader();

Future<void> scanOnce() async {
  if (!await nfc.isAvailable()) return; // no NFC, or it is turned off

  final sub = nfc.tags.listen(
    (tag) {
      for (final record in tag.records) {
        print(record.describe()); // e.g. "URI: https://example.com"
      }
    },
    onError: (Object e) {
      if (e is NfcException && e.reason == NfcErrorReason.disabled) {
        // prompt the user to enable NFC
      }
    },
  );

  try {
    await nfc.startSession();
  } on NfcException catch (e) {
    // e.reason: notSupported / disabled / noActivity
  }

  // ... when done:
  await nfc.stopSession();
  await sub.cancel();
}

A complete, fintech-styled example lives in example/.

Architecture

Dart side

NfcTagReader
    └─▶ NfcTagReaderPlatform   (interface — leaves the iOS seam)
            └─▶ MethodChannelNfcTagReader
                    ├─ MethodChannel  com.abdurrahmanjun/nfc_tag_reader/methods
                    └─ EventChannel   com.abdurrahmanjun/nfc_tag_reader/tags

Kotlin side

NfcTagReaderPlugin
    ├─▶ NfcAdapter.enableReaderMode   (reader-mode lifecycle)
    └─▶ NdefParser                    (Tag → structured map)

The two channels bridge the sides: method calls (startSession / stopSession / isAvailable) flow over the MethodChannel, and each scanned tag is pushed back to Dart as one event over the EventChannel.

Limitations

  • Read-only. Writing NDEF messages is not implemented.
  • Android only today. The federated NfcTagReaderPlatform interface leaves a clean seam for an iOS Core NFC implementation.
  • Uses the tag's cached NDEF message (no blocking IO on the reader thread), so it does not currently read non-NDEF proprietary card data.

Roadmap

  • iOS support via Core NFC (NFCTagReaderSession).
  • NDEF write support.
  • Opt-in deep read for specific tech types (IsoDep, MifareClassic).

License

MIT


Built by Abdurrahman Jundullah M — mobile engineer (Flutter + native Android), 8+ years, fintech/banking background.

Libraries

nfc_tag_reader
A hand-written Flutter plugin for reading NFC tags on Android via a MethodChannel + EventChannel bridge to NfcAdapter.enableReaderMode.