Skip to content

Commit

Permalink
Merge pull request #26 from icapps/bugfix/crash-ios-flutter-engine-re…
Browse files Browse the repository at this point in the history
…write-3

Bugfix/crash ios flutter engine rewrite
  • Loading branch information
vanlooverenkoen authored Feb 19, 2021
2 parents 03f717d + e4d8c9f commit d887c75
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 32 deletions.
5 changes: 5 additions & 0 deletions ios/Classes/CustomLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
4 changes: 4 additions & 0 deletions ios/Classes/LocationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
116 changes: 84 additions & 32 deletions ios/Classes/SwiftBackgroundLocationTrackerPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand All @@ -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 {
Expand All @@ -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)
}
}
}
Expand Down

0 comments on commit d887c75

Please sign in to comment.