使用 Flutter 关闭应用程序时,iOS 后台位置更新不起作用

问题描述 投票:0回答:1

提供的代码片段是 Flutter 应用程序的一部分,该应用程序使用

flutter_background_service
包来运行后台任务。
onStart
函数是后台服务的入口点,负责定期收集和更新设备的位置。即使我关闭应用程序,这在 Android 上也能完美运行。但在 IOS 中,它仅在应用程序运行或暂停时才起作用。

代码:

Future<void> initializeBackgroundService() async {
  final service = FlutterBackgroundService();

  await service.configure(
    androidConfiguration: AndroidConfiguration(
      onStart: onStart,
      autoStart: false,
      autoStartOnBoot: false,
      isForegroundMode: true,
      initialNotificationTitle: "Tracking",
      initialNotificationContent: 'Refreshing',
    ),
    iosConfiguration: IosConfiguration(
      autoStart: false,
      onForeground: onStart,
    ),
  );
}

Timer? timer;

@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
  print("onStart called with $service");
  try {
    DartPluginRegistrant.ensureInitialized();
    String __ = "";
    String version = "";
    String __ = "";
    String url = "";
    Position? position;

    if (Platform.isAndroid) {
      log("device is android");
      if (service is AndroidServiceInstance) {
        log("device is android service instance");
        service.on('setAsForeground').listen((event) async {
          //my codes
        });
      }
    } else if (Platform.isIOS) {
      service.on('setAsForeground').listen((event) async {
        //my codes
      });
    }

    if (Platform.isIOS) {
      final NotificationService notificationService = NotificationService();
      await notificationService.initializePlatformNotifications();
    }

    service.on('stopService').listen((event) async {
      timer?.cancel();
      await service.stopSelf();
      log("Service stopped");
    });

    if (Platform.isAndroid) {
      log("first notification android");
      if (service is AndroidServiceInstance && await service.isForegroundService()) {
        service.setForegroundNotificationInfo(
          title: "Tracking",
          content: "Last updated at ${DateFormat.jm().format(DateTime.now())}, ${DateFormat.yMd().format(DateTime.now())}",
        );
      }
    } else if (Platform.isIOS) {
      await NotificationService.showNotification(
        id: 0,
        title: "Tracking",
        body: "Last updated at ${DateFormat.jm().format(DateTime.now())}, ${DateFormat.yMd().format(DateTime.now())}",
        data: "",
      );
    }

    timer?.cancel();
    timer = Timer.periodic(const Duration(seconds: 10), (timer) async {
      if (Platform.isAndroid) {
        log("authcode for android $authcode");
        if (service is AndroidServiceInstance) {
          if (await service.isForegroundService()) {
            Position? position;
            bool isLocationEnabled = await Geolocator.isLocationServiceEnabled();
            bool isPermissionGranted = await Geolocator.checkPermission() ==
                LocationPermission.whileInUse ||
                await Geolocator.checkPermission() == LocationPermission.always;
            if (isLocationEnabled && isPermissionGranted) {
              position = await Geolocator.getCurrentPosition(
                  desiredAccuracy: LocationAccuracy.bestForNavigation);
              if (position.accuracy > 200) {
                StreamSubscription<Position> positionStream =
                Geolocator.getPositionStream(
                  locationSettings: AndroidSettings(
                    accuracy: LocationAccuracy.bestForNavigation,
                    distanceFilter: 0,
                    intervalDuration: const Duration(seconds: 1),
                  ),
                ).listen((Position value) {
                  position = value;
                });
                await Future.delayed(const Duration(seconds: 5));
                await positionStream.cancel();
              }
              log("authcode for android before call $authcode");
              log("url for android before call $url");
              //sending location from here
            } else {
              timer.cancel();
              service.stopSelf();
            }
          }
        }
      } else if (Platform.isIOS) {
        Position? position;
        bool isLocationEnabled = await Geolocator.isLocationServiceEnabled();
        bool isPermissionGranted = await Geolocator.checkPermission() ==
            LocationPermission.whileInUse ||
            await Geolocator.checkPermission() == LocationPermission.always;
        if (isLocationEnabled && isPermissionGranted) {
          position = await Geolocator.getCurrentPosition(
              desiredAccuracy: LocationAccuracy.bestForNavigation);
          if (position.accuracy > 200) {
            StreamSubscription<Position> positionStream =
            Geolocator.getPositionStream(
              locationSettings: AppleSettings(
                accuracy: LocationAccuracy.bestForNavigation,
                distanceFilter: 0,
                timeLimit: const Duration(seconds: 1),
                activityType: ActivityType.otherNavigation,
              ),
            ).listen((Position value) {
              position = value;
            });
            await Future.delayed(const Duration(seconds: 5));
            await positionStream.cancel();
          }
         //sending location from here
        
        } else {
          timer.cancel();
          service.stopSelf();
        }
      }
      print('FLUTTER BACKGROUND SERVICE: ${DateTime.now()}');
    });
  } catch (e, stack) {
    print(e);
    print('stack: $stack');
  }
}

我配置了 flutter_background_service 包并启用了 UIBackgroundModes 以在 Info.plist 文件中进行位置更新。

<key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>dev.flutter.background.refresh</string>
        <string>myBackgroundTask</string>
    </array>
<key>UIBackgroundModes</key>
    <array>
        <string>location</string>
        <string>fetch</string>
        <string>remote-notification</string>
    </array>

这是 Appdelegate.swift

import UIKit
import Flutter
import flutter_background_service_ios

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        SwiftFlutterBackgroundServicePlugin.taskIdentifier = "dev.flutter.background.refresh"
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

ios flutter background-service ios-background-mode flutter-background
1个回答
0
投票

此包的 API 文档的最后一段看起来完美地描述了您所看到的症状:

当应用程序在 iOS 上处于后台(最小化)时服务终止

请记住,iOS 没有像 Android 那样的长期运行的服务功能。因此,当您的应用程序在后台时不可能保持其运行,因为操作系统很快就会挂起您的应用程序。目前,该插件提供了 onBackground 方法,该方法将通过 iOS 提供的后台 Fetch 功能定期执行。它不能快于 15 分钟,并且只能存活约 15-30 秒。

© www.soinside.com 2019 - 2024. All rights reserved.