import "dart:io"; import "package:flutter/services.dart"; /// Detected beacon from native scanner class DetectedBeacon { final String uuid; final int rssi; final int samples; const DetectedBeacon({ required this.uuid, required this.rssi, required this.samples, }); factory DetectedBeacon.fromMap(Map map) { return DetectedBeacon( uuid: (map["uuid"] as String?) ?? "", rssi: (map["rssi"] as int?) ?? -100, samples: (map["samples"] as int?) ?? 0, ); } @override String toString() => "DetectedBeacon(uuid: $uuid, rssi: $rssi, samples: $samples)"; } /// Native beacon scanner via MethodChannel /// Only works on Android. iOS falls back to Flutter plugin. class BeaconChannel { static const _channel = MethodChannel("com.payfrit.app/beacon"); /// Check if running on Android (native scanner only works there) static bool get isSupported => Platform.isAndroid; /// Check if Bluetooth permissions are granted static Future hasPermissions() async { if (!isSupported) return false; try { final result = await _channel.invokeMethod("hasPermissions"); return result ?? false; } on PlatformException catch (e) { print("[BeaconChannel] hasPermissions error: $e"); return false; } } /// Check if Bluetooth is enabled static Future isBluetoothEnabled() async { if (!isSupported) return false; try { final result = await _channel.invokeMethod("isBluetoothEnabled"); return result ?? false; } on PlatformException catch (e) { print("[BeaconChannel] isBluetoothEnabled error: $e"); return false; } } /// Start scanning for beacons /// Returns list of detected beacons sorted by RSSI (strongest first) static Future> startScan({List? regions}) async { if (!isSupported) { print("[BeaconChannel] Not supported on this platform"); return []; } try { print("[BeaconChannel] Starting native beacon scan..."); final result = await _channel.invokeMethod>( "startScan", {"regions": regions ?? []}, ); if (result == null) { print("[BeaconChannel] Scan returned null"); return []; } final beacons = result .map((e) => DetectedBeacon.fromMap(e as Map)) .toList(); print("[BeaconChannel] Scan complete: found ${beacons.length} beacons"); for (final b in beacons) { print("[BeaconChannel] $b"); } return beacons; } on PlatformException catch (e) { print("[BeaconChannel] Scan error: ${e.message}"); return []; } } /// Stop an ongoing scan static Future stopScan() async { if (!isSupported) return; try { await _channel.invokeMethod("stopScan"); } on PlatformException catch (e) { print("[BeaconChannel] stopScan error: $e"); } } }