import CoreLocation import Flutter import UIKit public class LocationPlugin: NSObject, FlutterPlugin, CLLocationManagerDelegate { private let locationManager = CLLocationManager() private var pendingResult: FlutterResult? override init() { super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest } public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: "location_plugin", binaryMessenger: registrar.messenger()) let instance = LocationPlugin() registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getPlatformVersion": result("iOS " + UIDevice.current.systemVersion) case "getCurrentLocation": requestCurrentLocation(result: result) default: result(FlutterMethodNotImplemented) } } private func requestCurrentLocation(result: @escaping FlutterResult) { guard pendingResult == nil else { result(FlutterError(code: "LOCATION_IN_PROGRESS", message: "A previous location request is still running.", details: nil)) return } guard CLLocationManager.locationServicesEnabled() else { result(FlutterError(code: "LOCATION_DISABLED", message: "Location services are turned off.", details: nil)) return } pendingResult = result switch authorizationStatus() { case .authorizedAlways, .authorizedWhenInUse: locationManager.requestLocation() case .notDetermined: locationManager.requestWhenInUseAuthorization() case .restricted, .denied: finishWithError(code: "PERMISSION_DENIED", message: "Location permission denied.") @unknown default: finishWithError(code: "PERMISSION_UNKNOWN", message: "Unknown authorization status.") } } private func authorizationStatus() -> CLAuthorizationStatus { if #available(iOS 14.0, *) { return locationManager.authorizationStatus } return CLLocationManager.authorizationStatus() } private func finishWithLocation(_ location: CLLocation) { pendingResult?([ "latitude": location.coordinate.latitude, "longitude": location.coordinate.longitude, ]) pendingResult = nil } private func finishWithError(code: String, message: String) { pendingResult?(FlutterError(code: code, message: message, details: nil)) pendingResult = nil } public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let latest = locations.last else { finishWithError(code: "LOCATION_UNAVAILABLE", message: "Unable to obtain location.") return } finishWithLocation(latest) } public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { finishWithError(code: "LOCATION_ERROR", message: error.localizedDescription) } public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { handleAuthorizationChange(status: manager.authorizationStatus) } public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { handleAuthorizationChange(status: status) } private func handleAuthorizationChange(status: CLAuthorizationStatus) { guard pendingResult != nil else { return } switch status { case .authorizedAlways, .authorizedWhenInUse: locationManager.requestLocation() case .denied, .restricted: finishWithError(code: "PERMISSION_DENIED", message: "Location permission denied.") case .notDetermined: break @unknown default: finishWithError(code: "PERMISSION_UNKNOWN", message: "Unknown authorization status.") } } }