diff --git a/ios/Classes/CustomLogger.swift b/ios/Classes/CustomLogger.swift index 656c8a8..6671844 100644 --- a/ios/Classes/CustomLogger.swift +++ b/ios/Classes/CustomLogger.swift @@ -5,11 +5,16 @@ // Created by Dimmy Maenhout on 21/12/2020. // +import os import Foundation struct CustomLogger { static func log(message: String) { if SharedPrefsUtil.isLoggingEnabled() { + if #available(iOS 10.0, *) { + let app = OSLog(subsystem: "com.icapps.background_location_tracker", category: "background tracker") + os_log("🔥 background-location log: %{public}@", log: app, type: .error, message) + } print(message) } } diff --git a/ios/Classes/LocationManager.swift b/ios/Classes/LocationManager.swift index 5728242..273f826 100644 --- a/ios/Classes/LocationManager.swift +++ b/ios/Classes/LocationManager.swift @@ -14,6 +14,10 @@ class LocationManager { let manager = CLLocationManager() manager.activityType = .automotiveNavigation manager.desiredAccuracy = kCLLocationAccuracyBest + manager.pausesLocationUpdatesAutomatically = false + if #available(iOS 11, *) { + manager.showsBackgroundLocationIndicator = true + } if #available(iOS 9.0, *) { manager.allowsBackgroundLocationUpdates = true } diff --git a/ios/Classes/SwiftBackgroundLocationTrackerPlugin.swift b/ios/Classes/SwiftBackgroundLocationTrackerPlugin.swift index daef252..033ae0a 100644 --- a/ios/Classes/SwiftBackgroundLocationTrackerPlugin.swift +++ b/ios/Classes/SwiftBackgroundLocationTrackerPlugin.swift @@ -6,9 +6,16 @@ public class SwiftBackgroundLocationTrackerPlugin: FlutterPluginAppLifeCycleDele static let identifier = "com.icapps.background_location_tracker" - private let flutterThreadLabelPrefix = "\(identifier).BackgroundLocationTracker" + private static let flutterThreadLabelPrefix = "\(identifier).BackgroundLocationTracker" private static var foregroundChannel: ForegroundChannel? = nil + private static var backgroundMethodChannel: FlutterMethodChannel? = nil + + private static var flutterEngine: FlutterEngine? = nil + private static var hasRegisteredPlugins = false + private static var initializedBackgroundCallbacks = false + private static var initializedBackgroundCallbacksStarted = false + private static var locationData: [String: Any]? = nil private static var flutterPluginRegistrantCallback: FlutterPluginRegistrantCallback? @@ -35,6 +42,62 @@ extension SwiftBackgroundLocationTrackerPlugin: FlutterPlugin { locationManager.delegate = self SwiftBackgroundLocationTrackerPlugin.foregroundChannel?.handle(call, result: result) } + + public static func getFlutterEngine()-> FlutterEngine? { + if flutterEngine == nil { + let flutterEngine = FlutterEngine(name: flutterThreadLabelPrefix, project: nil, allowHeadlessExecution: true) + + guard let callbackHandle = SharedPrefsUtil.getCallbackHandle(), + let flutterCallbackInformation = FlutterCallbackCache.lookupCallbackInformation(callbackHandle) else { + CustomLogger.log(message: "No flutter callback cache ...") + return nil + } + let success = flutterEngine.run(withEntrypoint: flutterCallbackInformation.callbackName, libraryURI: flutterCallbackInformation.callbackLibraryPath) + + CustomLogger.log(message: "FlutterEngine.run returned `\(success)`") + if success { + SwiftBackgroundLocationTrackerPlugin.flutterPluginRegistrantCallback?(flutterEngine) + self.flutterEngine = flutterEngine + } else { + CustomLogger.log(message: "FlutterEngine.run returned `false` we will cleanup the flutterEngine") + flutterEngine.destroyContext() + } + } + return flutterEngine + } + + public static func initBackgroundMethodChannel(flutterEngine: FlutterEngine) { + if backgroundMethodChannel == nil { + let backgroundMethodChannel = FlutterMethodChannel(name: SwiftBackgroundLocationTrackerPlugin.BACKGROUND_CHANNEL_NAME, binaryMessenger: flutterEngine.binaryMessenger) + backgroundMethodChannel.setMethodCallHandler { (call, result) in + switch call.method { + case BackgroundMethods.initialized.rawValue: + initializedBackgroundCallbacks = true + if let data = SwiftBackgroundLocationTrackerPlugin.locationData { + CustomLogger.log(message: "Initialized with cached value, sending location update") + sendLocationupdate(locationData: data) + } else { + CustomLogger.log(message: "Initialized without cached value") + } + result(true) + default: + CustomLogger.log(message: "Not implemented method -> \(call.method)") + result(FlutterMethodNotImplemented) + } + } + self.backgroundMethodChannel = backgroundMethodChannel + } + } + + public static func sendLocationupdate(locationData: [String: Any]){ + guard let backgroundMethodChannel = SwiftBackgroundLocationTrackerPlugin.backgroundMethodChannel else { + CustomLogger.log(message: "No background channel available ...") + return + } + backgroundMethodChannel.invokeMethod(BackgroundMethods.onLocationUpdate.rawValue, arguments: locationData, result: { flutterResult in + CustomLogger.log(message: "Received result: \(flutterResult.debugDescription)") + }) + } } fileprivate enum BackgroundMethods: String { @@ -53,38 +116,27 @@ extension SwiftBackgroundLocationTrackerPlugin: CLLocationManagerDelegate { CustomLogger.log(message: "NEW LOCATION: \(location.coordinate.latitude): \(location.coordinate.longitude)") - guard let callbackHandle = SharedPrefsUtil.getCallbackHandle(), - let flutterCallbackInformation = FlutterCallbackCache.lookupCallbackInformation(callbackHandle) - else { return } - - var flutterEngine: FlutterEngine? = FlutterEngine(name: flutterThreadLabelPrefix, project: nil, allowHeadlessExecution: true) - flutterEngine!.run(withEntrypoint: flutterCallbackInformation.callbackName, libraryURI: flutterCallbackInformation.callbackLibraryPath) - SwiftBackgroundLocationTrackerPlugin.flutterPluginRegistrantCallback?(flutterEngine!) - - var backgroundMethodChannel: FlutterMethodChannel? = FlutterMethodChannel(name: SwiftBackgroundLocationTrackerPlugin.BACKGROUND_CHANNEL_NAME, binaryMessenger: flutterEngine!.binaryMessenger) - - - func cleanupFlutterResources() { - flutterEngine?.destroyContext() - backgroundMethodChannel = nil - flutterEngine = nil - } + let locationData: [String: Any] = [ + "lat": location.coordinate.latitude, + "lon": location.coordinate.longitude, + "logging_enabled": SharedPrefsUtil.isLoggingEnabled(), + ] - backgroundMethodChannel?.setMethodCallHandler { (call, result) in - switch call.method { - case BackgroundMethods.initialized.rawValue: - result(true) - let locationData :[String: Any] = [ - "lat": location.coordinate.latitude, - "lon": location.coordinate.longitude, - "logging_enabled": SharedPrefsUtil.isLoggingEnabled(), - ] - backgroundMethodChannel?.invokeMethod(BackgroundMethods.onLocationUpdate.rawValue, arguments: locationData, result: { flutterResult in - cleanupFlutterResources() - }) - default: - cleanupFlutterResources() - result(FlutterMethodNotImplemented) + if SwiftBackgroundLocationTrackerPlugin.initializedBackgroundCallbacks { + CustomLogger.log(message: "INITIALIZED, ready to send location updates") + SwiftBackgroundLocationTrackerPlugin.sendLocationupdate(locationData: locationData) + } else { + CustomLogger.log(message: "NOT YET INITIALIZED. Cache the location data") + SwiftBackgroundLocationTrackerPlugin.locationData = locationData + + if !SwiftBackgroundLocationTrackerPlugin.initializedBackgroundCallbacksStarted { + SwiftBackgroundLocationTrackerPlugin.initializedBackgroundCallbacksStarted = true + + guard let flutterEngine = SwiftBackgroundLocationTrackerPlugin.getFlutterEngine() else { + CustomLogger.log(message: "No Flutter engine available ...") + return + } + SwiftBackgroundLocationTrackerPlugin.initBackgroundMethodChannel(flutterEngine: flutterEngine) } } }