Open In App

How to Create a NFC Reader and Writer Flutter Application

Last Updated : 25 Feb, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

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

  1. NFC-Enabled Android Device - Your device must support NFC.
  2. Android Studio  or Visual Studio Code- Install Android Studio or Visual Studio Code in your System.
  3. Basic Knowledge of Flutter & dart - We will be developing this app using the Flutter & Dart.
  4. 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.



Next Article
Article Tags :

Similar Reads