How to Create a NFC Reader and Writer Flutter Application
Last Updated :
25 Feb, 2025
NFC that stands for Near Field Communication, is a very short range wireless technology that allows us share small amount of data between devices. Through this technology we can share data between an NFC tag and an android device or between two android devices. A maximum of 4 cm distance is required to establish this connection. In this articles, we will be developing a basic application that involved communicating between an Android Device and a NFC Tag.
Prerequisites
- NFC-Enabled Android Device - Your device must support NFC.
- Android Studio or Visual Studio Code- Install Android Studio or Visual Studio Code in your System.
- Basic Knowledge of Flutter & dart - We will be developing this app using the Flutter & Dart.
- NFC Tag - You must have a NFC tag, sticker or a card for testing purposes.
Steps to Create a NFC Reader and Writer Android Application
Step 1: Create a New Project in Android Studio or Visual Studio Code.
To create a new project in Android Studio please refer to Creating a Simple Application in Flutter.
Step 2: In your flutter project open pubspec.yaml and under dependencies add the following packages:
dependencies:
flutter:
sdk: flutter
nfc_manager: ^3.5.0
To know more about package refer : nfc_manager
Step 3: Adding Permissions in Manifest File
Navigate to android > app > src > main > AndroidManifest.xml and add the following permissions under the manifest tag.
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required ="true" />
Step 3: Working with main.dart
main.dart include 3 primary functionalities to execute NFC in flutter application.
- Check the device is compatible with NFC or Not
- Read data using NFC
- Write data using NFC
- Check the device is compatible with NFC or not.
Dart
NfcManager.instance.isAvailable().then((isAvailable) {
if (isAvailable) {
print("availble"); // Start NFC session if available
} else {
print("unavailble"); // Show error message if NFC is not available
}
});
- Read data using NFC
Dart
// Function to read NFC tag
void _readNfcTag() {
//Start NFC session
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
Ndef? ndef = Ndef.from(tag);
if (ndef != null) {
// Read message from tag
NdefMessage? message = await ndef.read();
//Code to Store the fetched data from tag
....
}
// Stop NFC session
NfcManager.instance.stopSession();
});
}
- Write data using NFC
Dart
void _writeNfcTag() {
// Start NFC session
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
// Example of writing data to the tag
Ndef? ndef = Ndef.from(tag);
if (ndef != null && ndef.isWritable) {
// Create NDEF message with input text
NdefMessage message = NdefMessage([
NdefRecord.createText(String_data),
]);
// Write message to tag
await ndef.write(message);
}
// Stop NFC session
NfcManager.instance.stopSession();
});
}
The whole Application code for this is provided below:
main.dart:
Dart
import 'package:flutter/material.dart';
import 'package:nfc_manager/nfc_manager.dart';
void main() {
// Start the app
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false, // Hide the debug banner
home: NfcScreen(), // Set the home screen to BitCoinTracker
);
}
}
// Main class for the NFC screen
class NfcScreen extends StatefulWidget {
@override
_NfcScreenState createState() => _NfcScreenState();
}
// State class for the NFC screen
class _NfcScreenState extends State<NfcScreen> {
// Variable to store NFC data
String _nfcData = 'No data';
// Controller for text input
final TextEditingController _textController = TextEditingController();
@override
void initState() {
super.initState();
// Check if NFC is available
NfcManager.instance.isAvailable().then((isAvailable) {
if (isAvailable) {
// Start NFC session if available
}
else {
setState(() {
// Update UI if NFC is not available
_nfcData = 'NFC is not available';
});
}
});
}
// Function to start NFC session
void _writeNfcTag() {
// Start NFC session
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
// Example of writing data to the tag
Ndef? ndef = Ndef.from(tag);
if (ndef != null && ndef.isWritable) {
// Create NDEF message with input text
NdefMessage message = NdefMessage([
NdefRecord.createText(_textController.text),
]);
try {
// Write message to tag
await ndef.write(message);
setState(() {
// Update UI on success
_nfcData = 'Write successful!';
});
} catch (e) {
setState(() {
// Update UI on failure
_nfcData = 'Write failed: $e';
});
}
}
// Stop NFC session
NfcManager.instance.stopSession();
});
}
// Function to read NFC tag
void _readNfcTag() {
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
Ndef? ndef = Ndef.from(tag);
if (ndef != null) {
// Read message from tag
NdefMessage? message = await ndef.read();
setState(() {
// Store payload in temp variable
var rawData = message.records.first.payload;
// Convert payload to string
String textData = String.fromCharCodes(rawData);
// Update UI with read data
_nfcData = textData.substring(3);
});
}
// Stop NFC session
NfcManager.instance.stopSession();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('NFC Screen'), // App bar title
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _textController,
decoration: InputDecoration(
labelText: 'Enter data to write', // Input field label
),
),
ElevatedButton(
onPressed: _writeNfcTag,
child: Text('Write to NFC'), // Button to write to NFC
),
ElevatedButton(
onPressed: _readNfcTag,
child: Text('Read from NFC'), // Button to read from NFC
),
SizedBox(height: 20),
Text(_nfcData), // Display NFC data
],
),
),
);
}
}
Output:
Note : default NFC reader can pop-up in your screen. So, the solution is preventing default Android NFC reader.
Solution of the above Problem
If you get any uneven behavior of the app like opening a default pop-up in the middle of the process then to control that behavior add below code in android > app > src > main > kotlin > com > example > oyo > MainActivity.kt.
MainActivity.kt:
Kotlin
package com.example.yourapp
import android.app.PendingIntent
import android.content.Intent
import android.nfc.NfcAdapter
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
// This method is called when the
// activity is resumed
override fun onResume() {
super.onResume()
// Create an intent to restart
// this activity
val intent = Intent(context, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
// Create a pending intent to be
// used by the NFC adapter
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// Enable NFC foreground dispatch
// to handle NFC tags when the app
// is in the foreground
NfcAdapter.getDefaultAdapter(context)?.enableForegroundDispatch(this, pendingIntent, null, null)
}
// This method is called when the
// activity is paused
override fun onPause() {
super.onPause()
// Disable NFC foreground dispatch
// when the app is not in the foreground
NfcAdapter.getDefaultAdapter(context)?.disableForegroundDispatch(this)
}
}
For GitHub link for the repository for the application is refer to this link.