flutter_workmanager icon indicating copy to clipboard operation
flutter_workmanager copied to clipboard

🐞 Workmanager not working with path_provider on iOS background fetch (MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider))

Open brunodmn opened this issue 3 years ago • 10 comments

  • [x] I have read the README
  • [x] I have done the setup for Android
  • [x] I have done the setup for iOS
  • [x] I have ran the sample app and it does not work there

Version

Technology Version
Workmanager version 0.4.1
Xcode version 13.2.1
Swift version 5
iOS deployment target 10

Describe the error Trying to use path_provider with workmanager on iOS. In my mainframe I can inject and use the path_provider, but when I trigger it from workmanager it wont work at all. Already tried flutter clean/get, flutter pub cache repair, close and reopen emulator and IDE..nothing works.

Here is a minimum code to reproduce: link 1 - created new flutter project 2 - added packages workamanager/path_provider 3 - initialized workmanager and setup iOS especific configuration 4 - opened xcode, ran the project then selected debug>simulate background fetch 5 - expected to see successful return with path created, but actually see MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)

Output of flutter doctor -v [✓] Flutter (Channel stable, 2.10.2, on macOS 12.1 21C52 darwin-arm, locale en-BR) • Flutter version 2.10.2 at /Users/brunoandrade/Dev/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 097d3313d8 (2 weeks ago), 2022-02-18 19:33:08 -0600 • Engine revision a83ed0e5e3 • Dart version 2.16.1 • DevTools version 2.9.2

[!] Android toolchain - develop for Android devices (Android SDK version 31.0.0) • Android SDK at /Users/brunoandrade/Library/Android/sdk • Platform android-31, build-tools 31.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165) ! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1) • Xcode at /Applications/Xcode.app/Contents/Developer • CocoaPods version 1.11.2

[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2020.3) • Android Studio at /Applications/Android Studio.app/Contents • 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.10+0-b96-7281165)

[✓] VS Code (version 1.65.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.36.0

brunodmn avatar Mar 04 '22 19:03 brunodmn

Check comment https://github.com/fluttercommunity/flutter_workmanager/issues/360#issuecomment-1043171712 You can do the same workaround with path provider, till flutter and dart team fixes the actual issue 98591 in flutter repo. Add in your pubspec.yaml:

path_provider_android: ^2.0.12 path_provider_ios: ^2.0.8

Add in your workmanager callback:

if (Platform.isAndroid) PathProviderAndroid.registerWith(); if (Platform.isIOS) PathProviderIOS.registerWith();

absar avatar Mar 05 '22 20:03 absar

Check comment #360 (comment) You can do the same workaround with path provider, till flutter and dart team fixes the actual issue 98591 in flutter repo. Add in your pubspec.yaml:

path_provider_android: ^2.0.12 path_provider_ios: ^2.0.8

Add in your workmanager callback:

if (Platform.isAndroid) PathProviderAndroid.registerWith(); if (Platform.isIOS) PathProviderIOS.registerWith();

It did work for me! Thank you very much. Where should it be put by default so user does not need to do it manually? On path_provider package?

brunodmn avatar Mar 07 '22 13:03 brunodmn

I can't make it work on iOS. On Android everything is fine but on iOS I always get the following error:

MissingPluginException(No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider_ios)<…>

Here is what I use:

In my pubspec.yaml

  path_provider: ^2.0.9
  path_provider_android: ^2.0.12
  path_provider_ios: ^2.0.8
  workmanager: ^0.5.0-dev.8

import 'package:path_provider_android/path_provider_android.dart';
import 'package:path_provider_ios/path_provider_ios.dart';

void callbackDispatcher() {
  if (Platform.isAndroid) PathProviderAndroid.registerWith();
  if (Platform.isIOS) PathProviderIOS.registerWith();

  Workmanager().executeTask((task, inputData) async {
    Logger().d("Native called background task");
    try {
      var dir = await getApplicationDocumentsDirectory(); // <-- NEVER PASSES AFTER THIS LINE.
      Logger().d("dir=${dir.path}");
    } on Exception catch(error){
      Logger().e(error);
    }
    return Future.value(true);
  });
}

Workmanager initialization:

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

What am I doing wrong, because

if (Platform.isAndroid) PathProviderAndroid.registerWith();
if (Platform.isIOS) PathProviderIOS.registerWith();

does NOT seem to work?

sirmamedical avatar Mar 08 '22 09:03 sirmamedical

@sirmamedical, if you try with getTemporaryDirectory() instead of getApplicationDocumentsDirectory(), you get same results? Did you finish and started application instead of hot reload? Did you run flutter clean / flutter pub get after change?

brunodmn avatar Mar 08 '22 19:03 brunodmn

@brunodmn I haven't tried with getTemporaryDirectory() because I need getApplicationDocumentsDirectory() in order to use Drift plugin from the background task and the initial issue happened when I called a db query.

I checked then that a simple call of getApplicationDocumentsDirectory() without any db usage causes the same error.

I did flutter clean and flutter pub get many times. I tested the app on a real device using the Simulate background fetch from XCode debug.

I will check what will be behaviour when I use getTemporaryDirectory() instead, in the background, although even it will work it will not solve my problem with Drift, because it needs getApplicationDocumentsDirectory(). I will let you know what the result is.

sirmamedical avatar Mar 10 '22 06:03 sirmamedical

Hi @sirmamedical, if works with temporary directory might be something with permission to access files on device, which you could try to ask permission on first run, before initializing the Workmanager. I noticed that you are using a pre-release version, you could also try with published stable version of the package. I hope you can make it work

brunodmn avatar Mar 10 '22 12:03 brunodmn

I have the same issue when trying to work with hive any workaround. and @brunodmn did you get any solution I have been working on this for two days

BrianMwas avatar Apr 08 '22 09:04 BrianMwas

I have the same issue when trying to work with hive any workaround. and @brunodmn did you get any solution I have been working on this for two days

Hi Brian,

With hive you could try #360.

  1. Add packages path_provider_android and path_provider_ios
  2. Add bellow snipet into your callbackdispatcher (before initializing hive):
 if (Platform.isAndroid) PathProviderAndroid.registerWith();
 if (Platform.isIOS) PathProviderIOS.registerWith();

brunodmn avatar Apr 08 '22 12:04 brunodmn

Can you please try this branch / PR https://github.com/fluttercommunity/flutter_workmanager/pull/388 and let me know whether it solves the problem?

ened avatar May 15 '22 12:05 ened

for me it looks like the problem still exists.

void uploadUserData() {  
  if (Platform.isAndroid) PathProviderAndroid.registerWith();  
  if (Platform.isIOS) PathProviderIOS.registerWith();  
  Workmanager().executeTask((task, inputData) async {  
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );
    MyRepository().syncUploadFiles();
}

Doppelklick avatar Aug 29 '22 18:08 Doppelklick

@ened I tried that branch and doesn't seem to fix the issue. Tested another plugin that implements the DartPluginRegistrant.ensureInitialized() method and it seems to work. This is the plugin: https://pub.dev/packages/flutter_background_service

Maybe it helps you realize what works incorrectly here. I also tried to call those methods by myself and still it doesn't work

droidpl avatar Oct 16 '22 18:10 droidpl

Please retry using the latest version 0.5.1

ened avatar Oct 21 '22 20:10 ened