- Send config to native before starting tracking (SharedPreferences sync) - Register ConnectivityReceiver for network state detection - Fix Settings number fields using TextEditingControllers - Cancel stream subscription on widget dispose (memory leak) - Replace WorkManager with AlarmManager for heartbeat - Add log cleanup for logs older than 24 hours - Change HTTP method from GET to POST These fixes resolve the 'device always offline' issue where: 1. Config was not being sent to native service 2. ConnectivityReceiver was never registered 3. Settings number fields were not saving 4. Heartbeat never fired due to WorkManager process isolation 5. Server expected POST not GET
94 lines
3 KiB
Dart
94 lines
3 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
class LocationBridge {
|
|
static const MethodChannel _methodChannel = MethodChannel(
|
|
'com.traccar.client/tracking',
|
|
);
|
|
static const EventChannel _eventChannel = EventChannel(
|
|
'com.traccar.client/location_updates',
|
|
);
|
|
|
|
static Stream<Map<String, dynamic>>? _locationStream;
|
|
|
|
static Future<bool> startTracking({Map<String, dynamic>? config}) async {
|
|
debugPrint('LocationBridge.startTracking called with config: $config');
|
|
try {
|
|
if (config != null) {
|
|
await _methodChannel.invokeMethod('updateConfig', config);
|
|
}
|
|
final result = await _methodChannel.invokeMethod<bool>('startTracking');
|
|
debugPrint('LocationBridge.startTracking result: $result');
|
|
return result ?? false;
|
|
} on PlatformException catch (e) {
|
|
debugPrint('LocationBridge.startTracking failed: ${e.message}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Future<bool> stopTracking() async {
|
|
debugPrint('LocationBridge.stopTracking called');
|
|
try {
|
|
final result = await _methodChannel.invokeMethod<bool>('stopTracking');
|
|
debugPrint('LocationBridge.stopTracking result: $result');
|
|
return result ?? false;
|
|
} on PlatformException catch (e) {
|
|
debugPrint('LocationBridge.stopTracking failed: ${e.message}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Future<bool> updateConfig(Map<String, dynamic> config) async {
|
|
try {
|
|
final result = await _methodChannel.invokeMethod<bool>(
|
|
'updateConfig',
|
|
config,
|
|
);
|
|
return result ?? false;
|
|
} on PlatformException catch (e) {
|
|
debugPrint('Failed to update config: ${e.message}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Future<Map<String, dynamic>?> getStatus() async {
|
|
debugPrint('LocationBridge.getStatus called');
|
|
try {
|
|
final result = await _methodChannel.invokeMethod<Map>('getStatus');
|
|
debugPrint('LocationBridge.getStatus result: $result');
|
|
return result?.cast<String, dynamic>();
|
|
} on PlatformException catch (e) {
|
|
debugPrint('LocationBridge.getStatus failed: ${e.message}');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<bool> reportLocation() async {
|
|
try {
|
|
final result = await _methodChannel.invokeMethod<bool>('reportLocation');
|
|
return result ?? false;
|
|
} on PlatformException catch (e) {
|
|
debugPrint('Failed to report location: ${e.message}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Stream<Map<String, dynamic>> get locationUpdates {
|
|
_locationStream ??= _eventChannel.receiveBroadcastStream().map(
|
|
(event) => Map<String, dynamic>.from(event as Map),
|
|
);
|
|
return _locationStream!;
|
|
}
|
|
|
|
static Future<List<Map<String, dynamic>>> getLogs({int limit = 100}) async {
|
|
try {
|
|
final result = await _methodChannel.invokeMethod<List>('getLogs', limit);
|
|
return result?.map((e) => Map<String, dynamic>.from(e as Map)).toList() ??
|
|
[];
|
|
} on PlatformException catch (e) {
|
|
debugPrint('Failed to get logs: ${e.message}');
|
|
return [];
|
|
}
|
|
}
|
|
}
|