App Bundle, split APKs and Multidex

On specific devices or if your app uses the App Bundle format, the legacy split APK feature or Multidex you might observe crashes due to UnsatisfiedLinkError or LinkageError (since ObjectBox 2.3.4).

This can have various causes and there exist multiple workarounds. Let us know if you have more info on this in GitHub issue 605.

Buggy devices

On some devices loading the native library may fail due to bugs. To counter this ObjectBox includes support for the ReLinker tool which will try to extract the native library manually if loading it normally fails.

To set this up add ReLinker to your dependencies:

implementation 'com.getkeepsafe.relinker:relinker:1.3.1'

ObjectBox is calling ReLinker via reflection. If you are using ProGuard or Multidex, make sure to add keep rules so that ReLinker code is not stripped from the final app or is not in the primary dex file.

For ProGuard add this line:

-keep class com.getkeepsafe.relinker.** { *; }

For Multidex add a multiDexKeepProguard file to your build file:

android {
buildTypes {
release {
multiDexKeepProguard file('multidex-config.pro')
}
}
}

And in the multidex-config.pro file add the same rule as above:

-keep class com.getkeepsafe.relinker.** { *; }

Multidex supports two file formats to keep files. We are using the ProGuard format (multiDexKeepProguard property). You can also use the multiDexKeepFile property, but make sure to adapt the rule above to that format.

Enable ReLinker debug log

To enable debug logs for ReLinker you can pass a custom ReLinkerInstance when building BoxStore:

boxStore = MyObjectBox.builder()
.androidContext(App.this)
.androidReLinker(ReLinker.log(new ReLinker.Logger() {
@Override
public void log(String message) { Log.d(TAG, message); }
}))
.build();

App Bundle and split APKs

Using App Bundle or split APKs will cause Google Play to only deliver the native libraries required for the architecture (ABI) of the user device. Users then might share their version of the app with others ("side-loading"). If they force install your app onto a device with an incompatible architecture (ABI) it will crash, as the native library loader can not find a compatible library version.

We know of two workarounds to avoid this.

Alternative: turn off splitting by ABI

The simplest solution is to always include native libraries for all supported ABIs. However, this will increase the download size of your app for all users.

android {
bundle {
abi {
// This property is set to true by default.
enableSplit = false
}
}
}

Source: Android Developers

Alternative: Catch exception and inform users

You can guard the MyObjectBox build call and for example display an activity with an info message (e.g. direct users to download the app directly from Google Play, send you an error report, ...):

// guard the build call and set some flag (here setting the boxStore field null)
try {
boxStore = MyObjectBox.builder()
.androidContext(context.getApplicationContext())
.build();
} catch (LinkageError e) {
boxStore = null;
Log.e(App.TAG, "Failed to load ObjectBox: " + e.getMessage());
}
// then for example in the main activity check the flag in onCreate and
// direct to an info/error message without the app crashing:
if (ObjectBox.get() == null) {
startActivity(new Intent(this, ErrorActivity.class));
finish();
return;
}

As an example see how we added this to our Android app example.