import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; void showNfcReader(BuildContext context, {required Function(String? nfcId) onNcfScan}) { showModalBottomSheet( context: context, enableDrag: false, isDismissible: false, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), ), backgroundColor: Colors.white, builder: (context) { return NfcLayout( onNcfScan: onNcfScan, ); }, ); } class NfcLayout extends StatefulWidget { final Function(String? nfcId) onNcfScan; const NfcLayout({super.key, required this.onNcfScan}); @override _NfcLayoutState createState() => _NfcLayoutState(); } class _NfcLayoutState extends State { bool _reading = false; Widget? mainWidget; String? nfcId; @override void initState() { super.initState(); NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { String? identifier; // Access tag identifier from the tag data // In nfc_manager 4.1.1, access data via dynamic cast to bypass protected member try { final dynamic tagDynamic = tag; final Map tagData = Map.from(tagDynamic.data as Map); if (Platform.isAndroid) { // For Android, try NfcA technology first if (tagData.containsKey('nfca')) { final nfcaData = tagData['nfca'] as Map; if (nfcaData.containsKey('identifier')) { final List idBytes = List.from(nfcaData['identifier'] as List); identifier = idBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } // Fallback to other technologies if NfcA is not available if (identifier == null && tagData.containsKey('nfcb')) { final nfcbData = tagData['nfcb'] as Map; if (nfcbData.containsKey('identifier')) { final List idBytes = List.from(nfcbData['identifier'] as List); identifier = idBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } else { // For iOS, try MiFare technology if (tagData.containsKey('mifare')) { final mifareData = tagData['mifare'] as Map; if (mifareData.containsKey('identifier')) { final List idBytes = List.from(mifareData['identifier'] as List); identifier = idBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } // Fallback to iso15693 for iOS if (identifier == null && tagData.containsKey('iso15693')) { final iso15693Data = tagData['iso15693'] as Map; if (iso15693Data.containsKey('identifier')) { final List idBytes = List.from(iso15693Data['identifier'] as List); identifier = idBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } // Universal fallback: try Ndef if available if (identifier == null && tagData.containsKey('ndef')) { final ndefData = tagData['ndef'] as Map; if (ndefData.containsKey('identifier')) { final List idBytes = List.from(ndefData['identifier'] as List); identifier = idBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } catch (e) { print('Error reading NFC tag: $e'); } nfcId = identifier; setState(() { _reading = true; mainWidget = doneNfc(); }); Future.delayed(const Duration(seconds: 1), () { NfcManager.instance.stopSession(); Navigator.pop(context); widget.onNcfScan(nfcId); }); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { print(err); }); } @override Widget build(BuildContext context) { (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); } Widget scanNfc() { return Container( key: ValueKey(1), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: 30, ), Text( "Ready To Scan", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 24, ), ), SizedBox( height: 30, ), Image.asset( "assets/images/nfc_dummy.png", height: MediaQuery.of(context).size.width / 3, width: double.infinity, ), SizedBox( height: 30, ), Text( "Approach an NFC Tag", style: TextStyle( fontSize: 18, ), ), SizedBox( height: 30, ), ButtonTheme( minWidth: MediaQuery.of(context).size.width / 1.2, height: 45.0, buttonColor: Colors.grey[300], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), child: TextButton( onPressed: () { NfcManager.instance.stopSession(); Navigator.pop(context); }, // elevation: 0, child: Text("CANCEL"), ), ), SizedBox( height: 30, ), ], ), ); } Widget doneNfc() { return Container( key: ValueKey(2), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: 30, ), Text( "Successfully Scanned", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 24, ), ), SizedBox( height: 30, ), Image.asset( // "assets/icons/nfc/ic_done.png", "assets/images/done_dummy.jpeg", height: MediaQuery.of(context).size.width / 3, width: double.infinity, ), SizedBox( height: 30, ), Text( "Approach an NFC Tag", style: TextStyle( fontSize: 18, ), ), SizedBox( height: 30, ), ButtonTheme( minWidth: MediaQuery.of(context).size.width / 1.2, height: 45.0, buttonColor: Colors.grey[300], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), child: TextButton( // onPressed: () { // _stream?.cancel(); // widget.onNcfScan(nfcId); // Navigator.pop(context); // }, onPressed: null, // elevation: 0, child: Text("DONE"), ), ), SizedBox( height: 30, ), ], ), ); } }