Realm projects with native dependencies.

466 views
Skip to first unread message

Pablo Meier

unread,
Oct 9, 2014, 4:02:58 PM10/9/14
to realm...@googlegroups.com
Hey friends!

I'm having trouble with my project that uses native dependencies. My project has a structure of the form

```
build.gradle
libs/
     something.jar
src/
    main/
        jniLibs/
            armeabi/
                libsomething.so
            x86/
                libsomething.so
...
```

Which built and ran correctly with my build.gradle file for the life of the project. Since adding Realm, however, while the project compiles and produces an APK, when `something.jar` requires its native component, the app crashes with 

```
java.lang.UnsatisfiedLinkError: Couldn't load something from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.app.dev-1.apk
                           "],nativeLibraryDirectories=[/data/app-lib/com.example.app.dev-1, /vendor/lib, /system/lib]]]: findLibrary returned null
```

I've found the injection point to be when I added Realm to the project (0.70), which took some meddling with the settings since Realm instructions used a new Android Studio project (with an `app/` directory) rather than adding to an existing (mine was modeled after projects like u2020 and deckard-gradle). I've since upgraded to 0.71, hoping the single-jar distribution would "bring it back," but to no avail.

My questions, then: any guesses on where to look? The *.so file is contained in the *.apk file that gets built, and knowing only so much about the Android build process and Gradle, I'm at a complete loss to know what failed here. Most searches for that exception result in old versions of Gradle requiring hacks accept a native component, before `jniLibs`.

Shot in the dark, but any help would be appreciated. Thanks again for your time and the library, hope you're all well ^_^

-Pablo

Emanuele Zattin

unread,
Oct 9, 2014, 4:25:00 PM10/9/14
to Pablo Meier, realm-java
Hello Pablo,

can you please post your build.gradle files? Thank could help in looking in the right direction.

BR,

Emanuele

--
You received this message because you are subscribed to the Google Groups "Realm Java" group.
To unsubscribe from this group and stop receiving emails from it, send an email to realm-java+...@googlegroups.com.
To post to this group, send email to realm...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/realm-java/764755e5-8459-4cdc-8271-167134547b99%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Pablo Meier

unread,
Oct 9, 2014, 4:43:16 PM10/9/14
to Emanuele Zattin, realm-java
Sure! The build.gradle is appended below.

FWIW, I'm mostly suspicious of anything to do with .iml files and the .idea directory, given that's what I know least about. As mentioned in the previous email, the project structure wasn't the same as the Realm .70 docs with `/app` being toplevel.

Also don't know if it's worth noting the discrepancy that in my APK, the native library is in (after unzipping) `/lib/armeabi/something.so` but the exception thrown is looking in, among other places, `/data/app-lib/com.example.app.dev-1`, which looks like a toplevel directory. Could that be getting reset somewhere incorrectly?

Thanks again, let me know if there's anything else I can provide! :D

-Pablo

```
buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:0.12.+'
    classpath 'com.stanfy.spoon:spoon-gradle-plugin:0.10.0'
    classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+'
  }
}

// Manifest version information!
def versionMajor = 1
def versionMinor = 9
def versionPatch = 0
def versionBuild = 0
def versionFunName = "Marine"

apply plugin: 'android-sdk-manager'
apply plugin: 'android'
apply plugin: 'spoon'

allprojects {
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
        }
    }
}

repositories {
  mavenCentral()
}

dependencies {
  compile 'com.jakewharton:butterknife:5.1.2'
  compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'

  compile 'com.squareup.retrofit:retrofit:1.6.1'
  debugCompile 'com.squareup.retrofit:retrofit-mock:1.6.1'

  compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
  compile 'com.squareup.okhttp:okhttp:2.0.0'

  compile 'com.android.support:support-v4:20.0.0'
  compile 'com.google.android.gms:play-services:5.0.89'

  compile fileTree(dir: 'libs', include: '*.jar')

  compile group: 'com.google.guava', name: 'guava', version: '12.0'

  provided ('com.squareup.dagger:dagger-compiler:1.2.2') {
    exclude group: 'com.squareup.dagger', module: 'dagger'
    exclude group: 'com.google.guava', module: 'guava'
  }
  compile ('com.squareup.dagger:dagger:1.2.2') {
    exclude group: 'com.google.guava', module: 'guava'
  }

  compile 'com.squareup.picasso:picasso:2.3.4'

  compile 'com.nineoldandroids:library:2.4.0'

  compile 'com.jakewharton.timber:timber:2.4.+'

  compile 'com.squareup:otto:1.3.5'

  compile 'com.soundcloud.android:android-crop:0.9.10@aar'

  compile 'net.danlew:android.joda:2.4.0'

  androidTestCompile ('com.jakewharton.espresso:espresso:1.1-r3'){
    exclude group: 'com.squareup.dagger', module: 'dagger'
    exclude group: 'com.google.guava', module: 'guava'
    exclude group: 'org.hamcrest', module: 'hamcrest-integration'
    exclude group: 'com.google.code.findbugs', module: 'jsr305'
    exclude group: 'com.android.support', module: 'support-v4'
  }
  androidTestCompile ('com.jakewharton.espresso:espresso-support-v4:1.1-r3') {
    exclude group: 'com.squareup.dagger', module: 'dagger'
    exclude group: 'com.google.guava', module: 'guava'
    exclude group: 'org.hamcrest', module: 'hamcrest-integration'
    exclude group: 'com.google.code.findbugs', module: 'jsr305'
    exclude group: 'com.android.support', module: 'support-v4'
  }
  androidTestCompile 'com.squareup.spoon:spoon-client:1.1.0'
}

def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
def buildTime = new Date().format("yyyy-MM-dd'T'HH:mm'Z'", TimeZone.getTimeZone("UTC"))

def isTravis = "true".equals(System.getenv("TRAVIS"))
def preDexEnabled = "true".equals(System.getProperty("pre-dex", "true"))

android {
  compileSdkVersion 20
  buildToolsVersion "19.1.0"

  dexOptions {
    // Skip pre-dexing when running on Travis CI or when disabled via -Dpre-dex=false.
    preDexLibraries = preDexEnabled && !isTravis
  }

  defaultConfig {
    minSdkVersion 10
    targetSdkVersion 20

    versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
    versionName "${versionMajor}.${versionMinor}.${versionPatch} -- ${versionFunName}"

    buildConfigField "String", "GIT_SHA", "\"${gitSha}\""
    buildConfigField "String", "BUILD_TIME", "\"${buildTime}\""

    testApplicationId 'com.example.product.test'
    testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
    testHandleProfiling true
    testFunctionalTest true

    packagingOptions {
      exclude 'LICENSE.txt'
      exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
  }

  buildTypes {
    release {
      runProguard false
    }
    debug {
      applicationIdSuffix '.dev'
      versionNameSuffix '-dev'
    }
  }

  lintOptions {
    abortOnError false
    disable 'InvalidPackage'
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
  }
}
```

--

Emanuele Zattin

unread,
Oct 10, 2014, 4:22:02 AM10/10/14
to Pablo Meier, realm-java
I can see Realm is not among your dependency. Are you simply putting the jar file in the libs folder?

Gauthier Butel

unread,
Oct 10, 2014, 4:49:31 AM10/10/14
to realm...@googlegroups.com, pa...@look-see.com
Hi Paolo,

I had to face the same issue with one of my project while trying to integrate Realm.

I'm not sure this is a good solution or if your problem is related to this, but you could try to add a armeabi-v7a folder inside jniLibs containing the same content as the already present armeabi folder.

It appears that Realm also relies on native libraries for four different types of processors (armeabi, armeabi-v7a, x86 and mips), so my guess is that as the native library you use is not also in the jniLibs/armeabi-v7a folder, something got screwed up during the build of the application.
What you should try also is, if you have one at your disposal, building the application on a x86 device without making any change.

I'm not a Gradle expert, so maybe I've missed something too during this integration of different native libraries, but at least this solution enabled me to run my application without crash on a armeabi-v7a processor device.

Hope this will help you,

Regards,

Gauthier Butel

Pablo Meier

unread,
Oct 10, 2014, 8:39:23 AM10/10/14
to Gauthier Butel, realm-java
Hi Gauthier,

I haven't been able to test this, but I think this may be exactly the issue -- the native library the system can't find is only available in `armeabi` and `x86` with no `armeabi-v7a` variant, whereas Realm includes `libtightdb-jni.so` in many variants, and I discovered this on an armeabi-v7a device. While the APK I'm installing contains all the necessary .so files, if the device is an armeabi-v7a device and sees its primary folder, I believe it's only looking there for .so files, assuming they're there for all libraries, rather than using a secondary as a fallback.

I found this explanation last night on how Android loads .so files depending on Android version, device type, and what is in the APK, and it looks like a process where this type of mix-up can happen.

I also finally found the correct incantation to Google to return results where others seem to have run into similar types of issues. I wanted to test the theory before writing back to the list, but you beat me to it ;)

I'll write back if this solves the problem, as well as contact the vendors of the other library to let them know how this can happen. Thanks again! With any luck this case will be found by others who Google the exception type who run into a similar issue :D

-Pablo

Pablo Meier

unread,
Oct 10, 2014, 11:14:56 AM10/10/14
to Gauthier Butel, realm-java
Just writing to close the loop -- that was the issue! Realm is TOO GOOD and provides binaries for both armeabi and armeabi-v7a, so if you're relying on a library that only provides one and the device scans another, for certain versions of Android it will fail to load it.

Thanks for all your help and patience, everyone :D

-Pablo
Reply all
Reply to author
Forward
0 new messages