Flutter access database in background fetch on Android
Asked Answered
A

4

7

I am trying to access the local database on the device while the app is completely closed, to achieve this I am using the sqlite plugin sqflite: ^1.2.0 and the background fetch plugin background_fetch: ^0.4.0.

I am able to register the headless background task with no issues, its when I try to run the background tasks, I get the following error!

The plugins seems to work fine while the app is running, or put into background mode.

Any suggestions please?

Error

[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method getDatabasesPath on channel com.tekartik.sqflite)

Flutter version:

Flutter 1.12.13+hotfix.7 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 9f5ff2306b (11 days ago) • 2020-01-26 22:38:26 -0800
Engine • revision a67792536c
Tools • Dart 2.7.0

Flutter Doctor

[✓] Flutter (Channel stable, v1.12.13+hotfix.7, on Mac OS X 10.15.2 19C57, locale en-GB)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3)
[✓] Android Studio (version 3.5)
[✓] Connected device (1 available)

• No issues found!

Annunciata answered 7/2, 2020 at 17:35 Comment(0)
R
1

You can try looking at sqflite troubleshooting section on their Github page, especially the one related to your error. Let me paste the bits from that page here.

This error is typically a build/setup error after adding the dependency.

  • Try all the steps defined at the top of the documents
  • Make sure you stop the current running application if any
  • Force a flutter packages get
  • Try to clean your build folder flutter clean
  • On iOS, you can try to force a pod install / pod update
  • Search for other bugs in flutter like this, other people face the same issue with other plugins so it is likely not sqflite related

Advanced checks:

Check the GeneratedPluginRegistrant file that flutter run should have generated in your project contains a line registering the plugin.

Android:

SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin"));

iOS:

[SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]];
  • Check MainActivity.java (Android) contains a call to GeneratedPluginRegistrant asking it to register itself. This call should be made from the app launch method (onCreate).
public class MainActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
    }
}
  • Check AppDelegate.m (iOS) contains a call to GeneratedPluginRegistrant asking it to register itself. This call should be made from the app launch method (application:didFinishLaunchingWithOptions:).
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

Before raising this issue, try adding another well established plugin (the simplest being path_provider or shared_preferences) to see if you get the error here as well.

Rectus answered 10/2, 2020 at 1:43 Comment(1)
Hi, thanks for your reply, I have already carried out all the above checks, the plugin works fine when the app is in foreground, the issue is when the app runs in headless mode.Annunciata
B
0

If your case is the same as mine, I have a custom plugin with Kotlin, so I didn't import GeneratedPluginRegistrant.registerWith(this) at the MainActivity. Instead, I implemented it at the start of the configureFlutterEngine() function and it worked perfectly.

import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity : FlutterActivity() {

    private val CHANNEL = "getEpubs"
    var _eventSink: EventChannel.EventSink? = null

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)
}

This registers the generated sqflite plugin access to the database on the device.

(Sorry for the Kotlin code, but you can change it to Java.)

Don't forget to import:

io.flutter.plugins.GeneratedPluginRegistrant
Buckler answered 21/5, 2020 at 15:7 Comment(0)
B
0

This may be because one of the other plugins in your project is failing during plugin registration and preventing other plugins listed below it from being registered.

If you see the line below in your logs,

Tried to automatically register plugins with FlutterEngine @{engine hash appears here} but could not find and invoke the GeneratedPluginRegistrant;

set a break point in GeneratedPluginRegister's registerGeneratedPlugins() static method to see what exception is being thrown.

In my case I was using a plugin that called io.flutter.plugin.common.PluginRegistry.Registrar's activity() method which returns null when there is no foreground activity in the application.

Baldric answered 22/4, 2021 at 18:22 Comment(0)
I
-1

There has been some experiments about using sqflite from a background isolate and I'm not sure about the plugin support here. Anyway the transaction mechanism is not safe across isolate in the same process so I advise using sqflite from the main isolate (it already uses its own thread).

Idyllic answered 12/2, 2020 at 7:30 Comment(1)
Hi, I am trying to run my code in a headless env of the app, so this is a background service that runs every 15 mins, even if the app is closed. background fetch plugin seems to be working fine, I just can't seem to access the Database.Annunciata

© 2022 - 2024 — McMap. All rights reserved.