fluttercommunity / flutter_workmanager

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

🐞When use 'await' to Obtain shared preferences, I got "Worker result FAILURE for Work". #361

Open waynewcwu opened 2 years ago

waynewcwu commented 2 years ago

Version

Technology Version
Workmanager version 0.4.1
SharedPreferences version 2.0.13

Describe the error I get the fail I/WM-WorkerWrapper(25984): Worker result FAILURE for Work [ id=eaf19926-15cd-4ba9-8858-ab8ed99182aa, tags={ be.tramckrijte.workmanager.BackgroundWorker } ] when I try to run the Debugging tips sample code in the README.md.

Then I mark final prefs = await SharedPreferences.getInstance(); and try and catch, it get worker result successful.

May I ask same suggestion? Thanks.

My mainfull code as below:

onst myTask = "syncWithTheBackEnd";

void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async{
    switch (task) {
      case myTask:

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

            try { //add code execution
              totalExecutions = await prefs.getInt("totalExecutions");
              // prefs.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);
            }

          break;
        case Workmanager.iOSBackgroundTask:
          print("iOS background fetch delegate ran");
          break;
      }

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

void main() {
  // add this, and it should be the first line in main method
  WidgetsFlutterBinding.ensureInitialized();
  //Workmanager.initialize(callbackDispatcher);
  Workmanager().initialize(callbackDispatcher, isInDebugMode: false);
  Workmanager().registerOneOffTask(
    "1",
    myTask, //This is the value that will be returned in the  #callbackDispatcher
  );
  runApp(MyApp());
}

//----------------------------------------------------------------------------------------------------

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('HKT 線上教室'),
        ),
        body: HomePage(),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver{
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('$state');
  }
  @override
  void initState() {
    super.initState();
    print('initState+++');
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void dispose() {
    print('dispose+++');
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('跳到 B 頁'),
        onPressed: () {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => BPage()));
        },
      ),
    );
  }
}

class BPage extends StatefulWidget {
  @override
  _BPageState createState() => _BPageState();
}

class _BPageState extends State<BPage> with WidgetsBindingObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('$state');
    // if (state == AppLifecycleState.resumed) {
    //   print('resumed');
    // }
    // else if (state == AppLifecycleState.inactive) {
    //   print('inactive');
    // }
    // else if (state == AppLifecycleState.paused) {
    //   print('paused');
    // }
  }

  @override
  void initState() {
    super.initState();
    print('initState+++');
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies+++');
  }

  @override
  void deactivate() {
    print('deactivate+++');
    super.deactivate();
  }

  @override
  void dispose() {
    print('dispose+++');
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我是 B 頁'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('返回首頁'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

Output of debug

Launching lib\main.dart on Android SDK built for x86 in debug mode...
Running Gradle task 'assembleDebug'...
√  Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app.apk...
Debug service listening on ws://127.0.0.1:52084/zak3O5cjSnk=/ws
Syncing files to device Android SDK built for x86...
D/EGL_emulation(25984): eglCreateContext: 0xf1820a00: maj 2 min 0 rcv 2
D/EGL_emulation(25984): eglCreateContext: 0xf18211e0: maj 2 min 0 rcv 2
D/HostConnection(25984): HostConnection::get() New Host Connection established 0xf1828f70, tid 26038
D/HostConnection(25984): HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_direct_mem ANDROID_EMU_host_composition_v1 ANDROID_EMU_host_composition_v2 ANDROID_EMU_vulkan ANDROID_EMU_deferred_vulkan_commands ANDROID_EMU_vulkan_null_optional_strings ANDROID_EMU_vulkan_create_resources_with_requirements ANDROID_EMU_YUV_Cache ANDROID_EMU_vulkan_ignored_handles ANDROID_EMU_has_shared_slots_host_memory_allocator ANDROID_EMU_vulkan_free_memory_sync ANDROID_EMU_vulkan_shader_float16_int8 ANDROID_EMU_vulkan_async_queue_submit ANDROID_EMU_sync_buffer_data ANDROID_EMU_read_color_buffer_dma GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_2 
D/EGL_emulation(25984): eglMakeCurrent: 0xf18211e0: ver 2 0 (tinfo 0xf1b5ec10) (first time)
I/flutter (25984): initState+++
I/WM-WorkerWrapper(25984): Worker result FAILURE for Work [ id=eaf19926-15cd-4ba9-8858-ab8ed99182aa, tags={ be.tramckrijte.workmanager.BackgroundWorker } ]

Output of flutter doctor -v

[√] Flutter (Channel stable, 2.10.1, on Microsoft Windows [Version 10.0.19043.1466], locale zh-TW)
    • Flutter version 2.10.1 at C:\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision db747aa133 (6 days ago), 2022-02-09 13:57:35 -0600
    • Engine revision ab46186b24
    • Dart version 2.16.1
    • DevTools version 2.9.2

[√] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
    • Android SDK at C:\Users\USER\AppData\Local\Android\sdk
    • Platform android-32, build-tools 32.0.0
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 11.0.11+9-b60-7590822)
    • All Android licenses accepted.

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

[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.0.5)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.0.32112.339
    • Windows 10 SDK version 10.0.19041.0

[√] Android Studio (version 2021.1)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+9-b60-7590822)

[√] Connected device (4 available)
    • Android SDK built for x86 (mobile) • emulator-5554 • android-x86    • Android 11 (API 30) (emulator)
    • Windows (desktop)                  • windows       • windows-x64    • Microsoft Windows [Version 10.0.19043.1466]
    • Chrome (web)                       • chrome        • web-javascript • Google Chrome 98.0.4758.82
    • Edge (web)                         • edge          • web-javascript • Microsoft Edge 98.0.1108.43

[√] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
absar commented 2 years ago

Check if below workaround from https://github.com/flutter/flutter/issues/98473#issuecomment-1041895729 fixes the issue

Thanks for filing this; I've filed #98591 for the general problem (which we weren't aware of when updating the plugins).

While we investigate whether we can adjust Flutter to handle this automatically in the future, here's a workaround that should allow using the current versions of the plugins:

  • Add dependencies on shared_preferences_android and shared_preferences_ios.
  • At the beginning of your background isolate entry point, add something like:
    if (Platform.isAndroid) SharedPreferencesAndroid.registerWith();
    if (Platform.isIOS) SharedPreferencesIOS.registerWith();
mohammedsalem97 commented 2 years ago

@absar i didn't get the solution yet! please explain it

mathiasgodwin commented 1 year ago

@mohammedsalem97 something like this.

void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async{
   if (Platform.isAndroid) SharedPreferencesAndroid.registerWith(); // here
   if (Platform.isIOS) SharedPreferencesIOS.registerWith(); // and here

    switch (task) {
      case myTask:

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

            try { //add code execution
              totalExecutions = await prefs.getInt("totalExecutions");
              // prefs.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);
            }

          break;
        case Workmanager.iOSBackgroundTask:
          print("iOS background fetch delegate ran");
          break;
      }

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

The callback above runs in a different Isolate, while some plugins initialization is straight forward as when used in the main Isolate, some might require extra steps to work properly. You should use DartPluginRegistrant.ensureInitialized(); // Initialize dependency When working with plugin in an isolate as well to be on a safer side.