【问题标题】:Issue while using background_locator plugin while tracking background location in flutter在颤动中跟踪背景位置时使用 background_locator 插件时出现问题
【发布时间】:2022-08-04 19:13:04
【问题描述】:

我正在尝试使用颤振在后台跟踪位置,为此我正在使用background_locator 插件。它的实现方式是注册了某些静态回调函数。我已经声明了一个文件类型的类变量来在后台保存日志。全局变量是在类的最开始构建的。

问题:调用回调方法时,构建的全局变量变为空。因此,尽管我可以在控制台中看到位置日志,但由于对象为空,我无法将其写入文件。

尝试:

  1. 我已尝试使用他们文档中提供的确切示例。
  2. 我已将其声明为非静态属性并尝试使用类对象进行访问。
  3. 尝试将其声明为静态属性。
  4. 每次需要时都尝试使用相同的路径构建文件对象,但会引发以下问题。

    在通道 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


【解决方案1】:

回调函数没有被调用是我在 1.6.12 版本中遇到的问题。

我解决了这个问题

  1. 在 github 上分叉 background_locator 存储库。
  2. 将 repo 克隆到我的计算机
  3. 打开 location_dto.dart 文件并转到fromJson 函数。
  4. 添加了 json[Keys.ARG_PROVIDER] ?? '' 反而
  5. 提交并推送到我的分叉存储库
  6. 在 pubspec.yaml 中,我更新了我的依赖项以指向我的分叉存储库,如下所示:
      background_locator:
        git:
          url: git@github.com:frankvollebregt/background_locator.git
    

    如果您发现任何问题,请关注这两个 github 问题:

【讨论】:

  • 感谢 Oumar 的回复。但是我仍然无法执行从您的分支签出的示例。我一直面临的问题是日志没有正确写入文件。每次尝试创建日志文件时,都会引发问题。如果你有你的 git,你能分享一下这个工作示例吗?!
【解决方案2】:

background_locator 在最新的 Flutter sdk 版本上不起作用 对我来说,当我执行这些步骤时它起作用了

  • Flutter sdk 版本应该是:3.0.1
  • 在 pubspec.yaml 文件中更改 sdk:">=2.8.0 <3.0.0"
  • 不要将代码迁移到空安全
  • 在 gradle-wrapper.properties 中将 gradle 版本更改为 gradle-6.5
  • android/build gradle 将 ext.kotlin_version 更改为 '1.4.31'
  • android/app/build gradle 将 compileSdkVersion 更改为 31,将 minSdkVersion 更改为 19,将 targetSdkVersion 更改为 30

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2011-05-15
    • 1970-01-01
    相关资源
    最近更新 更多