Dev-hwang / flutter_foreground_task

This plugin is used to implement a foreground service on the Android platform.
https://pub.dev/packages/flutter_foreground_task
MIT License
140 stars 105 forks source link

Kotlin: I can't get Activity information from Android's (native) side when calling my plugin code through your package's TaskHandler. #208

Closed BigYajuu closed 6 months ago

BigYajuu commented 6 months ago

Hello, thanks for reading this.

So I made a new Flutter plugin and made the TaskHandler to run this plugin. Everything seems fine until I want to get Activity from using the interface ActivityAware on Android's side.

My onStart method basically runs my Flutter plugin that streams Android's realtime information (even when the app is removed from the background). And the Plugin class on Android's side would have 1 methodChannel and 1 eventChannel to service this.

The said Android Plugin class looks like this. I removed most of the unrelated details for readability.:

class AppTimerServicePlugin: FlutterPlugin, ActivityAware, MethodCallHandler, EventChannel.StreamHandler {
    ...
    override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        context = flutterPluginBinding.applicationContext
        binaryMessenger = flutterPluginBinding.binaryMessenger
        handler = Handler(Looper.getMainLooper())
        eventChannel = EventChannel(binaryMessenger, eventChannelName)
        methodChannel = MethodChannel(binaryMessenger, methodChannelName)
        eventChannel.setStreamHandler(this)
        methodChannel.setMethodCallHandler(this)
        Log.d("APPWATCH", "Attached to Engine. Activity: " + activity.toString() + " " + hashCode())
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        if (call.method.equals("getPlatformVersion")) {
            result.success("Android " + Build.VERSION.RELEASE);
        } else if (call.method == "setAppStatusWatchlist") {
            val appWatchlist = call.argument<List<String>>("value")
            setAppWatchlist(appWatchlist!!)
        } else if (call.method == "setBlockingAppState") {
            if (call.argument<Boolean>("value") == true) {
                startBlockingApps()
            } else if (call.argument<Boolean>("value") == false) {
                stopBlockingApps()
            }
        }
    }

    // The followings are ActivityAware methods
    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        activity = binding.activity
        Log.d("APPWATCH", "Activity attached. Activity: " + activity.toString() + " " + hashCode())
    }

    override fun onDetachedFromActivityForConfigChanges() {
        Log.d("APPWATCH", "Activity detached otherwise")
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        Log.d("APPWATCH", "Activity reattached")
        onAttachedToActivity(binding)
    }

    override fun onDetachedFromActivity() {
        Log.d("APPWATCH", "Activity Detached")
    }
    ...
}

From what I know: These onAttach/detach/reattached functions are a part of ActivityAware interface, and the only chance for me to get the binding (which is critical of getting the Activity feature) is through onAttachedToActivity or onReattachedToActivityForConfigChanges.

I have added some log statements in some of the methods above to understand which methods are called at what time. Note that I am also trying to obtain the hashcodes. and found some really weird.

When I try to debug my Flutter program the Logcat goes like this:

Attached to Engine. Activity: null 102199110
Activity attached. Activity: <Activity Instance> 102199110
Attached to Engine. Activity: null 75215547

The hashcode changed when the engine was attached again. It seems that a different instance was created.

I was able to obtain the Activity instance for a second there, but because there seems to be a second instance running I could no longer use that.

Can you explain why the plugin felt the need to attach to the engine again on a completely different instance?

BigYajuu commented 6 months ago

I have fixed my issue. It seems for me there is no need to use Activity because you can just startActivity using context provided from onAttachedToEngine.

Closing this issue.