На стороне Flutter я проверю наличие всех необходимых разрешений перед передачей регионов в Native. сторона через канал метода для мониторинга региона и использует EventChannel для информирования стороны Flutter о том, что пользователь либо вышел из региона, либо вошел в него. Все работает как положено, когда приложение активно на переднем плане или в фоновом режиме. Однако, когда я закрываю приложение, мониторинг региона, похоже, больше не работает.
Я попробовал этот прототип, который является полностью встроенным, он отлично работает на переднем плане, в фоновом режиме и в состоянии завершения.
Ниже приведен мой код на нативной стороне
Код: Выделить всё
import UIKit
import CoreLocation
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var locationManager: CLLocationManager!
var eventSink: FlutterEventSink?
var regions: [CLCircularRegion] = []
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "location", binaryMessenger: controller.binaryMessenger)
let eventChannel = FlutterEventChannel(name: "location_stream", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler(handle)
eventChannel.setStreamHandler(self)
locationManager = CLLocationManager()
locationManager.delegate = self
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
print("regrion monitoring: here")
switch call.method {
case "startMonitoring":
startMonitoring()
result(nil)
case "stopMonitoring":
stopMonitoring()
result(nil)
case "setRegions":
setRegions(call: call)
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}
private func startMonitoring() {
print("regrion monitoring: start")
eventSink?(["type": 3, "identifier": "startMonitoring"])
for o in regions {
eventSink?(["type": 3, "identifier": "startMonitoring: \(o.identifier)"])
print("regrion monitoring: \(o.identifier)")
o.notifyOnExit = true;
o.notifyOnEntry = true;
locationManager.startMonitoring(for: o)
}
}
private func stopMonitoring() {
print("regrion monitoring: stop")
for o in regions {
locationManager.stopMonitoring(for: o)
}
// locationManager.delegate = nil
eventSink = nil
}
private func setRegions(call: FlutterMethodCall) {
let argResult = call.arguments as? [String: [String: Any]]
for s in argResult!.keys {
print("regrion monitoring: \(s)");
regions.append(CLCircularRegion(
center: CLLocationCoordinate2D(latitude: argResult![s]!["latitude"] as! Double, longitude: argResult![s]!["longitude"] as! Double),
radius: argResult![s]!["radius"] as! Double,
identifier: argResult![s]!["description"] as! String))
}
}
private func handleEvent(forRegion region: CLRegion, type: Int) {
print("regrion monitoring: \(region.identifier)")
eventSink?(["type": type, "identifier": region.identifier])
print("regrion monitoring: after event sink")
}
}
extension AppDelegate: CLLocationManagerDelegate {
public func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
print("regrion monitoring: didStartMonitoring")
print("\(region.identifier)")
}
public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("regrion monitoring: Enter")
if region is CLCircularRegion {
handleEvent(forRegion: region, type: 0)
}
}
public func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("regrion monitoring: Exit")
if region is CLCircularRegion {
handleEvent(forRegion: region, type: 1)
}
}
}
extension AppDelegate: FlutterStreamHandler {
@objc public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("onListen")
self.eventSink = events
return nil
}
@objc public func onCancel(withArguments arguments: Any?) -> FlutterError? {
print("onCancel")
self.eventSink = nil
return nil
}
}
main.dart
Код: Выделить всё
import 'package:flutter/material.dart';
import 'package:regrion_monitoring/location.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State createState() => _MainAppState();
}
class _MainAppState extends State {
@override
void initState() {
super.initState();
requestLocationService().then((value) async {
if (value) {
await requestLocationPermission();
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Region Monitoring')),
body: Center(
child: Column(children: [
FilledButton(
onPressed: () async => await LocationHelper().setRegions(),
child: const Text('Set Region')),
FilledButton(
onPressed: () async => await LocationHelper().start(),
child: const Text('Start Monitor')),
FilledButton(
onPressed: () async => await LocationHelper().stop(),
child: const Text('Stop Monitor'))
]))));
}
}
Код: Выделить всё
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:geolocator/geolocator.dart';
import 'package:location/location.dart' as location;
import 'package:permission_handler/permission_handler.dart' as permission;
class LocationHelper {
static final LocationHelper _instance = LocationHelper._internal();
LocationHelper._internal();
factory LocationHelper() => _instance;
final MethodChannel channel = const MethodChannel('location');
final EventChannel eventChannel = const EventChannel('location_stream');
Future start() async {
print('regrion monitoring: start');
await channel.invokeMethod('startMonitoring');
eventChannel.receiveBroadcastStream().listen((event) {
Map result = Map.from(event as Map);
print('receiveBroadcastStream');
print('regrion monitoring: identifier: ${result['identifier']}');
print('regrion monitoring: type: ${result['type']}');
});
}
Future stop() async {
print('regrion monitoring: stop');
await channel.invokeMethod('stopMonitoring');
}
Future setRegions() async {
Map regions = {
'location1': {
'latitude': 3.1067979,
'longitude': 101.4466574,
'radius': 60,
'description': 'Lotus'
},
'location2': {
'latitude': 3.1072308,
'longitude': 101.4387836,
'radius': 60,
'description': 'NSK'
};
print('regrion monitoring: setRegions');
await channel.invokeMethod('setRegions', regions);
}
}
Future requestLocationService() async {
if (!await Geolocator.isLocationServiceEnabled()) {
if (Platform.isAndroid) {
await location.Location().requestService();
if (!await location.Location().serviceEnabled()) {
return false;
}
} else if (Platform.isIOS || Platform.isMacOS) {
await Geolocator.openLocationSettings();
}
}
return true;
}
Future requestLocationPermission() async {
if (await permission.Permission.locationWhenInUse.isDenied) {
await permission.Permission.locationWhenInUse.request();
}
if (await permission.Permission.locationWhenInUse.isGranted &&
!await permission.Permission.locationAlways.isGranted) {
if (Platform.isIOS || Platform.isMacOS) {
await permission.Permission.locationAlways.request();
}
if (await permission.Permission.locationAlways.isDenied) {
return false;
}
}
// if location permission is permanently denied
if (await permission.Permission.locationWhenInUse.isPermanentlyDenied) {
await permission.openAppSettings();
}
return true;
}
Код: Выделить всё
Location Always and When In Use
Я также пробовал вызвать startMonitoring в applicationWillTerminateно это все равно не работает. Кто-нибудь может мне помочь?
Подробнее здесь: https://stackoverflow.com/questions/785 ... ed-flutter