diff --git a/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt b/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt index 496fdc44..8ddc1991 100644 --- a/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt +++ b/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt @@ -24,7 +24,7 @@ import rekab.app.background_locator.pluggables.InitPluggable class BackgroundLocatorPlugin : MethodCallHandler, FlutterPlugin, PluginRegistry.NewIntentListener, ActivityAware { - private var context: Context? = null + internal var context: Context? = null private var activity: Activity? = null companion object { @@ -32,7 +32,12 @@ class BackgroundLocatorPlugin private var channel: MethodChannel? = null @JvmStatic - private fun sendResultWithDelay(context: Context, result: Result?, value: Boolean, delay: Long) { + private fun sendResultWithDelay( + context: Context, + result: Result?, + value: Boolean, + delay: Long + ) { context.mainLooper.let { Handler(it).postDelayed({ result?.success(value) @@ -42,9 +47,11 @@ class BackgroundLocatorPlugin @SuppressLint("MissingPermission") @JvmStatic - private fun registerLocator(context: Context, - args: Map, - result: Result?) { + private fun registerLocator( + context: Context, + args: Map, + result: Result? + ) { if (IsolateHolderService.isServiceRunning) { // The service is running already Log.d("BackgroundLocatorPlugin", "Locator service is already running") @@ -52,14 +59,20 @@ class BackgroundLocatorPlugin return } - Log.d("BackgroundLocatorPlugin", - "start locator with ${PreferencesManager.getLocationClient(context)} client") + Log.d( + "BackgroundLocatorPlugin", + "start locator with ${PreferencesManager.getLocationClient(context)} client" + ) val callbackHandle = args[Keys.ARG_CALLBACK] as Long PreferencesManager.setCallbackHandle(context, Keys.CALLBACK_HANDLE_KEY, callbackHandle) val notificationCallback = args[Keys.ARG_NOTIFICATION_CALLBACK] as? Long - PreferencesManager.setCallbackHandle(context, Keys.NOTIFICATION_CALLBACK_HANDLE_KEY, notificationCallback) + PreferencesManager.setCallbackHandle( + context, + Keys.NOTIFICATION_CALLBACK_HANDLE_KEY, + notificationCallback + ) // Call InitPluggable with initCallbackHandle (args[Keys.ARG_INIT_CALLBACK] as? Long)?.let { initCallbackHandle -> @@ -81,8 +94,9 @@ class BackgroundLocatorPlugin val settings = args[Keys.ARG_SETTINGS] as Map<*, *> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && - context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_DENIED) { + context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_DENIED + ) { val msg = "'registerLocator' requires the ACCESS_FINE_LOCATION permission." result?.error(msg, null, null) @@ -97,34 +111,60 @@ class BackgroundLocatorPlugin } @JvmStatic - private fun startIsolateService(context: Context, settings: Map<*, *>) { + internal fun startIsolateService(context: Context, settings: Map<*, *>) { + Log.e("BackgroundLocatorPlugin", "startIsolateService") val intent = Intent(context, IsolateHolderService::class.java) intent.action = IsolateHolderService.ACTION_START - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME] as String) - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] as String) - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] as String) - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] as String) - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON] as String) - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR, - settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR] as Long) - intent.putExtra(Keys.SETTINGS_INTERVAL, settings[Keys.SETTINGS_INTERVAL] as Int) - intent.putExtra(Keys.SETTINGS_ACCURACY, settings[Keys.SETTINGS_ACCURACY] as Int) - intent.putExtra(Keys.SETTINGS_DISTANCE_FILTER, settings[Keys.SETTINGS_DISTANCE_FILTER] as Double) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME] as? String + ) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] as? String + ) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_MSG, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] as? String + ) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] as? String + ) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_ICON, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON] as? String + ) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR, + settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR] as? Long + ) + intent.putExtra(Keys.SETTINGS_INTERVAL, settings[Keys.SETTINGS_INTERVAL] as? Int) + intent.putExtra(Keys.SETTINGS_ACCURACY, settings[Keys.SETTINGS_ACCURACY] as? Int) + intent.putExtra( + Keys.SETTINGS_DISTANCE_FILTER, + settings[Keys.SETTINGS_DISTANCE_FILTER] as? Double + ) if (settings.containsKey(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME)) { - intent.putExtra(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME, - settings[Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME] as Int) + intent.putExtra( + Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME, + settings[Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME] as? Int + ) } - if (PreferencesManager.getCallbackHandle(context, Keys.INIT_CALLBACK_HANDLE_KEY) != null) { + if (PreferencesManager.getCallbackHandle( + context, + Keys.INIT_CALLBACK_HANDLE_KEY + ) != null + ) { intent.putExtra(Keys.SETTINGS_INIT_PLUGGABLE, true) } - if (PreferencesManager.getCallbackHandle(context, Keys.DISPOSE_CALLBACK_HANDLE_KEY) != null) { + if (PreferencesManager.getCallbackHandle( + context, + Keys.DISPOSE_CALLBACK_HANDLE_KEY + ) != null + ) { intent.putExtra(Keys.SETTINGS_DISPOSABLE_PLUGGABLE, true) } @@ -139,7 +179,7 @@ class BackgroundLocatorPlugin } @JvmStatic - private fun initializeService(context: Context, args: Map) { + internal fun initializeService(context: Context, args: Map) { val callbackHandle: Long = args[Keys.ARG_CALLBACK_DISPATCHER] as Long setCallbackDispatcherHandle(context, callbackHandle) } @@ -171,16 +211,22 @@ class BackgroundLocatorPlugin val intent = Intent(context, IsolateHolderService::class.java) intent.action = IsolateHolderService.ACTION_UPDATE_NOTIFICATION if (args.containsKey(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE)) { - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE, - args[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] as String) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE, + args[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] as String + ) } if (args.containsKey(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG)) { - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG, - args[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] as String) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_MSG, + args[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] as String + ) } if (args.containsKey(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG)) { - intent.putExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG, - args[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] as String) + intent.putExtra( + Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG, + args[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] as String + ) } ContextCompat.startForegroundService(context, intent) @@ -189,9 +235,9 @@ class BackgroundLocatorPlugin @JvmStatic private fun setCallbackDispatcherHandle(context: Context, handle: Long) { context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) - .edit() - .putLong(Keys.CALLBACK_DISPATCHER_HANDLE_KEY, handle) - .apply() + .edit() + .putLong(Keys.CALLBACK_DISPATCHER_HANDLE_KEY, handle) + .apply() } @JvmStatic @@ -202,7 +248,13 @@ class BackgroundLocatorPlugin plugin.context = context initializeService(context, settings) - startIsolateService(context, settings) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED + ) { + startIsolateService(context, settings) + } } } @@ -223,9 +275,11 @@ class BackgroundLocatorPlugin // save setting to use it when device reboots PreferencesManager.saveSettings(context!!, args) - registerLocator(context!!, - args, - result) + registerLocator( + context!!, + args, + result + ) } Keys.METHOD_PLUGIN_UN_REGISTER_LOCATION_UPDATE -> { unRegisterPlugin(context!!, result) @@ -266,16 +320,27 @@ class BackgroundLocatorPlugin return false } - val notificationCallback = PreferencesManager.getCallbackHandle(activity!!, Keys.NOTIFICATION_CALLBACK_HANDLE_KEY) - if (notificationCallback != null && IsolateHolderService.backgroundEngine != null) { - val backgroundChannel = - MethodChannel(IsolateHolderService.backgroundEngine?.dartExecutor?.binaryMessenger, Keys.BACKGROUND_CHANNEL_ID) - activity?.mainLooper?.let { - Handler(it) + IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger -> + val notificationCallback = + PreferencesManager.getCallbackHandle( + activity!!, + Keys.NOTIFICATION_CALLBACK_HANDLE_KEY + ) + if (notificationCallback != null && IsolateHolderService.backgroundEngine != null) { + val backgroundChannel = + MethodChannel( + binaryMessenger, + Keys.BACKGROUND_CHANNEL_ID + ) + activity?.mainLooper?.let { + Handler(it) .post { - backgroundChannel.invokeMethod(Keys.BCM_NOTIFICATION_CLICK, - hashMapOf(Keys.ARG_NOTIFICATION_CALLBACK to notificationCallback)) + backgroundChannel.invokeMethod( + Keys.BCM_NOTIFICATION_CLICK, + hashMapOf(Keys.ARG_NOTIFICATION_CALLBACK to notificationCallback) + ) } + } } } diff --git a/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderExtension.kt b/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderExtension.kt index 9c0f65d0..994c67f7 100644 --- a/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderExtension.kt +++ b/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderExtension.kt @@ -1,14 +1,20 @@ package rekab.app.background_locator +import android.Manifest import android.content.Context import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log import com.google.android.gms.location.LocationRequest import io.flutter.FlutterInjector import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.dart.DartExecutor import io.flutter.plugin.common.MethodChannel import io.flutter.view.FlutterCallbackInformation +import rekab.app.background_locator.IsolateHolderService.Companion.isServiceInitialized import rekab.app.background_locator.provider.LocationRequestOptions +import java.lang.RuntimeException import java.util.concurrent.atomic.AtomicBoolean internal fun IsolateHolderService.startLocatorService(context: Context) { @@ -18,30 +24,56 @@ internal fun IsolateHolderService.startLocatorService(context: Context) { synchronized(serviceStarted) { this.context = context if (IsolateHolderService.backgroundEngine == null) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED + ) { + val callbackHandle = context.getSharedPreferences( + Keys.SHARED_PREFERENCES_KEY, + Context.MODE_PRIVATE + ) + .getLong(Keys.CALLBACK_DISPATCHER_HANDLE_KEY, 0) + val callbackInfo = + FlutterCallbackInformation.lookupCallbackInformation(callbackHandle) - val callbackHandle = context.getSharedPreferences( - Keys.SHARED_PREFERENCES_KEY, - Context.MODE_PRIVATE) - .getLong(Keys.CALLBACK_DISPATCHER_HANDLE_KEY, 0) - val callbackInfo = FlutterCallbackInformation.lookupCallbackInformation(callbackHandle) + // We need flutter engine to handle callback, so if it is not available we have to create a + // Flutter engine without any view + Log.e("IsolateHolderService", "startLocatorService: Start Flutter Enginer") + IsolateHolderService.backgroundEngine = FlutterEngine(context) - // We need flutter engine to handle callback, so if it is not available we have to create a - // Flutter engine without any view - IsolateHolderService.backgroundEngine = FlutterEngine(context) + val args = DartExecutor.DartCallback( + context.assets, + FlutterInjector.instance().flutterLoader().findAppBundlePath(), + callbackInfo + ) + IsolateHolderService.backgroundEngine?.dartExecutor?.executeDartCallback(args) + isServiceInitialized = true + Log.e("IsolateHolderExtension", "service initialized") + } + } catch (e: UnsatisfiedLinkError) { + e.printStackTrace() + } + } + } - val args = DartExecutor.DartCallback( - context.assets, - FlutterInjector.instance().flutterLoader().findAppBundlePath(), - callbackInfo + IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger -> + backgroundChannel = + MethodChannel( + binaryMessenger, + Keys.BACKGROUND_CHANNEL_ID ) - IsolateHolderService.backgroundEngine?.dartExecutor?.executeDartCallback(args) + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED + ) { + backgroundChannel.setMethodCallHandler(this) + } + } catch (e: RuntimeException) { + e.printStackTrace() } } - - backgroundChannel = - MethodChannel(IsolateHolderService.backgroundEngine?.dartExecutor?.binaryMessenger, - Keys.BACKGROUND_CHANNEL_ID) - backgroundChannel.setMethodCallHandler(this) } fun getLocationRequest(intent: Intent): LocationRequestOptions { diff --git a/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderService.kt b/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderService.kt index 040e7fc5..7450ed95 100644 --- a/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderService.kt +++ b/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderService.kt @@ -11,6 +11,7 @@ import android.util.Log import androidx.core.app.NotificationCompat import io.flutter.FlutterInjector import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import rekab.app.background_locator.pluggables.DisposePluggable @@ -41,18 +42,33 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList @JvmStatic var isServiceRunning = false + + @JvmStatic + var isServiceInitialized = false + + fun getBinaryMessenger(context: Context?): BinaryMessenger? { + val messenger = backgroundEngine?.dartExecutor?.binaryMessenger + return messenger + ?: if (context != null) { + backgroundEngine = FlutterEngine(context) + backgroundEngine?.dartExecutor?.binaryMessenger + }else{ + messenger + } + } } private var notificationChannelName = "Flutter Locator Plugin" private var notificationTitle = "Start Location Tracking" private var notificationMsg = "Track location in background" - private var notificationBigMsg = "Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running." + private var notificationBigMsg = + "Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running." private var notificationIconColor = 0 private var icon = 0 private var wakeLockTime = 60 * 60 * 1000L // 1 hour default wake lock time private var locatorClient: BLLocationProvider? = null internal lateinit var backgroundChannel: MethodChannel - internal lateinit var context: Context + internal var context: Context? = null private var pluggables: ArrayList = ArrayList() override fun onBind(intent: Intent?): IBinder? { @@ -78,38 +94,44 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList startForeground(notificationId, notification) pluggables.forEach { - it.onServiceStart(context) + context?.let { it1 -> it.onServiceStart(it1) } } } private fun getNotification(): Notification { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Notification channel is available in Android O and up - val channel = NotificationChannel(Keys.CHANNEL_ID, notificationChannelName, - NotificationManager.IMPORTANCE_LOW) + val channel = NotificationChannel( + Keys.CHANNEL_ID, notificationChannelName, + NotificationManager.IMPORTANCE_LOW + ) (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager) - .createNotificationChannel(channel) + .createNotificationChannel(channel) } val intent = Intent(this, getMainActivityClass(this)) intent.action = Keys.NOTIFICATION_ACTION - val pendingIntent: PendingIntent = PendingIntent.getActivity(this, - 1, intent, PendingIntent.FLAG_UPDATE_CURRENT) + val pendingIntent: PendingIntent = PendingIntent.getActivity( + this, + 1, intent, PendingIntent.FLAG_UPDATE_CURRENT + ) return NotificationCompat.Builder(this, Keys.CHANNEL_ID) - .setContentTitle(notificationTitle) - .setContentText(notificationMsg) - .setStyle(NotificationCompat.BigTextStyle() - .bigText(notificationBigMsg)) - .setSmallIcon(icon) - .setColor(notificationIconColor) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setContentIntent(pendingIntent) - .setOnlyAlertOnce(true) // so when data is updated don't make sound and alert in android 8.0+ - .setOngoing(true) - .build() + .setContentTitle(notificationTitle) + .setContentText(notificationMsg) + .setStyle( + NotificationCompat.BigTextStyle() + .bigText(notificationBigMsg) + ) + .setSmallIcon(icon) + .setColor(notificationIconColor) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setContentIntent(pendingIntent) + .setOnlyAlertOnce(true) // so when data is updated don't make sound and alert in android 8.0+ + .setOngoing(true) + .build() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -139,24 +161,29 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList } private fun startHolderService(intent: Intent) { - notificationChannelName = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME).toString() - notificationTitle = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE).toString() + Log.e("IsolateHolderService", "startHolderService") + notificationChannelName = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME).toString() + notificationTitle = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE).toString() notificationMsg = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG).toString() - notificationBigMsg = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG).toString() + notificationBigMsg = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG).toString() val iconNameDefault = "ic_launcher" var iconName = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON) if (iconName == null || iconName.isEmpty()) { iconName = iconNameDefault } icon = resources.getIdentifier(iconName, "mipmap", packageName) - notificationIconColor = intent.getLongExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR, 0).toInt() + notificationIconColor = + intent.getLongExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR, 0).toInt() wakeLockTime = intent.getIntExtra(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME, 60) * 60 * 1000L - locatorClient = getLocationClient(context) + locatorClient = context?.let { getLocationClient(it) } locatorClient?.requestLocationUpdates(getLocationRequest(intent)) // Fill pluggable list - if( intent.hasExtra(Keys.SETTINGS_INIT_PLUGGABLE)) { + if (intent.hasExtra(Keys.SETTINGS_INIT_PLUGGABLE)) { pluggables.add(InitPluggable()) } @@ -168,6 +195,7 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList } private fun shutdownHolderService() { + Log.e("IsolateHolderService", "shutdownHolderService") (getSystemService(Context.POWER_SERVICE) as PowerManager).run { newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG).apply { if (isHeld) { @@ -181,25 +209,30 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList stopSelf() pluggables.forEach { - it.onServiceDispose(context) + context?.let { it1 -> it.onServiceDispose(it1) } } } private fun updateNotification(intent: Intent) { + Log.e("IsolateHolderService", "updateNotification") if (intent.hasExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE)) { - notificationTitle = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE).toString() + notificationTitle = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE).toString() } if (intent.hasExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG)) { - notificationMsg = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG).toString() + notificationMsg = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG).toString() } if (intent.hasExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG)) { - notificationBigMsg = intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG).toString() + notificationBigMsg = + intent.getStringExtra(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG).toString() } val notification = getNotification() - val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val notificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(notificationId, notification) } @@ -217,14 +250,18 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList } override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - when (call.method) { - Keys.METHOD_SERVICE_INITIALIZED -> { - isServiceRunning = true + try { + when (call.method) { + Keys.METHOD_SERVICE_INITIALIZED -> { + isServiceRunning = true + } + else -> result.notImplemented() } - else -> result.notImplemented() - } - result.success(null) + result.success(null) + } catch (e: Exception) { + + } } override fun onDestroy() { @@ -241,20 +278,36 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList } override fun onLocationUpdated(location: HashMap?) { - FlutterInjector.instance().flutterLoader().ensureInitializationComplete(context, null) - - //https://github.com/flutter/plugins/pull/1641 - //https://github.com/flutter/flutter/issues/36059 - //https://github.com/flutter/plugins/pull/1641/commits/4358fbba3327f1fa75bc40df503ca5341fdbb77d - // new version of flutter can not invoke method from background thread - if (location != null) { - val callback = PreferencesManager.getCallbackHandle(context, Keys.CALLBACK_HANDLE_KEY) as Long + try { + context?.let { + FlutterInjector.instance().flutterLoader().ensureInitializationComplete( + it, null + ) + } - val result: HashMap = - hashMapOf(Keys.ARG_CALLBACK to callback, - Keys.ARG_LOCATION to location) + //https://github.com/flutter/plugins/pull/1641 + //https://github.com/flutter/flutter/issues/36059 + //https://github.com/flutter/plugins/pull/1641/commits/4358fbba3327f1fa75bc40df503ca5341fdbb77d + // new version of flutter can not invoke method from background thread + if (location != null) { + val callback = + context?.let { + PreferencesManager.getCallbackHandle( + it, + Keys.CALLBACK_HANDLE_KEY + ) + } as Long + + val result: HashMap = + hashMapOf( + Keys.ARG_CALLBACK to callback, + Keys.ARG_LOCATION to location + ) + + sendLocationEvent(result) + } + } catch (e: Exception) { - sendLocationEvent(result) } } @@ -265,13 +318,20 @@ class IsolateHolderService : MethodChannel.MethodCallHandler, LocationUpdateList // new version of flutter can not invoke method from background thread if (backgroundEngine != null) { - val backgroundChannel = - MethodChannel(backgroundEngine?.dartExecutor?.binaryMessenger, Keys.BACKGROUND_CHANNEL_ID) - Handler(context.mainLooper) + context?.let { + val backgroundChannel = + MethodChannel( + getBinaryMessenger(it), + Keys.BACKGROUND_CHANNEL_ID + ) + } + context?.let { + Handler(it.mainLooper) .post { Log.d("plugin", "sendLocationEvent $result") backgroundChannel.invokeMethod(Keys.BCM_SEND_LOCATION, result) } + } } } diff --git a/android/src/main/kotlin/rekab/app/background_locator/pluggables/DisposePluggable.kt b/android/src/main/kotlin/rekab/app/background_locator/pluggables/DisposePluggable.kt index 69358109..8f137eb3 100644 --- a/android/src/main/kotlin/rekab/app/background_locator/pluggables/DisposePluggable.kt +++ b/android/src/main/kotlin/rekab/app/background_locator/pluggables/DisposePluggable.kt @@ -9,18 +9,31 @@ import rekab.app.background_locator.PreferencesManager class DisposePluggable : Pluggable { override fun setCallback(context: Context, callbackHandle: Long) { - PreferencesManager.setCallbackHandle(context, Keys.DISPOSE_CALLBACK_HANDLE_KEY, callbackHandle) + PreferencesManager.setCallbackHandle( + context, + Keys.DISPOSE_CALLBACK_HANDLE_KEY, + callbackHandle + ) } override fun onServiceDispose(context: Context) { - (PreferencesManager.getCallbackHandle(context, Keys.DISPOSE_CALLBACK_HANDLE_KEY))?.let { disposeCallback -> - val backgroundChannel = MethodChannel(IsolateHolderService.backgroundEngine?.dartExecutor?.binaryMessenger, - Keys.BACKGROUND_CHANNEL_ID) - Handler(context.mainLooper) + (PreferencesManager.getCallbackHandle( + context, + Keys.DISPOSE_CALLBACK_HANDLE_KEY + ))?.let { disposeCallback -> + IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger -> + val backgroundChannel = MethodChannel( + binaryMessenger, + Keys.BACKGROUND_CHANNEL_ID + ) + Handler(context.mainLooper) .post { - backgroundChannel.invokeMethod(Keys.BCM_DISPOSE, - hashMapOf(Keys.ARG_DISPOSE_CALLBACK to disposeCallback)) + backgroundChannel.invokeMethod( + Keys.BCM_DISPOSE, + hashMapOf(Keys.ARG_DISPOSE_CALLBACK to disposeCallback) + ) } + } } } } \ No newline at end of file diff --git a/android/src/main/kotlin/rekab/app/background_locator/pluggables/InitPluggable.kt b/android/src/main/kotlin/rekab/app/background_locator/pluggables/InitPluggable.kt index a33a7ecf..93c8b743 100644 --- a/android/src/main/kotlin/rekab/app/background_locator/pluggables/InitPluggable.kt +++ b/android/src/main/kotlin/rekab/app/background_locator/pluggables/InitPluggable.kt @@ -2,10 +2,15 @@ package rekab.app.background_locator.pluggables import android.content.Context import android.os.Handler +import android.util.Log +import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel +import rekab.app.background_locator.BackgroundLocatorPlugin import rekab.app.background_locator.IsolateHolderService +import rekab.app.background_locator.IsolateHolderService.Companion.isServiceInitialized import rekab.app.background_locator.Keys import rekab.app.background_locator.PreferencesManager +import java.lang.NullPointerException class InitPluggable : Pluggable { private var isInitCallbackCalled = false @@ -17,15 +22,28 @@ class InitPluggable : Pluggable { override fun onServiceStart(context: Context) { if (!isInitCallbackCalled) { - (PreferencesManager.getCallbackHandle(context, Keys.INIT_CALLBACK_HANDLE_KEY))?.let { initCallback -> - val initialDataMap = PreferencesManager.getDataCallback(context, Keys.INIT_DATA_CALLBACK_KEY) - val backgroundChannel = MethodChannel(IsolateHolderService.backgroundEngine?.dartExecutor?.binaryMessenger, - Keys.BACKGROUND_CHANNEL_ID) - Handler(context.mainLooper) + (PreferencesManager.getCallbackHandle( + context, + Keys.INIT_CALLBACK_HANDLE_KEY + ))?.let { initCallback -> + IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger -> + val initialDataMap = + PreferencesManager.getDataCallback(context, Keys.INIT_DATA_CALLBACK_KEY) + val backgroundChannel = MethodChannel( + binaryMessenger, + Keys.BACKGROUND_CHANNEL_ID + ) + Handler(context.mainLooper) .post { - backgroundChannel.invokeMethod(Keys.BCM_INIT, - hashMapOf(Keys.ARG_INIT_CALLBACK to initCallback, Keys.ARG_INIT_DATA_CALLBACK to initialDataMap)) + backgroundChannel.invokeMethod( + Keys.BCM_INIT, + hashMapOf( + Keys.ARG_INIT_CALLBACK to initCallback, + Keys.ARG_INIT_DATA_CALLBACK to initialDataMap + ) + ) } + } } isInitCallbackCalled = true } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d6cedd6f..ad1e9d04 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -48,8 +48,6 @@ android { buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug } }