Code Monkey home page Code Monkey logo

flutter_workmanager's Introduction

Flutter Workmanager

pub package Build status

Flutter WorkManager is a wrapper around Android's WorkManager, iOS' performFetchWithCompletionHandler and iOS BGAppRefreshTask, effectively enabling headless execution of Dart code in the background.

For iOS users, please watch this video on a general introduction to background processing: https://developer.apple.com/videos/play/wwdc2020/10063. All of the constraints discussed in the video also apply to this plugin.

This is especially useful to run periodic tasks, such as fetching remote data on a regular basis.

This plugin was featured in this Medium blogpost

Platform Setup

In order for background work to be scheduled correctly you should follow the Android and iOS setup first.

How to use the package?

See sample folder for a complete working example.
Before registering any task, the WorkManager plugin must be initialized.

@pragma('vm:entry-point') // Mandatory if the App is obfuscated or using Flutter 3.1+
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) {
    print("Native called background task: $task"); //simpleTask will be emitted here.
    return Future.value(true);
  });
}

void main() {
  Workmanager().initialize(
    callbackDispatcher, // The top level function, aka callbackDispatcher
    isInDebugMode: true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
  );
  Workmanager().registerOneOffTask("task-identifier", "simpleTask");
  runApp(MyApp());
}

The callbackDispatcher needs to be either a static function or a top level function to be accessible as a Flutter entry point.

The workmanager runs on a separate isolate from the main flutter isolate. Ensure to initialize all dependencies inside the Workmanager().executeTask.

Debugging tips

Wrap the code inside your Workmanager().executeTask in a try and catch in order to catch any exceptions thrown.

@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {

    int? totalExecutions;
    final _sharedPreference = await SharedPreferences.getInstance(); //Initialize dependency

    try { //add code execution
      totalExecutions = _sharedPreference.getInt("totalExecutions");
      _sharedPreference.setInt("totalExecutions", totalExecutions == null ? 1 : totalExecutions+1);
    } catch(err) {
      Logger().e(err.toString()); // Logger flutter package, prints error on the debug console
      throw Exception(err);
    }

    return Future.value(true);
  });
}

Android tasks are identified using their taskName. iOS tasks are identified using their taskIdentifier.

However, there is an exception for iOS background fetch: Workmanager.iOSBackgroundTask, a constant for iOS background fetch task.


Work Result

The Workmanager().executeTask(... block supports 3 possible outcomes:

  1. Future.value(true): The task is successful.
  2. Future.value(false): The task did not complete successfully and needs to be retried. On Android, the retry is done automatically. On iOS (when using BGTaskScheduler), the retry needs to be scheduled manually.
  3. Future.error(...): The task failed.

On Android, the BackoffPolicy will configure how WorkManager is going to retry the task.

Refer to the example app for a successful, retrying and a failed task.

iOS specific setup and note

Initialize Workmanager only once. Background app refresh can only be tested on a real device, it cannot be tested on a simulator.

Migrate to 0.6.x

Version 0.6.x of this plugin has some breaking changes for iOS:

  • Workmanager.registerOneOffTask was previously using iOS BGProcessingTask, now it will be an immediate run task which will continue in the background if user leaves the App. Since the previous solution meant the one off task will only run if the device is idle and as often experienced only when device is charging, in practice it means somewhere at night, or not at all during that day, because BGProcessingTask is meant for long running tasks. The new solution makes it more in line with Android except it does not support initialDelay
  • If you need the old behavior you can use the new iOS only method Workmanager.registerProcessingTask:
    1. Replace Workmanager().registerOneOffTask with Workmanager().registerProcessingTask in your App
    2. Replace WorkmanagerPlugin.registerTask with WorkmanagerPlugin.registerBGProcessingTask in AppDelegate.swift
  • Workmanager.registerOneOffTask does not support initialDelay
  • Workmanager.registerOneOffTask now supports inputData which was always returning null in the previous solution
  • Workmanager.registerOneOffTask now does NOT require WorkmanagerPlugin.registerTask call in AppDelegate.swift hence remove the call

One off tasks

iOS supports One off tasks only on iOS 13+ with a few basic constraints:

registerOneOffTask starts immediately. It might run for only 30 seconds due to iOS restrictions.

Workmanager().registerOneOffTask(
  "task-identifier",
  simpleTaskKey, // Ignored on iOS
  initialDelay: Duration(minutes: 30), // Ignored on iOS
  inputData: ... // fully supported
);

Periodic tasks

iOS supports two types of Periodic tasks:

  • On iOS 12 and lower you can use deprecated Background Fetch API, see iOS Setup, even though the API is deprecated by iOS it still works on iOS 13+ as of writing this article

  • registerPeriodicTask is only supported on iOS 13+, it might run for only 30 seconds due to iOS restrictions, but doesn't start immediately, rather iOS will schedule it as per user's App usage pattern.

⚠️ On iOS 13+, adding a BGTaskSchedulerPermittedIdentifiers key to the Info.plist for new BGTaskScheduler API disables the performFetchWithCompletionHandler and setMinimumBackgroundFetchInterval methods, which means you cannot use both old Background Fetch and new registerPeriodicTask at the same time, you have to choose one based on your minimum iOS target version. For details see Apple Docs

To use registerPeriodicTask first register the task in Info.plist and AppDelegate.swift iOS Setup. Unlike Android, for iOS you have to set the frequency in AppDelegate.swift. The frequency is not guaranteed rather iOS will schedule it as per user's App usage pattern, iOS might take a few days to learn usage pattern. In reality frequency just means do not repeat the task before x seconds/minutes. If frequency is not provided it will default to 15 minutes.

// Register a periodic task with 20 minutes frequency. The frequency is in seconds.
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh", frequency: NSNumber(value: 20 * 60))

Then schedule the task from your App

const iOSBackgroundAppRefresh = "be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh";
Workmanager().registerPeriodicTask(
  iOSBackgroundAppRefresh,
  iOSBackgroundAppRefresh,
  initialDelay: Duration(seconds: 10),
  frequency: Duration(hours: 1), // Ignored on iOS, rather set in AppDelegate.swift
  inputData: ... // Not supported
);

For more information see BGAppRefreshTask

Processing tasks

iOS supports Processing tasks only on iOS 13+ which can run for more than 30 seconds.

registerProcessingTask is a long running one off background task, currently only for iOS. It can be run for more than 30 seconds but doesn't start immediately, rather iOS might schedule it when device is idle and charging. Processing tasks are for long processes like data processing and app maintenance. Processing tasks can run for minutes, but the system can interrupt these. iOS might terminate any running background processing tasks when the user starts using the device. For more information see BGProcessingTask

const iOSBackgroundProcessingTask = "be.tramckrijte.workmanagerExample.iOSBackgroundProcessingTask";
Workmanager().registerProcessingTask(
  iOSBackgroundProcessingTask,
  iOSBackgroundProcessingTask,
  initialDelay: Duration(minutes: 2),
  constraints: Constraints(
    // Connected or metered mark the task as requiring internet
    networkType: NetworkType.connected,
    // Require external power
    requiresCharging: true,
  ),
);

Background App Refresh permission

On iOS user can disable Background App Refresh permission anytime, hence background tasks can only run if user has granted the permission.

Use permision_handler to check for the permission:

final status = await Permission.backgroundRefresh.status;
if (status != PermissionStatus.granted) {
  _showNoPermission(context, status);
  return;
}

For more information see the BGTaskScheduler documentation.

Print scheduled tasks

On iOS you can print scheduled tasks using Workmanager.printScheduledTasks

It prints task details to console. To be used during development/debugging. Currently only supported on iOS and only on iOS 13+.

if (Platform.isIOS) {
  Workmanager().printScheduledTasks();
  // Prints: [BGTaskScheduler] Task Identifier: iOSBackgroundAppRefresh earliestBeginDate: 2023.10.10 PM 11:10:12
  // Or:     [BGTaskScheduler] There are no scheduled tasks
}

Customisation (Android)

Not every Android WorkManager feature is ported.

Two kinds of background tasks can be registered :

  • One off task : runs only once
  • Periodic tasks : runs indefinitely on a regular basis
// One off task registration
Workmanager().registerOneOffTask(
    "oneoff-task-identifier", 
    "simpleTask"
);

// Periodic task registration
Workmanager().registerPeriodicTask(
    "periodic-task-identifier", 
    "simplePeriodicTask", 
    // When no frequency is provided the default 15 minutes is set.
    // Minimum frequency is 15 min. Android will automatically change your frequency to 15 min if you have configured a lower frequency.
    frequency: Duration(hours: 1),
)

Each task must have an unique name;
This allows cancellation of a started task.
The second parameter is the String that will be sent to your callbackDispatcher function, indicating the task's type.

Tagging

You can set the optional tag property.
Handy for cancellation by tag.
This is different from the unique name in that you can group multiple tasks under one tag.

Workmanager().registerOneOffTask("1", "simpleTask", tag: "tag");

Existing Work Policy

Indicates the desired behaviour when the same task is scheduled more than once.
The default is KEEP

Workmanager().registerOneOffTask("1", "simpleTask", existingWorkPolicy: ExistingWorkPolicy.append);

Initial Delay

Indicates how along a task should waitbefore its first run.

Workmanager().registerOneOffTask("1", "simpleTask", initialDelay: Duration(seconds: 10));

Constraints

Constraints are mapped at best effort to each platform. Android's WorkManager supports most of the specific constraints, whereas iOS tasks are limited.

  • NetworkType Constrains the type of network required for your work to run. For example, Connected. The NetworkType lists various network conditions. .connected & .metered will be mapped to requiresNetworkConnectivity on iOS.
  • RequiresBatteryNotLow (Android only) When set to true, your work will not run if the device is in low battery mode. Enabling the battery saving mode on the android device prevents the job from running
  • RequiresCharging When set to true, your work will only run when the device is charging.
  • RequiresDeviceIdle (Android only) When set to true, this requires the user’s device to be idle before the work will run. This can be useful for running batched operations that might otherwise have a - negative performance impact on other apps running actively on the user’s device.
  • RequiresStorageNotLow (Android only) When set to true, your work will not run if the user’s storage space on the device is too low.
Workmanager().registerOneOffTask(
    "1",
    "simpleTask",
    constraints: Constraints(
        networkType: NetworkType.connected,
        requiresBatteryNotLow: true,
        requiresCharging: true,
        requiresDeviceIdle: true,
        requiresStorageNotLow: true
    )
);

InputData

Add some input data for your task. Valid value types are: int, bool, double, String and their list

 Workmanager().registerOneOffTask(
    "1",
    "simpleTask",
    inputData: {
    'int': 1,
    'bool': true,
    'double': 1.0,
    'string': 'string',
    'array': [1, 2, 3],
    },
);

BackoffPolicy

Indicates the waiting strategy upon task failure.
The default is BackoffPolicy.exponential.
You can also specify the delay.

Workmanager().registerOneOffTask("1", "simpleTask", backoffPolicy: BackoffPolicy.exponential, backoffPolicyDelay: Duration(seconds: 10));

Cancellation

A task can be cancelled in different ways :

By Tag

Cancels the task that was previously registered using this Tag, if any.

Workmanager().cancelByTag("tag");

By Unique Name

Workmanager().cancelByUniqueName("<MyTask>");

All

Workmanager().cancelAll();

flutter_workmanager's People

Contributors

absar avatar clragon avatar edsonboldrini avatar ened avatar glitchy-tozier avatar hanabi1224 avatar hawkbee1 avatar ifesunmola avatar jeremie-movify avatar joaovvrodrigues avatar johnpryan avatar loonix avatar masterashu avatar mmahgoub avatar mx1up avatar parthdave93 avatar petermnt avatar petermusembi69 avatar pierre-monier avatar prefanatic avatar pyranox avatar renanzdm avatar setcy avatar spitfire55 avatar tamir198 avatar timrijckaert avatar tuyen-vuduc avatar vanlooverenkoen avatar vigneshthedev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter_workmanager's Issues

⬆️ Debug Mode notification improvement

Implementing improvements to the debug notification on Android.

  • The first information notification should be removed if the result notification was posted.
  • Show elapsed time in seconds between starting the Flutter engine and receiving the result.
  • Emoji's!
  • Use the date formatter of the user
  • Provide a sample screenshot in the ANDROID_README

⬆️ Debug Mode should post a notification

When a background task was scheduled it is difficult to trace/debug whether this task actually ran.
When a task runs on Android 2 notifications are shown:

  • The first one appears when a the background task was launched in native side. This is called before Flutter Engine is started. We output some useful information this includes:
    • dartTask
      This was the value the task was scheduled with during registerOneOffTask or registerPeriodicTask and outputted to the executeTask method. On iOS this irrelevant.
    • callbackHandle:
      This is the raw int handle that was saved during the initialize method
    • callBackName:
      This is the name of the callbackDispatcher function. If a user renamed this in between runs this would be very helpful debug information.
    • callbackClassName:
      The name (if any) of the class this callbackDispatcher resides in.
    • callbackLibraryPath:
      The filename of where the callbackDispatcher resides.
    • dartBundlePath:
      The path where of the Dart code inside the binary.
  • The second notification is scheduled when the Result is returned from the callbackDispatcher.

Example of Android debug notifications:
Screenshot_20190813-193847

The idea would be to get the same behaviour on iOS too.

Some improvements will be made:

  • Show the elapsed time in seconds between starting the callback and retrieving the answer (so you know how long your background task ran, this should be as little as possible)
  • Emoji's for quick glancing to see if it returned a success or a failure
  • Stacks, combine logical grouping of notification
  • Remove the first notification with the information if the result is received.
  • Local Local formatting for time
  • Don't forget to show an example screenshot of what a user can expect in the IOS_README

Android improvement ticket #36

Airplane mode overnight cancels periodictask?

I'm running a periodic task and it works perfectly. However during the night I usually turn on airplane mode and turn it off in the morning. From that point on I do not receive notifications again.

🐞 Unhandled Exception: MissingPluginException.

As discovered in #4.
flutter_workmanager: 0.0.6+1

It seems like it is currently impossible to use other plugins inside your background task as they are not registered.

[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method FirebaseApp#appNamed on channel plugins.flutter.io/firebase_core)

Simple example:

pubspec:

name: workmanager_example
description: Demonstrates how to use the workmanager plugin.
publish_to: 'none'

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  path_provider: ^1.2.0
  workmanager: 0.0.6+1
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2

flutter:
  uses-material-design: true

main.dart

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'dart:async';

import 'package:workmanager/workmanager.dart';

void callbackDispatcher() {
  Workmanager.defaultCallbackDispatcher((echoValue) async {
    switch (echoValue) {
      case simpleTaskKey:
        Directory tempDir = await getTemporaryDirectory();
        String tempPath = tempDir.path;
        break;
    }

    return Future.value(true);
  });
}

App closes imediatelly after starting.

OK. So, the install instructions aren't very through for mortals like me so this is what I did:
1 - create new flutter app (run, test, OK)
2 - added workmanager: ^0.0.15 to the dependencies (get packages, ok)
3 - created a file called App.kt under android.app.source.main.java.myproject.com.projectname along with the MainActivity.java file
4 - copy the file from readme to App.kt
5 - change AndroidManifest.xml under android.app.source.main android:name=".App"
6 - run app
7 - emulator blinks as if it was opening an app and them goes back to the device screen
8 - console says: Installing build\app\outputs\apk\app.apk... and stays there

What am I missing here?

Can't get the iOS version to work. Help needed

Hey guys,

I tried to run the example as well as my own version. Android works fine but I can't get the simulator to run notifications never. Is there some trick with simulator or do I have to use real device?

Also, the option to dispatch fetch in xcode is greyed out for me, so I couldn't try that one from the docs.

"variable declaration in when subject" only supported since 1.3

Failed to compile version 0.0.12

android/src/main/kotlin/be/tramckrijte/workmanager/WorkmanagerCallHandler.kt: (22, 19): The feature "variable declaration in when subject" is only available since language version 1.3

If you are having this issue. Upgrade your Kotlin version of 1.3 or above for your project.

App crashes during initialisation of task

I tried to integrate the dummy code example in my App:

void callbackDispatcher() {
  Workmanager.executeTask((backgroundTask) {
    print("Native called background task: $backgroundTask"); //simpleTask will be emitted here.
    return Future.value(true);
  });
}

void main() {
  Workmanager.initialize(
    callbackDispatcher, // The top level function, aka callbackDispatcher
    isInDebugMode: true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
  );
  Workmanager.registerOneOffTask("1", "simpleTask");
  runApp(MyApp());
}

But I got the following error while starting:

E/AndroidRuntime(27923): kotlin.UninitializedPropertyAccessException: lateinit property pluginRegistryCallback has not been initialized
E/AndroidRuntime(27923): 	at be.tramckrijte.workmanager.WorkmanagerPlugin$Companion.getPluginRegistryCallback(WorkmanagerPlugin.kt:13)
E/AndroidRuntime(27923): 	at be.tramckrijte.workmanager.BackgroundWorker$doWork$1.run(BackgroundWorker.kt:71)
E/AndroidRuntime(27923): 	at android.os.Handler.handleCallback(Handler.java:751)
E/AndroidRuntime(27923): 	at android.os.Handler.dispatchMessage(Handler.java:95)
E/AndroidRuntime(27923): 	at android.os.Looper.loop(Looper.java:154)
E/AndroidRuntime(27923): 	at android.app.ActivityThread.main(ActivityThread.java:6682)
E/AndroidRuntime(27923): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(27923): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
E/AndroidRuntime(27923): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

⬆️ iOS: Show debug notifications in foreground

As mentioned in #45: if the example app is running in the foreground while simulating a background fetch in Xcode, the notification banner isn't shown. That is default behaviour on iOS.

Triggering Simulate Background Fetch when running on a real device will put the app in the background automatically for you. This doesn't happen in the simulator for some reason 🤷‍♂️

If you do want the banners to appear while your app is in the foreground you can implement userNotificationCenter(_:willPresent:withCompletionHandler:) of UNUserNotificationCenterDelegate.

From the Apple docs:

If your app is in the foreground when a notification arrives, the shared user notification center calls this method to deliver the notification directly to your app. If you implement this method, you can take whatever actions are necessary to process the notification and update your app. When you finish, call the completionHandler block and specify how you want the system to alert the user, if at all.

The example app should implement this delegate call, and it's definitely something we should mention in our documentation (see #46) as well.

Erro start - service

workmanager: ^0.1.1

E/AndroidRuntime( 6854): kotlin.UninitializedPropertyAccessException: lateinit property pluginRegistryCallback has not been initialized

[√] Flutter (Channel master, v1.10.2-pre.83, on Microsoft Windows [versão 10.0.18362.356], locale pt-BR)
[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[√] Android Studio (version 3.5)
[√] VS Code (version 1.37.0)
[√] Connected device (1 available)

FlutterLocation Plugin is not registered with an Application Context

After initialising the the workmanager and creating either of the tasks, If we use any plugins inside of the task execution it isn't recognised and throw an error as bellow
MissingPluginException(No implementation found for method getLocation on channel lyokone/location)

Actual code :
Workmanager.executeTask((task, inputData) async { Location locationObject = Location(); locationObject.getLocation(); print(locationObject); return Future.value(true); }

Basically any other plugin used inside of the task of work manager seems to be not recognised.

What am I missing, Do I need to register all my plugins again ?

⬆️ iOS: UserDefaults scoping and key uniqueness

Currently the CallbackHandle is stored in the standard UserDefaults, it might be better to not 'dirty' up the standard UserDefaults but to instead store any necessary info in a separate suite specifically for the plugin.

It would also be safer to prefix certain Strings with the plugin's identifier, to make them more unique. More specifically:

  • The callbackHandleStorageKey used to store a callback handle in the UserDefaults
  • The flutterThreadLabelPrefix used to initialise a FlutterEngine

Relevant excerpt from the FlutterEngine.hfile:

 * @param labelPrefix The label prefix used to identify threads for this instance. Should
 *   be unique across FlutterEngine instances, and is used in instrumentation to label
 *   the threads used by this FlutterEngine.
 * @param projectOrNil The `FlutterDartProject` to run.
 */
- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil;

[Question] Android custom application

Regarding Android setup process, is it possible to add default working custom application to plugin so that ppl only need to change application name and save the step to create an application class everytime?

IOS pod install error

Hi,
I am getting this error when trying to run the app on IOS.

Unable to determine Swift version for the following pods:
    - `workmanager` does not specify a Swift version and none of the targets (`Runner`) integrating it have the `SWIFT_VERSION` attribute set.
Please contact the author or set the `SWIFT_VERSION` attribute in at least one of the targets that integrate this pod.

🐞 iOS: issue with delivery of local notifications

In our testing we noticed an issue with delivery of the local debug notifications.

We see a lot of "👷‍♀️ work started" notifications but no "🔥/ 🎉 work finished" notifications (finished should overwrite started notifications). When, at a later point we open the app we immediately see the work finished notification coming in.

The timestamps and elapsed times are all correct, so it's definitely a notification delivery issue. The actual background fetch did run correctly.

🐞 setPluginRegistrantCallback cannot find symbol Java

I'm getting this error, am I missing something?

Application.java:12: error: cannot find symbol
    WorkmanagerPlugin.setPluginRegistrantCallback(this);
                     ^
  symbol:   method setPluginRegistrantCallback(Application)
  location: class WorkmanagerPlugin
1 error

FAILURE: Build failed with an exception.

Application.java

package`package_name`;

import be.tramckrijte.workmanager.WorkmanagerPlugin;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class Application extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    WorkmanagerPlugin.setPluginRegistrantCallback(this);
  }

  @Override
  public void registerWith(PluginRegistry registry) {
    GeneratedPluginRegistrant.registerWith(registry);
  }
}

I've added the custom application to android manifest.

I have the dependency: workmanager: ^0.0.11

Conflicts with other plugins

I assume this issue could be relevant not only for flutter_webview_plugin ,but still.
I have listeners attached to flutter_webview_plugin. For example onUrlChanged and onStateChanged. All works fine until I call Workmanager.initialize().
No errors. Just listeners stops working.

MissingPluginException(No implementation found for method initialize...

I'm using workmanager: ^0.1.0

Getting an error calling initialize method:

MissingPluginException(No implementation found for method initialize on channel be.tramckrijte.workmanager/foreground_channel_work_manager)

My main.dart:

import 'package:workmanager/workmanager.dart' as workManager;

...

void main() async {
  FlutterError.onError = (errorDetails) {
    Logger.e( "${errorDetails.exception}");
    if (Logger.isInDebugMode) {
      FlutterError.dumpErrorToConsole(errorDetails);
    }
  };

  runZoned(() {
    workManager.Workmanager.initialize(
        LocationManager.updateDeviceLocationIsolate,
        isInDebugMode: Logger.isInDebugMode
    );
    runApp(new HAClientApp());

  }, onError: (error, stack) {
    Logger.e("$error");
    Logger.e("$stack");
    if (Logger.isInDebugMode) {
      debugPrint("$stack");
    }
  });
}

...

My Application.java:

package com.keyboardcrumbs.hassclient;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import be.tramckrijte.workmanager.WorkmanagerPlugin;

public class Application extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        WorkmanagerPlugin.setPluginRegistrantCallback(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }
}

Part of my AndroidManifest.xml:

....

<application
        android:name=".Application"
        android:label="HA Client"
        android:icon="@mipmap/ic_launcher"
        android:usesCleartextTraffic="true">

...

⬆️ Improve result code from a Background Task

Actually this was an idea we already discussed with @jeremie-movify and @petermnt before.
The return of a boolean as the result of a background job was a MVP approach and might be insufficient.

Ideally we would want to return some sort of enum representing the success state of a background task.

Android already expects either a:

  • Result.failure()
    • Used to indicate that the work completed with a permanent failure. Any work that depends
      on this will also be marked as failed and will not be run. If you need child workers
      to run, you need to return Result.Success() failure indicates a permanent
      stoppage of the chain of work.

  • Result.success()
    • Used to indicate that the work completed successfully. Any work that depends on this
      can be executed as long as all of its other dependencies and constraints are met.

  • Result.Retry()
    • Used to indicate that the work encountered a transient failure and should be retried with
      backoff.

As of now (0.0.12) the plugin will map the returning bool as following:

  • false -> Result.retry()
  • true -> Result.success()

I thought the iOS return code was similarly mapped.

We could then have something like:

void callbackDispatcher() {
  var result = Result.retry
  Workmanager.executeTask((task) async {
    switch (task) {
      case simpleTaskKey:
       print("do some background work");
       result = Result.success
        break;
    }

    return Future.value(result);
  });
}

Originally posted by @timrijckaert in #20 (comment)

🐞 Android: Missing PluginException for cancelAll

Crash when using cancelAll.

ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method cancelAll on channel be.tramckrijte.workmanager/foreground_channel_work_manager)
E/flutter (17937): #0      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:314:7)
E/flutter (17937): <asynchronous suspension>
E/flutter (17937): #1      Workmanager.cancelAll (package:workmanager/src/workmanager.dart:163:32)
E/flutter (17937): <asynchronous suspension>
E/flutter (17937): #2      BackgroundWorker.cancelAll (package:flutter_template/background/background.dart:60:42)
E/flutter (17937): #3      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:635:14)
E/flutter (17937): #4      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:711:32)
E/flutter (17937): #5      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (17937): #6      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
E/flutter (17937): #7      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
E/flutter (17937): #8      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
E/flutter (17937): #9      PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:75:13)
E/flutter (17937): #10     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:102:11)
E/flutter (17937): #11     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
E/flutter (17937): #12     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
E/flutter (17937): #13     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter (17937): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter (17937): #15     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (17937): #16     _rootRunUnary (dart:async/zone.dart:1136:13)
E/flutter (17937): #17     _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (17937): #18     _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
E/flutter (17937): #19     _invoke1 (dart:ui/hooks.dart:250:10)
E/flutter (17937): #20     _dispatchPointerDataPacket (dart:ui/hooks.dart:159:5)

Handle notifications

Congratulations for the work. This is the only background solution I know.

Could you give us the freedom to configure the notification that appears after starting the service? How to choose the icon, title and be able to generate a link by clicking on it? How to generate a link to open the app.

build failed

Error output from Xcode build:

** BUILD FAILED **

Xcode's output:

/Users/apple/git_flutter/flutter/.pub-cache/hosted/pub.flutter-io.cn/workmanager-0.1.0/ios/Classes/SwiftWorkmanagerPlugin.swift:98:156: error: argument type 'FlutterEngine' does not conform to expected type 'FlutterBinaryMessenger'
var backgroundMethodChannel: FlutterMethodChannel? = FlutterMethodChannel(name: BackgroundMethodChannel.channelName, binaryMessenger: flutterEngine!)
~~~~~~~~~~~~~^
as! FlutterBinaryMessenger

UninitializedPropertyAccessException: lateinit property pluginRegistryCallback has not been initialized E

E/AndroidRuntime(28568): kotlin.UninitializedPropertyAccessException: lateinit property pluginRegistryCallback has not been initialized
E/AndroidRuntime(28568): at be.tramckrijte.workmanager.WorkmanagerPlugin$Companion.getPluginRegistryCallback(WorkmanagerPlugin.kt:13)
E/AndroidRuntime(28568): at be.tramckrijte.workmanager.BackgroundWorker$doWork$1.run(BackgroundWorker.kt:71)
E/AndroidRuntime(28568): at android.os.Handler.handleCallback(Handler.java:789)
E/AndroidRuntime(28568): at android.os.Handler.dispatchMessage(Handler.java:98)
E/AndroidRuntime(28568): at android.os.Looper.loop(Looper.java:164)
E/AndroidRuntime(28568): at android.app.ActivityThread.main(ActivityThread.java:6944)
E/AndroidRuntime(28568): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(28568): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
E/AndroidRuntime(28568): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Build failure

Build failed with error

'pngData()' has been renamed to 'UIImagePNGRepresentation(_:)'
``` in swift 4.2

❓How to schedule a Periodic Task

I've been trying to use the package, but I couldn't find out where to put the code to perform the desired Task. As I understood from the working example and from the plugin implementation, I would have to write a custom class that extends the Worker and override the doWork function, but when installing the package by pubspec I wasn't able to find out where to put it.

App throws exception with simple task

I can't get to run ths library
this is how I configured my App class "App.java"

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class App extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback{
    @Override()
    public void onCreate() {
        super.onCreate();
        WorkmanagerPlugin.setPluginRegistrantCallback(this);
    }

    @Override()
    public void registerWith(PluginRegistry reg) {
        GeneratedPluginRegistrant.registerWith(reg);
    }
}

this the code I ran just like the readme

    Workmanager.initialize(
        callbackDispatcher, // The top level function, aka callbackDispatcher
        isInDebugMode:
            true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
        );
    Workmanager.registerOneOffTask("1", "simpleTask");

and this is the error I am getting

E/AndroidRuntime( 8906): FATAL EXCEPTION: main
E/AndroidRuntime( 8906): Process: com.tafeel.full.masar4, PID: 8906
E/AndroidRuntime( 8906): java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.Application android.app.Activity.getApplication()' on a null object reference
E/AndroidRuntime( 8906): 	at com.github.adee42.keyboardvisibility.KeyboardVisibilityPlugin.registerWith(KeyboardVisibilityPlugin.java:107)
E/AndroidRuntime( 8906): 	at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(GeneratedPluginRegistrant.java:33)
E/AndroidRuntime( 8906): 	at com.tafeel.masar_4_flutter.App.registerWith(App.java:20)
E/AndroidRuntime( 8906): 	at be.tramckrijte.workmanager.BackgroundWorker$doWork$1.run(BackgroundWorker.kt:71)
E/AndroidRuntime( 8906): 	at android.os.Handler.handleCallback(Handler.java:873)
E/AndroidRuntime( 8906): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 8906): 	at android.os.Looper.loop(Looper.java:193)
E/AndroidRuntime( 8906): 	at android.app.ActivityThread.main(ActivityThread.java:6669)
E/AndroidRuntime( 8906): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 8906): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/AndroidRuntime( 8906): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

App Crashes automatically

2019-09-18 19:46:18.575 4430-4430/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.avinashi.meracrm_master_app, PID: 4430
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.Application android.app.Activity.getApplication()' on a null object reference
        at com.github.adee42.keyboardvisibility.KeyboardVisibilityPlugin.registerWith(KeyboardVisibilityPlugin.java:107)
        at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(GeneratedPluginRegistrant.java:19)
        at com.avinashi.meracrm_master_app.App.registerWith(Application.kt:15)
        at be.tramckrijte.workmanager.BackgroundWorker$doWork$1.run(BackgroundWorker.kt:71)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:241)
        at android.app.ActivityThread.main(ActivityThread.java:6274)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
2019-09-18 19:46:18.952 4430-4496/com.avinashi.meracrm_master_app I/flutter: Observatory listening on http://127.0.0.1:47083/mRwMFBkhYAY=/

Wake up the application

Is there any way to wake up the application when the task running and the application is closed? I tried to used a navigator but there aren't any context to push on it.

🐞 iOSPerformFetch actually never worked

iOSPerformFetch actually calls the Flutter callback with nill arguments.

This will cause Flutter to start the callbackDispatcher, but it will not go through the user provided switch case.

backgroundMethodChannel?.invokeMethod(BackgroundMethodChannel.methods.iOSPerformFetch.rawValue, arguments: nil, result: ...)

Instead should be

backgroundMethodChannel?.invokeMethod(BackgroundMethodChannel.methods.iOSPerformFetch.rawValue, arguments: BackgroundMethodChannel.methods.iOSPerformFetch.rawValue, result: ...)

⬆️ Better Example

We could use a better sample.
Ideas:

  • Have a log file that keeps track of previous ran tasks.
  • Completely different UI for either Android and iOS.
    • Android could expose all possible options in a sort of form.
    • iOS could only expose the log file, since there is zero customisability on iOS

Current Sample:
Current Sample app screenshot

Communication with main thread

First of all, amazing plugin! Thanks for the great work.

I'm new to Flutter development and had some progress with using isolates and SendPort to communicate data between the isolate and main thread. Unfortunately I found out the hard way that isolates do not continue running when the app goes to the background and that's when I found your plugin.

However, I can't seem to figure out what would be the best method with communicating between the main thread (layout) and the background isolate. The situation would be contacting a server multiple times and sending a progress (0-100) to the main thread which shows a progress indicator. The user would be able to dismiss the progress view and check the progress later where it would continue the progress.
I solved this now with an isolate connected to a parent widget which keeps the SendPort connection always open. So if a child widget closes/changes that parent would still have the progress.

Any ideas how this would be possible in your plugin?

Thanks!

Themuzz

📝 Interval duration lesser than minimum allowed value; Changed to 900000

Android Jetpack automatically changes your interval to 15min or 900000

This should be documented here as well. People who are using this plugin will not necessarily know that this is the case. Although Jetpack prints out:

W/WM-WorkSpec(13916): Interval duration lesser than minimum allowed value; Changed to 900000

I think it should be documented somewhere as well.

Is it possible to use the plugin for data sync in background like the way firebase does

I wonder how is possible to sync offline data with server like firebase does in background especially in iOS . with OneOffTask by network connected constraint we can do it easily in android but in iOS we have just fetch in background can we use that for this purpose? If not and If the iOS has restricted this, how the firebase does syncing in iOS

NoSuchMethodError: the method 'toRawHandle' was called on null.

image

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="br.art.code.xxx" 
    xmlns:tools="http://schemas.android.com/tools">
    <application tools:replace="android:label,android:icon,android:name" android:name=".App" android:label="xxx"
        android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/icon_round" android:fullBackupContent="@xml/backup_rules">
        <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>

        <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />

        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-xxx~xxx"/>

        <activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait" 
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

        <activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />

        <activity android:name="com.facebook.CustomTabActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" 
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
            <meta-data android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
</manifest>

App.kt as documentation suggests.

[√] Flutter (Channel master, v1.10.7-pre.37, on Microsoft Windows [Version 10.0.18362.356], locale en-GB)
    • Flutter version 1.10.7-pre.37 at C:\flutter
    • Framework revision 56d68a9071 (30 hours ago), 2019-09-26 14:01:57 -0700
    • Engine revision b126ba7585
    • Dart version 2.6.0 (build 2.6.0-dev.3.0 6ff8d2199d)

 
[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at C:\Users\jckod\Android\SDK
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.2
    • ANDROID_HOME = C:\Users\jckod\Android\SDK
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b03)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

[√] Android Studio (version 3.5)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 39.0.3
    • Dart plugin version 191.8423
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b03)

[√] VS Code (version 1.38.1)
    • VS Code at C:\Users\jckod\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.4.1

[√] Connected device (3 available)
    • Android SDK built for x86 • emulator-5554 • android-x86    • Android 7.0 (API 24) (emulator)
    • Chrome                    • chrome        • web-javascript • Google Chrome 77.0.3865.90
    • Server                    • web           • web-javascript • Flutter Tools

• No issues found!

🚀 0.0.13

  • Document new debug iOS notification
  • Add Kymer to contributors

⬆️ UIBackgroundFetchResult ordinal mapping

Currently in the setMethodCallHandler block of backgroundMethodChannel a UIBackgroundFetchResult is created using the flutter result Int like so:

UIBackgroundFetchResult(rawValue: UInt(fetchResult))

We shouldn't rely on the internal ordering of UIBackgroundFetchResult cases, as they could change with future iOS releases.

Passing ExistingWorkPolicy values to existingWorkPolicy parameter causes exception

Workmanager.initialize(callbackDispatcher, isInDebugMode: true);
Workmanager.registerPeriodicTask(
    "1",  
    "simpleTask", 
     existingWorkPolicy: ExistingWorkPolicy.replace, 
     frequency: Duration(hours: 24) ,
     initialDelay: Duration(seconds: 5), 
);
E/flutter (23220): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Invalid argument: Instance of 'ExistingWorkPolicy'
E/flutter (23220): #0      StandardMessageCodec.writeValue (package:flutter/src/services/message_codecs.dart:387:7)
E/flutter (23220): #1      StandardMessageCodec.writeValue.<anonymous closure> (package:flutter/src/services/message_codecs.dart:384:9)
E/flutter (23220): #2      __InternalLinkedHashMap&_HashVMBase&MapMixin&_LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:367:8)
E/flutter (23220): #3      StandardMessageCodec.writeValue (package:flutter/src/services/message_codecs.dart:382:13)
E/flutter (23220): #4      StandardMethodCodec.encodeMethodCall (package:flutter/src/services/message_codecs.dart:519:18)
E/flutter (23220): #5      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:311:13)
E/flutter (23220): <asynchronous suspension>
E/flutter (23220): #6      Workmanager._register (package:workmanager/workmanager.dart:216:37)
E/flutter (23220): <asynchronous suspension>
E/flutter (23220): #7      Workmanager.registerPeriodicTask (package:workmanager/workmanager.dart:189:13)
E/flutter (23220): <asynchronous suspension>
E/flutter (23220): #8      HazizzNotification.scheduleNotificationAlarmManager (package:mobile/notification/notification.dart:156:17)
E/flutter (23220): #9      _AsyncAwaitCompleter.start (dart:async-patch/async_patch.dart:49:6)
E/flutter (23220): #10     HazizzNotification.scheduleNotificationAlarmManager (package:mobile/notification/notification.dart:142:49)
E/flutter (23220): #11     _SettingsPage.build.<anonymous closure> (package:mobile/pages/settings_page.dart:255:38)
E/flutter (23220): #12     _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:77:64)
E/flutter (23220): #13     _rootRunUnary (dart:async/zone.dart:1132:38)
E/flutter (23220): #14     _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (23220): #15     _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
E/flutter (23220): #16     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
E/flutter (23220): #17     Future._propagateToListeners (dart:async/future_impl.dart:668:32)
E/flutter (23220): #18     Future._complete (dart:async/future_impl.dart:473:7)
E/flutter (23220): #19     _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter (23220): #20     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:28:18)
E/flutter (23220): #21     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:294:13)
E/flutter (23220): #22     showTimePicker (package:flutter/src/material/time_picker.dart)
E/flutter (23220): #23     _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:77:64)
E/flutter (23220): #24     _rootRunUnary (dart:async/zone.dart:1132:38)
E/flutter (23220): #25     _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (23220): #26     _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
E/flutter (23220): #27     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
E/flutter (23220): #28     Future._propagateToListeners (dart:async/future_impl.dart:668:32)
E/flutter (23220): #29     Future._completeWithValue (dart:async/future_impl.dart:483:5)
E/flutter (23220): #30     Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:513:7)
E/flutter (23220): #31     _rootRun (dart:async/zone.dart:1124:13)
E/flutter (23220): #32     _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (23220): #33     _CustomZone.runGuarded (dart:async/zone.dart:923:7)
E/flutter (23220): #34     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
E/flutter (23220): #35     _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (23220): #36     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)

Conflict with flutter_blue plugin

After add and set up the work manager plugin, I tested my app with a simple task:
image
And when the 10 seconds passed it throws an exception:
image
However, the task was triggered, but many times (this bug made me uninstall the app):
image
My pubspec.yml:
image

What should I do to solve this?

⬆️ iOS: Plugin should work in ObjC-only projects

As mentioned in issue #57: the Workmanager plugin should work out of the box with ObjC-only projects. Currently you get the following error when running pod install:

Unable to determine Swift version for the following pods:
    - `workmanager` does not specify a Swift version and none of the targets (`Runner`) integrating it have the `SWIFT_VERSION` attribute set.
Please contact the author or set the `SWIFT_VERSION` attribute in at least one of the targets that integrate this pod.

Unhandled Exception: PlatformException - WorkManager is not initialized properly

Hello, thanks for the package.
I am trying to write data to Google's Firestore every x minutes let's say. I created App.kt and set it as android:name. And my main file is as the following:

void callbackDispatcher() {
  Workmanager.executeTask((backgroundTask) {
    Test.writeTestData();
    return Future.value(true);
  });
}

void main() {
  if (Platform.isAndroid) {
    Workmanager.initialize(
      callbackDispatcher, // The top level function, aka Flutter entry point
      isInDebugMode: true,
    );
    Workmanager.registerPeriodicTask("testSensor", "simplePeriodicTask", frequency: Duration(seconds: 10));
  }
  runApp(MyApp());
} 

And the error is:

Unhandled Exception: PlatformException(error, WorkManager is not initialized properly. You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider., null)

Cheers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.