diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 7c569640..391a902b 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 12.0 diff --git a/ios/Podfile b/ios/Podfile index 28532b78..de9dd564 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -40,7 +40,7 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' end target.build_configurations.each do |config| flutter_additional_ios_build_settings(target) @@ -53,7 +53,7 @@ post_install do |installer| installer.generated_projects.each do |project| project.targets.each do |target| target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', ## dart: PermissionGroup.microphone diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 159a3dcf..5d0c0f62 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -375,7 +375,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -433,8 +433,6 @@ "-framework", "\"GoogleUtilities\"", "-framework", - "\"MTBBarcodeScanner\"", - "-framework", "\"MediaPlayer\"", "-framework", "\"QuartzCore\"", @@ -443,10 +441,6 @@ "-framework", "\"SystemConfiguration\"", "-framework", - "\"Toast\"", - "-framework", - "\"Try\"", - "-framework", "\"UIKit\"", "-framework", "\"audioplayers_darwin\"", @@ -471,8 +465,6 @@ "-framework", "\"speech_to_text\"", "-framework", - "\"sqflite\"", - "-framework", "\"url_launcher_ios\"", "-weak_framework", "\"UserNotifications\"", @@ -538,7 +530,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -591,7 +583,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -651,8 +643,6 @@ "-framework", "\"GoogleUtilities\"", "-framework", - "\"MTBBarcodeScanner\"", - "-framework", "\"MediaPlayer\"", "-framework", "\"QuartzCore\"", @@ -661,10 +651,6 @@ "-framework", "\"SystemConfiguration\"", "-framework", - "\"Toast\"", - "-framework", - "\"Try\"", - "-framework", "\"UIKit\"", "-framework", "\"audioplayers_darwin\"", @@ -689,8 +675,6 @@ "-framework", "\"speech_to_text\"", "-framework", - "\"sqflite\"", - "-framework", "\"url_launcher_ios\"", "-weak_framework", "\"UserNotifications\"", @@ -755,8 +739,6 @@ "-framework", "\"GoogleUtilities\"", "-framework", - "\"MTBBarcodeScanner\"", - "-framework", "\"MediaPlayer\"", "-framework", "\"QuartzCore\"", @@ -765,10 +747,6 @@ "-framework", "\"SystemConfiguration\"", "-framework", - "\"Toast\"", - "-framework", - "\"Try\"", - "-framework", "\"UIKit\"", "-framework", "\"audioplayers_darwin\"", @@ -793,8 +771,6 @@ "-framework", "\"speech_to_text\"", "-framework", - "\"sqflite\"", - "-framework", "\"url_launcher_ios\"", "-weak_framework", "\"UserNotifications\"", diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d3..9c12df59 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/lib/helper/utils.dart b/lib/helper/utils.dart index d35cd4cb..82d3f879 100644 --- a/lib/helper/utils.dart +++ b/lib/helper/utils.dart @@ -20,6 +20,8 @@ import 'package:google_api_availability/google_api_availability.dart'; // import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; // import 'package:mohem_flutter_app/widgets/loading_dialog.dart'; import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; +import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart'; @@ -416,29 +418,41 @@ class Utils { // return selectedDate; // } - static void readNFc({required Function(String) onRead}) { + static void readNFc({required Function(String) onRead}) async { + // Stop any existing session before starting a new one + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('No active session to stop: $e'); + } + NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { String identifier = ''; try { - final dynamic tagDynamic = tag; - final Map tagData = Map.from(tagDynamic.data as Map); - if (Platform.isAndroid) { - 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(''); + // Try NfcA first (most common) + final nfcA = NfcAAndroid.from(tag); + if (nfcA != null) { + identifier = nfcA.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to NfcB + final nfcB = NfcBAndroid.from(tag); + if (nfcB != null) { + identifier = nfcB.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } else { - 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(''); + // For iOS, try MiFare first + final mifare = MiFareIos.from(tag); + if (mifare != null) { + identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to Iso15693 for iOS + final iso15693 = Iso15693Ios.from(tag); + if (iso15693 != null) { + identifier = iso15693.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } @@ -446,12 +460,20 @@ class Utils { print('Error reading NFC: $e'); } - NfcManager.instance.stopSession(); + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping NFC session: $e'); + } onRead(identifier); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { - print(err); + print('NFC session error: $err'); + // Stop session on error + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping session after error: $e'); + }); }); } diff --git a/lib/new_views/swipe_module/dialoge/nfc_reader_sheet.dart b/lib/new_views/swipe_module/dialoge/nfc_reader_sheet.dart index 7eecd8e2..ffab4991 100644 --- a/lib/new_views/swipe_module/dialoge/nfc_reader_sheet.dart +++ b/lib/new_views/swipe_module/dialoge/nfc_reader_sheet.dart @@ -3,6 +3,8 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; +import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; import 'package:test_sa/dashboard_latest/dashboard_view.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -42,29 +44,53 @@ class _NfcLayoutState extends State { @override void initState() { super.initState(); + _startNfcSession(); + } + + @override + void dispose() { + // Ensure session is stopped when widget is disposed + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping NFC session in dispose: $e'); + }); + super.dispose(); + } + + void _startNfcSession() async { + // Stop any existing session before starting a new one + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('No active session to stop: $e'); + } NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { String? identifier; try { - final dynamic tagDynamic = tag; - final Map tagData = Map.from(tagDynamic.data as Map); - if (Platform.isAndroid) { - 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(''); + // Try NfcA first (most common) + final nfcA = NfcAAndroid.from(tag); + if (nfcA != null) { + identifier = nfcA.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to NfcB + final nfcB = NfcBAndroid.from(tag); + if (nfcB != null) { + identifier = nfcB.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } else { - 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(''); + // For iOS, try MiFare first + final mifare = MiFareIos.from(tag); + if (mifare != null) { + identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to Iso15693 for iOS + final iso15693 = Iso15693Ios.from(tag); + if (iso15693 != null) { + identifier = iso15693.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } @@ -74,20 +100,32 @@ class _NfcLayoutState extends State { nfcId = identifier; + if (!mounted) return; + setState(() { _reading = true; mainWidget = doneNfc(); }); - Future.delayed(const Duration(seconds: 1), () { - NfcManager.instance.stopSession(); - Navigator.pop(context); - widget.onNcfScan!(nfcId!); + Future.delayed(const Duration(seconds: 1), () async { + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping session: $e'); + } + if (mounted) { + Navigator.pop(context); + widget.onNcfScan!(nfcId!); + } }); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { - print(err); + print('NFC session error: $err'); + // Stop session on error + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping session after error: $e'); + }); }); } @@ -144,9 +182,15 @@ class _NfcLayoutState extends State { borderRadius: BorderRadius.circular(6), ), child: TextButton( - onPressed: () { - NfcManager.instance.stopSession(); - Navigator.pop(context); + onPressed: () async { + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping NFC session: $e'); + } + if (mounted) { + Navigator.pop(context); + } }, // elevation: 0, child: const Text("CANCEL"), diff --git a/lib/new_views/swipe_module/utils/swipe_general_utils.dart b/lib/new_views/swipe_module/utils/swipe_general_utils.dart index ded2daa6..14bd3a40 100644 --- a/lib/new_views/swipe_module/utils/swipe_general_utils.dart +++ b/lib/new_views/swipe_module/utils/swipe_general_utils.dart @@ -10,6 +10,8 @@ import 'package:google_api_availability/google_api_availability.dart'; import 'package:huawei_location/huawei_location.dart'; import 'package:intl/intl.dart'; import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; +import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -299,6 +301,7 @@ class SwipeGeneralUtils { if (Platform.isIOS) { readNFc(onRead: (String nfcId) async { + print("nfcId:$nfcId"); await _processNfcAttendance(nfcId, latitude, longitude, context); }); } else { @@ -456,29 +459,41 @@ class SwipeGeneralUtils { ); } - void readNFc({Function(String)? onRead}) { + void readNFc({Function(String)? onRead}) async { + // Stop any existing session before starting a new one + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('No active session to stop: $e'); + } + NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { String identifier = ''; try { - final dynamic tagDynamic = tag; - final Map tagData = Map.from(tagDynamic.data as Map); - if (Platform.isAndroid) { - 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(''); + // Try NfcA first (most common) + final nfcA = NfcAAndroid.from(tag); + if (nfcA != null) { + identifier = nfcA.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to NfcB + final nfcB = NfcBAndroid.from(tag); + if (nfcB != null) { + identifier = nfcB.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } else { - 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(''); + // For iOS, try MiFare first + final mifare = MiFareIos.from(tag); + if (mifare != null) { + identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to Iso15693 for iOS + final iso15693 = Iso15693Ios.from(tag); + if (iso15693 != null) { + identifier = iso15693.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } @@ -486,12 +501,20 @@ class SwipeGeneralUtils { print('Error reading NFC: $e'); } - NfcManager.instance.stopSession(); + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping NFC session: $e'); + } onRead!(identifier); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { - print(err); + print('NFC session error: $err'); + // Stop session on error + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping session after error: $e'); + }); }); } diff --git a/lib/nfc/nfc_reader_sheet.dart b/lib/nfc/nfc_reader_sheet.dart index 151b1ebb..e2c1e0e4 100644 --- a/lib/nfc/nfc_reader_sheet.dart +++ b/lib/nfc/nfc_reader_sheet.dart @@ -3,6 +3,8 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; +import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; void showNfcReader(BuildContext context, {required Function(String? nfcId) onNcfScan}) { showModalBottomSheet( @@ -38,60 +40,55 @@ class _NfcLayoutState extends State { @override void initState() { super.initState(); + _startNfcSession(); + } + + @override + void dispose() { + // Ensure session is stopped when widget is disposed + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping NFC session in dispose: $e'); + }); + super.dispose(); + } + + void _startNfcSession() async { + // Stop any existing session before starting a new one + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('No active session to stop: $e'); + } 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(''); + // Try NfcA first (most common) + final nfcA = NfcAAndroid.from(tag); + if (nfcA != null) { + identifier = nfcA.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to NfcB + final nfcB = NfcBAndroid.from(tag); + if (nfcB != null) { + identifier = nfcB.tag.id.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(''); + // For iOS, try MiFare first + final mifare = MiFareIos.from(tag); + if (mifare != null) { + identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + } else { + // Fallback to Iso15693 for iOS + final iso15693 = Iso15693Ios.from(tag); + if (iso15693 != null) { + identifier = iso15693.identifier.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'); @@ -99,20 +96,32 @@ class _NfcLayoutState extends State { nfcId = identifier; + if (!mounted) return; + setState(() { _reading = true; mainWidget = doneNfc(); }); - Future.delayed(const Duration(seconds: 1), () { - NfcManager.instance.stopSession(); - Navigator.pop(context); - widget.onNcfScan(nfcId); + Future.delayed(const Duration(seconds: 1), () async { + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping session: $e'); + } + if (mounted) { + Navigator.pop(context); + widget.onNcfScan(nfcId); + } }); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { - print(err); + print('NFC session error: $err'); + // Stop session on error + NfcManager.instance.stopSession().catchError((e) { + print('Error stopping session after error: $e'); + }); }); } @@ -166,9 +175,15 @@ class _NfcLayoutState extends State { borderRadius: BorderRadius.circular(6), ), child: TextButton( - onPressed: () { - NfcManager.instance.stopSession(); - Navigator.pop(context); + onPressed: () async { + try { + await NfcManager.instance.stopSession(); + } catch (e) { + print('Error stopping NFC session: $e'); + } + if (mounted) { + Navigator.pop(context); + } }, // elevation: 0, child: Text("CANCEL"), diff --git a/pubspec.lock b/pubspec.lock index 50ce5e15..c30cf843 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1030,6 +1030,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + mobile_scanner: + dependency: "direct main" + description: + name: mobile_scanner + sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce + url: "https://pub.dev" + source: hosted + version: "7.2.0" native_toolchain_c: dependency: transitive description: