objectbox / objectbox-dart

Flutter database for super-fast Dart object persistence
https://docs.objectbox.io/getting-started
Apache License 2.0
927 stars 115 forks source link

libobjectbox-jni.so not found on Android 6 and older #369

Closed alsoLut closed 3 months ago

alsoLut commented 2 years ago

Invalid argument(s): Failed to load dynamic library 'libobjectbox-jni.so': dlopen failed: library "libobjectbox-jni.so" not found

greenrobot-team commented 2 years ago

Thanks, but I can't reproduce this (using Android emulator). Could you share more details about the project, maybe even a small example project? Also what devices are you trying to run it on?

greenrobot-team commented 2 years ago

Closing this issue due to inactivity. :zzz: Feel free to comment with more details or submit a new issue.

quewen08 commented 1 year ago

I have same question in android Marshmallow(API 23) device Here is my option:

app/build.gradle

android {
...
    sourceSets {
        main() {
            java.srcDirs += 'src/main/kotlin'
            jni.srcDirs = []
            jniLibs.srcDirs = ['libs']
            res.srcDirs = ['src/main/res']
        }
    }

    defaultConfig {
        ...
        ndk {
            abiFilters 'arm64-v8a', 'x86_64', 'armeabi-v7a'
        }     
        ...
    }
...
}

flutter doctor

[√] Flutter (Channel unknown, 2.10.5, on Microsoft Windows [Version 10.0.19044.1741], locale zh-CN)
    • Flutter version 2.10.5 at
    • Upstream repository unknown
    • Framework revision 5464c5bac7 (8 weeks ago), 2022-04-18 09:55:37 -0700
    • Engine revision 57d3bac3dd
    • Dart version 2.16.2
    • DevTools version 2.9.2
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn
[√] Android Studio (version 2021.2)
    • 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.12+7-b1504.28-7817840)

......
dependencies:
  ......
  #db
  objectbox: ^1.5.0
  objectbox_flutter_libs: any
  ......

dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^1.0.0
  build_runner: ^2.1.11
  objectbox_generator: any
......

// splash_controller.dart
......
  @override
  void onReady() {
    super.onReady();
   ...
   _store = await openStore().catchError((e) {
        throw e;
    });
   ...
  }
......

I/flutter (17898): Failed to load ObjectBox library. For Flutter apps, check if objectbox_flutter_libs is added to dependencies. For unit tests and Dart apps, check if the ObjectBox library was downloaded (https://docs.objectbox.io/getting-started).
E/flutter (17898): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Invalid argument(s): Failed to load dynamic library 'libobjectbox-jni.so': dlopen failed: library "libobjectbox-jni.so" not found
E/flutter (17898): #0      _open (dart:ffi-patch/ffi_dynamic_library_patch.dart:12:43)
E/flutter (17898): #1      new DynamicLibrary.open (dart:ffi-patch/ffi_dynamic_library_patch.dart:23:12)
E/flutter (17898): #2      _tryObjectBoxLibFile (package:objectbox/src/native/bindings/bindings.dart:77:29)
E/flutter (17898): #3      loadObjectBoxLib (package:objectbox/src/native/bindings/bindings.dart:94:12)
E/flutter (17898): #4      C (package:objectbox/src/native/bindings/bindings.dart:112:27)
E/flutter (17898): #5      C (package:objectbox/src/native/bindings/bindings.dart)
E/flutter (17898): #6      new Model (package:objectbox/src/native/model.dart:19:31)
E/flutter (17898): #7      new Store (package:objectbox/src/native/store.dart:117:21)
E/flutter (17898): #8      openStore (package:xxxxxx/objectbox.g.dart:276:5)
E/flutter (17898): <asynchronous suspension>
E/flutter (17898): #9      SplashController.onReady.<anonymous closure> (package:xxxxxx/pages/splash/splash_controller.dart:30:16)
E/flutter (17898): <asynchronous suspension>
E/flutter (17898): 
greenrobot-team commented 1 year ago

@quewen08 Can you analyze your APK or AAB file (e.g. open it with Android Studio) and make sure the libobjectbox-jni.so exists?

quewen08 commented 1 year ago

Sure I have image

greenrobot-team commented 1 year ago

This appears to be an issue on Android 6 and older and can possibly be solved by loading the library in Java, then trying again to load the library in Dart: https://github.com/simolus3/drift/issues/895

Now I also see why https://github.com/objectbox/objectbox-dart/pull/328 makes sense (though would not do this for all devices, only if users actively call a workaround method, e.g. like sqlite3_flutter_libs or if the code could detect it's running on Android 6 or older).

@quewen08 Can you check what version of the Android Gradle Plugin is used in your project? And maybe try updating to the latest version? Are you building APKs or App Bundles? I remember the Gradle plugin receiving some fixes so native libraries are extracted on Android 6 devices, which should avoid this issue.

quewen08 commented 1 year ago

I think my gradle version is enough

android/build.gradle

buildscript{
...
    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
...
}

gradle/wrapper/gradle-wrapper.properties

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
greenrobot-team commented 1 year ago

@quewen08 Version 7.1.2 looks recent enough.

You may try the suggestion about targeting Android 6.0 in the warning at https://docs.flutter.dev/deployment/android#building-the-app-for-release

quewen08 commented 1 year ago

@quewen08 Version 7.1.2 looks recent enough.

You may try the suggestion about targeting Android 6.0 in the warning at https://docs.flutter.dev/deployment/android#building-the-app-for-release

Hum, it seems useless. I tried add android.bundle.enableUncompressedNativeLibs=false in android/gradle.properties ,then I checked the AndroidManifest.xml, make sure it does not has android:extractNativeLibs=false in the <application> tag. And then I run it on my device, it also cannot get the libobjectbox-jni.so.

greenrobot-team commented 1 year ago

@quewen08 Thanks for trying! Then we probably have to add the workaround as described in my previous comment to a future release.

(Note for me: see internal issue for details.)

mdpe-ir commented 1 year ago

I had the same problem and I solved it:

edit :

import 'objectbox.g.dart'; // created by `flutter pub run build_runner build`

class ObjectBox {
  /// The Store of this app.
  late final Store store;

  ObjectBox._create(this.store) {
    // Add any additional setup code, e.g. build queries.
  }

  /// Create an instance of ObjectBox to use throughout the app.
  static Future<ObjectBox> create() async {
    // Future<Store> openStore() {...} is defined in the generated objectbox.g.dart
    final store = await openStore();
    return ObjectBox._create(store);
  }
}

and changed it to :

 /// Create an instance of ObjectBox to use throughout the app.
  static Future<ObjectBox> create() async {
    try {
      final store = await openStore();
      return ObjectBox._create(store);
    } catch (e) {
      PackageInfo packageInfo = await PackageInfo.fromPlatform();
      DynamicLibrary.open("/data/data/${packageInfo.packageName}/lib/libobjectbox-jni.so");
      final store = await openStore();
      return ObjectBox._create(store);
    }
  }

--

What happened?

Well, if libobjectbox-jni.so could not load by https://github.com/objectbox/objectbox-dart/blob/main/flutter_libs/android/src/main/java/io/objectbox/objectbox_flutter_libs/ObjectboxFlutterLibsPlugin.java , DynamicLibrary.open("/data/data/${packageInfo.packageName}/lib/libobjectbox-jni.so"); will be load it manually with dart:ffi.

mariovitor commented 1 year ago

https://github.com/objectbox/objectbox-dart/issues/369#issuecomment-1198281930

didnt work here

kennir commented 1 year ago

https://github.com/objectbox/objectbox-dart/issues/369#issuecomment-1198281930

sorry, did not work, the app stuck on second load

greenrobot-team commented 1 year ago

@mariovitor @kennir Are both of you trying to work with Android 6 devices? If not, could you please share what devices you are trying this on?

mariovitor commented 1 year ago

@mariovitor @kennir Are both of you trying to work with Android 6 devices? If not, could you please share what devices you are trying this on?

Yes, Android 6 device. I fixed using Kotlin

In MainActivity.kt:

class MainActivity: FlutterActivity() {
    private val CHANNEL = "native_lib_dir"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
                call, result ->
            if (call.method == "loadNativeLibrary") {

                try {
                    System.loadLibrary("objectbox-jni")
                    result.success("ok")
                } catch (e: Throwable){
                    result.error("error on loading ${e.toString()}",null, null)
                }
            } else {
                result.notImplemented()
            }
         }
      }
   }

created a method

loadNativeObjBoxLib() async {
     const channel = MethodChannel("native_lib_dir");
    return await channel.invokeMethod("loadNativeLibrary");
  }

Put openStore() in a try/catch


Future<void> create() async {
      try {
      store = await openStore();
      } catch (e) {

        if (Platform.isAndroid) {
          try {
          await loadNativeObjBoxLib();
          store = await openStore();
          } catch (e) {
          log('error on object box objectbox $e');
          }
          } else {
          log('error on object box objectbox $e');
          }
        }
       }
kennir commented 1 year ago

@mariovitor @kennir Are both of you trying to work with Android 6 devices? If not, could you please share what devices you are trying this on?

No, this is an android 5.1 device, I will try @mariovitor's solution later

ChickenF622 commented 1 year ago

I'm experiencing the same issue Basic info (please complete the following information):

ObjectBox version: 1.7.2
Flutter/Dart SDK: 3.7.7
Null-safety enabled: yes 
Reproducibility: always
OS: Android 13
Device/Emulator: ASUS Zenfone 8

My dependencies

environment:
  sdk: '>=2.18.5 <3.0.0'

dependencies:
  flutter:
    sdk: flutter

  awesome_select: ^6.0.0
  permission_handler: ^10.2.0
  flutter_contacts: ^1.1.5+1
  objectbox: ^1.7.2
  objectbox_flutter_libs: any
  enough_icalendar: ^0.13.0
  workmanager: ^0.5.1
  intl: ^0.17.0
  rrule: ^0.2.10

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.3.3
  flutter_lints: ^2.0.0
  mockito: ^5.3.2
  objectbox_generator: ^1.7.2
  faker: ^2.0.0
mariovitor commented 1 year ago

I'm experiencing the same issue Basic info (please complete the following information):

ObjectBox version: 1.7.2
Flutter/Dart SDK: 3.7.7
Null-safety enabled: yes 
Reproducibility: always
OS: Android 13
Device/Emulator: ASUS Zenfone 8

My dependencies

environment:
  sdk: '>=2.18.5 <3.0.0'

dependencies:
  flutter:
    sdk: flutter

  awesome_select: ^6.0.0
  permission_handler: ^10.2.0
  flutter_contacts: ^1.1.5+1
  objectbox: ^1.7.2
  objectbox_flutter_libs: any
  enough_icalendar: ^0.13.0
  workmanager: ^0.5.1
  intl: ^0.17.0
  rrule: ^0.2.10

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.3.3
  flutter_lints: ^2.0.0
  mockito: ^5.3.2
  objectbox_generator: ^1.7.2
  faker: ^2.0.0

https://github.com/objectbox/objectbox-dart/issues/369#issuecomment-1313966095

greenrobot-team commented 1 year ago

@ChickenF622 Loading the library should not longer fail due to the reasons above on Android 13. It is more likely that you

ChickenF622 commented 1 year ago

Found the issue. I was excluding the files from the debug build. I think I was halfway through trying to configure the admin, and stopped halfway through. Removing the below code, in my /android/app/build.gradle, fixed the issue.

configurations {
    debugImplementation {
        exclude group: 'io.objectbox', module: 'objectbox-android'
    }
}
greenrobot-team commented 11 months ago

I just released a preview release objectbox: ^2.1.1-dev.2 which contains a new loadObjectBoxLibraryAndroidCompat() method in objectbox_flutter_libs (and objectbox_sync_flutter_libs).

If you are affected, it would help us if you could test if calling it before using any ObjectBox APIs resolves this issue on Android 6 devices (or older). E.g. something like:

Future<void> main() async {
  // This is required so ObjectBox can get the application directory
  // to store the database in.
  WidgetsFlutterBinding.ensureInitialized();

  // Fix to load library on Android 6 devices (or older)
  loadObjectBoxLibraryAndroidCompat();
  objectbox = await ObjectBox.create();

  runApp(const MyApp());
}

If successful, we might consider calling this by default when e.g. using the openStore helper method for Flutter apps (it will only run on Android 6 or older devices).

Tumist76 commented 9 months ago

@greenrobot-team, hello! We are affected by this issue and tried to switch to 2.1.1-dev.2. I can tell for now that during coarse testing we've encountered no issues. We'd like to handle the issue but we don't want to use a non-release version. Could you please tell when you're planning to make a new release this this fix included?

greenrobot commented 9 months ago

If successful, we might consider calling this by default when e.g. using the openStore helper method for Flutter apps (it will only run on Android 6 or older devices).

@Tumist76 and others: do you think that's worth that we put in some effort to call this automatically? (I'm a bit surprised to see Android 6 is still supported by app devs.)

Tumist76 commented 9 months ago

@Tumist76 and others: do you think that's worth that we put in some effort to call this automatically? (I'm a bit surprised to see Android 6 is still supported by app devs.)

If there isn't any downsides, I think it'll be better to call this automatically so library usage is identical for those who support Android 6 and for those who don't.

As for Android 6 support altogether - well, it's not like we want to support it, but it still has userbase so we're trying to cover it :)

greenrobot commented 9 months ago

Just curious, what's the percentage of your users on Android 6?

Tumist76 commented 9 months ago

Really sorry, but I can't disclose this info. Let's just say that'll probably be cheaper to buy these users newer phones than for us to support Android 6 :)

greenrobot-team commented 9 months ago

We have released version 2.2.0 which includes the compat method mentioned above. Please update using flutter pub upgrade (or dart pub upgrade for Dart Native projects).

Let us know if this fixes the issue on Android 6 and 5 devices. If so, we will consider calling the compat method automatically on these devices in a future release.

Tumist76 commented 9 months ago

Thank you for fast release! We've updated our app to use 2.2.0 in test environments. I'll let you know in about a week, if everything's okay after testing.

Tumist76 commented 9 months ago

Reporting back. We've passed the tests everything's fine on both Android 6.0 and later versions. We didn't test <Android 6.0 though.

greenrobot-team commented 3 months ago

With the latest release (2.5.0) the workaround is called automatically when using the generated openStore() helper (requires to re-run dart run build_runner build). In this case you can remove the duplicate call from your code.