@@ -19,40 +19,124 @@ internal object FlutterBackgroundManager {
1919 private const val BACKGROUND_CHANNEL_NAME = " com.icapps.background_location_tracker/background_channel"
2020
2121 private val flutterLoader = FlutterLoader ()
22+ private var backgroundChannel: MethodChannel ? = null
23+ private var isInitialized = false
24+ private var pendingLocation: Location ? = null
25+ private var isSettingUp = false
2226
2327 private fun getInitializedFlutterEngine (ctx : Context ): FlutterEngine {
24- Logger .debug(" BackgroundManager" , " Creating new engine" )
25-
28+ Logger .debug(" BackgroundManager" , " Getting Flutter engine" )
2629 return BackgroundLocationTrackerPlugin .getFlutterEngine(ctx)
2730 }
2831
2932 fun sendLocation (ctx : Context , location : Location ) {
3033 Logger .debug(" BackgroundManager" , " Location: ${location.latitude} : ${location.longitude} " )
31- val engine = getInitializedFlutterEngine(ctx)
34+
35+ if (isInitialized) {
36+ // Engine is already initialized, send location immediately
37+ sendLocationToChannel(ctx, location)
38+ } else {
39+ // Store the location and initialize if needed
40+ pendingLocation = location
41+ setupBackgroundChannelIfNeeded(ctx)
42+ }
43+ }
3244
33- val backgroundChannel = MethodChannel (engine.dartExecutor, BACKGROUND_CHANNEL_NAME )
34- backgroundChannel.setMethodCallHandler { call, result ->
45+ private fun setupBackgroundChannelIfNeeded (ctx : Context ) {
46+ if (backgroundChannel != null || isSettingUp) {
47+ Logger .debug(" BackgroundManager" , " Setup already in progress or completed" )
48+ return // Already setup or in progress
49+ }
50+
51+ isSettingUp = true
52+ Logger .debug(" BackgroundManager" , " Setting up background channel and dart executor" )
53+ val engine = getInitializedFlutterEngine(ctx)
54+
55+ // Check if the DartExecutor is already running to prevent the error
56+ if (engine.dartExecutor.isExecutingDart) {
57+ Logger .debug(" BackgroundManager" , " DartExecutor is already running, reusing existing executor" )
58+ backgroundChannel = MethodChannel (engine.dartExecutor, BACKGROUND_CHANNEL_NAME )
59+ backgroundChannel?.setMethodCallHandler { call, result ->
60+ when (call.method) {
61+ " initialized" -> {
62+ Logger .debug(" BackgroundManager" , " Dart background isolate already initialized" )
63+ isInitialized = true
64+ isSettingUp = false
65+ result.success(true )
66+
67+ // Send any pending location
68+ pendingLocation?.let { location ->
69+ Logger .debug(" BackgroundManager" , " Sending pending location after reuse" )
70+ sendLocationToChannel(ctx, location)
71+ pendingLocation = null
72+ }
73+ }
74+ else -> {
75+ result.notImplemented()
76+ }
77+ }
78+ }
79+
80+ // Mark as initialized since the executor is already running
81+ isInitialized = true
82+ isSettingUp = false
83+
84+ // Send any pending location immediately if we have one
85+ pendingLocation?.let { location ->
86+ Logger .debug(" BackgroundManager" , " Sending pending location immediately (executor already running)" )
87+ sendLocationToChannel(ctx, location)
88+ pendingLocation = null
89+ }
90+
91+ return
92+ }
93+
94+ backgroundChannel = MethodChannel (engine.dartExecutor, BACKGROUND_CHANNEL_NAME )
95+ backgroundChannel?.setMethodCallHandler { call, result ->
3596 when (call.method) {
36- " initialized" -> handleInitialized(call, result, ctx, backgroundChannel, location, engine)
97+ " initialized" -> {
98+ Logger .debug(" BackgroundManager" , " Dart background isolate initialized" )
99+ isInitialized = true
100+ isSettingUp = false
101+ result.success(true )
102+
103+ // Send any pending location
104+ pendingLocation?.let { location ->
105+ Logger .debug(" BackgroundManager" , " Sending pending location after initialization" )
106+ sendLocationToChannel(ctx, location)
107+ pendingLocation = null
108+ }
109+ }
37110 else -> {
38111 result.notImplemented()
39- engine.destroy()
40112 }
41113 }
42114 }
43115
44116 if (! flutterLoader.initialized()) {
117+ Logger .debug(" BackgroundManager" , " Initializing FlutterLoader" )
45118 flutterLoader.startInitialization(ctx)
46119 }
120+
47121 flutterLoader.ensureInitializationCompleteAsync(ctx, null , Handler (Looper .getMainLooper())) {
122+ Logger .debug(" BackgroundManager" , " FlutterLoader initialization complete, executing Dart callback" )
48123 val callbackHandle = SharedPrefsUtil .getCallbackHandle(ctx)
49124 val callbackInfo = FlutterCallbackInformation .lookupCallbackInformation(callbackHandle)
50125 val dartBundlePath = flutterLoader.findAppBundlePath()
51- engine.dartExecutor.executeDartCallback(DartExecutor .DartCallback (ctx.assets, dartBundlePath, callbackInfo))
126+
127+ try {
128+ engine.dartExecutor.executeDartCallback(DartExecutor .DartCallback (ctx.assets, dartBundlePath, callbackInfo))
129+ } catch (e: Exception ) {
130+ Logger .debug(" BackgroundManager" , " Error executing Dart callback: ${e.message} " )
131+ isSettingUp = false
132+ }
52133 }
53134 }
54135
55- private fun handleInitialized (call : MethodCall , result : MethodChannel .Result , ctx : Context , channel : MethodChannel , location : Location , engine : FlutterEngine ) {
136+ private fun sendLocationToChannel (ctx : Context , location : Location ) {
137+ val channel = backgroundChannel ? : return
138+ Logger .debug(" BackgroundManager" , " Sending location to initialized channel" )
139+
56140 val data = mutableMapOf<String , Any >()
57141 data[" lat" ] = location.latitude
58142 data[" lon" ] = location.longitude
@@ -73,19 +157,37 @@ internal object FlutterBackgroundManager {
73157
74158 channel.invokeMethod(" onLocationUpdate" , data, object : MethodChannel .Result {
75159 override fun success (result : Any? ) {
76- Logger .debug(" BackgroundManager" , " Got success, destroy engine!" )
77- engine.destroy()
160+ Logger .debug(" BackgroundManager" , " Successfully sent location update" )
78161 }
79162
80163 override fun error (errorCode : String , errorMessage : String? , errorDetails : Any? ) {
81- Logger .debug(" BackgroundManager" , " Got error, destroy engine! $errorCode - $errorMessage : $errorDetails " )
82- engine.destroy()
164+ Logger .debug(" BackgroundManager" , " Error sending location update: $errorCode - $errorMessage : $errorDetails " )
83165 }
84166
85167 override fun notImplemented () {
86- Logger .debug(" BackgroundManager" , " Got not implemented, destroy engine!" )
87- engine.destroy()
168+ Logger .debug(" BackgroundManager" , " Method not implemented for location update" )
88169 }
89170 })
90171 }
91- }
172+
173+ fun cleanup () {
174+ Logger .debug(" BackgroundManager" , " Cleaning up background resources" )
175+ isInitialized = false
176+ isSettingUp = false
177+ backgroundChannel?.setMethodCallHandler(null )
178+ backgroundChannel = null
179+ pendingLocation = null
180+
181+ // Instead of destroying the engine completely, just mark it as not initialized
182+ // This allows for reuse without the "DartExecutor already running" error
183+ Logger .debug(" BackgroundManager" , " Background channel cleaned up, ready for reuse" )
184+ }
185+
186+ fun forceCleanup () {
187+ Logger .debug(" BackgroundManager" , " Force cleaning up all background resources" )
188+ cleanup()
189+
190+ // Clean up the Flutter engine completely to prevent DartExecutor reuse issues
191+ BackgroundLocationTrackerPlugin .cleanupFlutterEngine()
192+ }
193+ }
0 commit comments