【发布时间】:2022-08-04 19:13:04
【问题描述】:
我正在尝试使用颤振在后台跟踪位置,为此我正在使用background_locator 插件。它的实现方式是注册了某些静态回调函数。我已经声明了一个文件类型的类变量来在后台保存日志。全局变量是在类的最开始构建的。
问题:调用回调方法时,构建的全局变量变为空。因此,尽管我可以在控制台中看到位置日志,但由于对象为空,我无法将其写入文件。
尝试:
- 我已尝试使用他们文档中提供的确切示例。
- 我已将其声明为非静态属性并尝试使用类对象进行访问。
- 尝试将其声明为静态属性。
- 每次需要时都尝试使用相同的路径构建文件对象,但会引发以下问题。
在通道 plugins.flutter.io/path_provider 上找不到方法 getApplicationDocumentsDirectory 的实现
这是我的完整源代码供参考。
import \'dart:async\'; import \'dart:ffi\'; import \'dart:io\'; import \'dart:isolate\'; import \'dart:math\'; import \'dart:ui\'; import \'package:background_locator/background_locator.dart\'; import \'package:background_locator/location_dto.dart\'; import \'package:background_locator/settings/android_settings.dart\'; import \'package:background_locator/settings/ios_settings.dart\'; import \'package:background_locator/settings/locator_settings.dart\'; import \'package:flutter/material.dart\'; import \'package:location_permissions/location_permissions.dart\'; import \'package:path_provider/path_provider.dart\'; import \'package:permission_handler/permission_handler.dart\' as ph; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { ReceivePort port = ReceivePort(); String logStr = \'\'; bool isRunning = false; LocationDto? lastLocation; bool permissionsGranted = false; static const String isolateName = \'LocatorIsolate\'; static int _count = -1; static File? finalFile; void requestPermission() async { var storageStatus = await ph.Permission.storage.status; if (!storageStatus.isGranted) { await ph.Permission.storage.request(); } if (storageStatus.isGranted) { permissionsGranted = true; setPrerequisites(); } setState(() {}); } static Future<void> init(Map<dynamic, dynamic> params) async { //TODO change logs print(\"***********Init callback handler\"); if (params.containsKey(\'countInit\')) { dynamic tmpCount = params[\'countInit\']; if (tmpCount is double) { _count = tmpCount.toInt(); } else if (tmpCount is String) { _count = int.parse(tmpCount); } else if (tmpCount is int) { _count = tmpCount; } else { _count = -2; } } else { _count = 0; } print(\"$_count\"); await setLogLabel(\"start\"); final SendPort? send = IsolateNameServer.lookupPortByName(isolateName); send?.send(null); } static Future<void> disposeLocationService() async { await setLogLabel(\"end\"); final SendPort? send = IsolateNameServer.lookupPortByName(isolateName); send?.send(null); } static Future<void> callback(LocationDto locationDto) async { await setLogPosition(_count, locationDto); final SendPort? send = IsolateNameServer.lookupPortByName(isolateName); send?.send(locationDto); _count++; } static Future<void> setLogLabel(String label) async { final date = DateTime.now(); await _MyAppState().writeToLogFile( \'------------\\n$label: ${formatDateLog(date)}\\n------------\\n\'); } static Future<void> setLogPosition(int count, LocationDto data) async { final date = DateTime.now(); await _MyAppState().writeToLogFile( \'$count : ${formatDateLog(date)} --> ${formatLog(data)} --- isMocked: ${data.isMocked}\\n\'); } static double dp(double val, int places) { num mod = pow(10.0, places); return ((val * mod).round().toDouble() / mod); } static String formatDateLog(DateTime date) { return date.hour.toString() + \":\" + date.minute.toString() + \":\" + date.second.toString(); } static String formatLog(LocationDto locationDto) { return dp(locationDto.latitude, 4).toString() + \" \" + dp(locationDto.longitude, 4).toString(); } @override void initState() { super.initState(); if (permissionsGranted) { setPrerequisites(); } else { requestPermission(); } } void setPrerequisites() async { finalFile = await _getTempLogFile(); if (IsolateNameServer.lookupPortByName(isolateName) != null) { IsolateNameServer.removePortNameMapping(isolateName); } IsolateNameServer.registerPortWithName(port.sendPort, isolateName); port.listen( (dynamic data) async { await updateUI(data); }, ); initPlatformState(); setState(() {}); } Future<void> updateUI(LocationDto data) async { final log = await readLogFile(); await _updateNotificationText(data); setState(() { if (data != null) { lastLocation = data; } logStr = log; }); } Future<void> _updateNotificationText(LocationDto data) async { if (data == null) { return; } await BackgroundLocator.updateNotificationText( title: \"new location received\", msg: \"${DateTime.now()}\", bigMsg: \"${data.latitude}, ${data.longitude}\"); } Future<void> initPlatformState() async { print(\'Initializing...\'); await BackgroundLocator.initialize(); logStr = await readLogFile(); print(\'Initialization done\'); final _isRunning = await BackgroundLocator.isServiceRunning(); setState(() { isRunning = _isRunning; }); print(\'Running ${isRunning.toString()}\'); } @override Widget build(BuildContext context) { final start = SizedBox( width: double.maxFinite, child: ElevatedButton( child: const Text(\'Start\'), onPressed: () { _onStart(); }, ), ); final stop = SizedBox( width: double.maxFinite, child: ElevatedButton( child: Text(\'Stop\'), onPressed: () { onStop(); }, ), ); final clear = SizedBox( width: double.maxFinite, child: ElevatedButton( child: Text(\'Clear Log\'), onPressed: () { clearLogFile(); setState(() { logStr = \'\'; }); }, ), ); String msgStatus = \"-\"; if (isRunning != null) { if (isRunning) { msgStatus = \'Is running\'; } else { msgStatus = \'Is not running\'; } } final status = Text(\"Status: $msgStatus\"); final log = Text( logStr, ); return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text(\'Flutter background Locator\'), ), body: Container( width: double.maxFinite, padding: const EdgeInsets.all(22), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[start, stop, clear, status, log], ), ), ), ), ); } void onStop() async { await BackgroundLocator.unRegisterLocationUpdate(); final _isRunning = await BackgroundLocator.isServiceRunning(); setState(() { isRunning = _isRunning; }); } void _onStart() async { if (await _checkLocationPermission()) { await _startLocator(); final _isRunning = await BackgroundLocator.isServiceRunning(); setState(() { isRunning = _isRunning; lastLocation = null; }); } else { // show error } } static Future<void> initCallback(Map<dynamic, dynamic> params) async { await init(params); } static Future<void> disposeCallback() async { await disposeLocationService(); } Future<void> locationServicecallback(LocationDto locationDto) async { await callback(locationDto); } static Future<void> notificationCallback() async { print(\'***notificationCallback\'); } Future<void> writeToLogFile(String log) async { await finalFile!.writeAsString(log, mode: FileMode.append); } Future<String> readLogFile() async { return finalFile!.readAsString(); } static Future<File?> _getTempLogFile() async { File file = File(\'${(await getApplicationDocumentsDirectory()).path}/log.txt\'); if (file.existsSync()) { return file; } else { file = await file.create(recursive: true); } return file; } Future<void> clearLogFile() async { await finalFile!.writeAsString(\'\'); } Future<bool> _checkLocationPermission() async { final access = await LocationPermissions().checkPermissionStatus(); switch (access) { case PermissionStatus.unknown: case PermissionStatus.denied: case PermissionStatus.restricted: final permission = await LocationPermissions().requestPermissions( permissionLevel: LocationPermissionLevel.locationAlways, ); if (permission == PermissionStatus.granted) { return true; } else { return false; } case PermissionStatus.granted: return true; default: return false; } } Future<void> _startLocator() async { Map<String, dynamic> data = {\'countInit\': 1}; return await BackgroundLocator.registerLocationUpdate( callback, initCallback: initCallback, initDataCallback: data, disposeCallback: disposeCallback, iosSettings: const IOSSettings( accuracy: LocationAccuracy.NAVIGATION, distanceFilter: 0), autoStop: false, androidSettings: const AndroidSettings( accuracy: LocationAccuracy.NAVIGATION, interval: 5, distanceFilter: 0, client: LocationClient.google, androidNotificationSettings: AndroidNotificationSettings( notificationChannelName: \'Location tracking\', notificationTitle: \'Start Location Tracking\', notificationMsg: \'Track location in background\', notificationBigMsg: \'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.\', notificationIconColor: Colors.grey, notificationTapCallback: notificationCallback, ), ), ); } }任何帮助/建议将不胜感激。谢谢!
-
为同样的问题而苦苦挣扎。在回调函数中没有得到回调。背景位置的任何解决方法都会颤抖吗?
标签: android ios flutter dart background