fluttercommunity / flutter_workmanager

A Flutter plugin which allows you to execute code in the background on Android and iOS.
825 stars 247 forks source link

How can I invoke work manager from native side? #540

Open RaySuhyunLee opened 4 months ago

RaySuhyunLee commented 4 months ago

First of all, thank you for such a great plugin :)

I'm wondering if it's possible to invoke the work manager from native side, just like in flutter. For instance, I want to do something like this (in android):

class MainActivity : FlutterActivity() {
    ...
    // triggered by some other native code
    fun triggerBackgroundWork() {
        final inputData = [workDataOf("param" to "foo")]
        FlutterWorkManager().registerOneOffTask("unique-task-id", "myTask", inputData: inputData)
    }

which triggers callback dispatcher defined in flutter side.

I first considered to manually instantiate a BackgroundWorker, but I'm not sure how I can import this class from my native code (or if it's even possible)

Is there any way to do this, or do you have any plans to support it in the future? Thanks in advance.

ened commented 4 months ago

What is your usecase for this?

RaySuhyunLee commented 4 months ago

Summary: I have to trigger background worker from an Invisible Activity (without UI).

This is my use case:

To do this, I made an invisible activity by using @android:style/Theme.NoDisplay, as invisible activity doesn't trigger app switching animation. This makes things a little bit complicated. Unlike normal activities, invisible activities should finish themselves right after being created (or they will crash). So to summarize, ideal workflow is like this:

  1. Invisible activity launches
  2. The activity triggers the flutter-side background worker
  3. The activity forgets about background worker and finish in advance.
  4. The flutter background worker starts, do some stuff and quit silently.

But since this doesn't seem possible for now, I'm using the following workaround, which is very hacky 😂

/* Android-side */
class TransparentActivity : FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        final methodChannel = ...
        final arguments = ...
        methodChannel.invokeMethod("triggerWorker", arguments) // ask for flutter worker to run with given arguments
        sleep(5000) // Wait until flutter engine to attach (so that it can receive method call)
        finish()
    }
}
/* Flutter-side */
void main() async {
  Workmanager().initialize(callbackDispatcher);
  final methodChannel = ...
  methodChannel.setMethodCallHandler((call) async {
    final inputData = {'arguments': call.arguments};
    Workmanager().registerOneOffTask(Uuid().v4(), "backgroundWork", inputData: inputData);
  });
  runApp(MyApp());
}

@pragma('vm:entry-point')
void callbackDispatcher() {
  ...
}

I know that my use case is very specific and complicated, but it will be really handy if there is a better approach.