1

I have a Java library for Android which I distribute to third party developers, and I want to embed a C library in it. I've added the library to the project via CMake:

add_library(wrapper SHARED wrap.c)
target_link_libraries(wrapper CLibraryTarget)

To the library's build.gradle I've added:

apply plugin: 'com.android.library'

...

android {
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags ""
                targets "wrapper",
                "CLibraryTarget"
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.0+"
        }
    }
}

In the library, I load the C library with:

public class Wrapper {
  static {
    System.loadLibrary("wrapper");
  }
  ...
}

I'm trying to run a unit test to test some of the Java functions which wrap the C functions, and I get the exception:

java.lang.UnsatisfiedLinkError: no wrapper in java.library.path

    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1871)
...

This works when I'm linking the C library in an App, but doesn't seem to work in a Java library. Why is the library not loaded? What do I need to do to embed the C library in a Java library for distribution? I can't seem to find any documentation specific to this scenario.

Nick
  • 3,958
  • 4
  • 32
  • 47
  • "I have a Java library for Android" -- what Gradle plugin are you using to build this? `java-library` or `com.android.library`? IOW, you trying to create a JAR or an AAR? If the answer is a JAR, that's your problem. – CommonsWare Oct 04 '20 at 18:33
  • `com.android.library` – Nick Oct 04 '20 at 18:39
  • "I'm trying to run a unit test to test some of the Java functions which wrap the C functions" -- have you tried switching this to an instrumented test? I haven't tried unit tests of JNI. Beyond that, double check to confirm that the AAR has your C library embedded in it. – CommonsWare Oct 04 '20 at 18:41
  • The aar does contain the library at `jni//libwrapper.so`, but that is only generated with `assembleRelease`. I haven't tried an instrumented test yet – Nick Oct 04 '20 at 20:40
  • It's also present in `build/intermediates/cmake/debug/obj//libwrapper.so`. – Nick Oct 04 '20 at 20:49
  • 1
    "The aar does contain the library" -- then I would focus on testing the library in an Android environment (instrumented test, scrap app, etc.). IOW, confirm whether the problem is strictly with unit tests or not. – CommonsWare Oct 04 '20 at 21:12

1 Answers1

0

The problem is that JUnit tests run on the host machine, and on macOS that requires a dylib library, which is not built by default. There are approaches which make gradle build this library, although it was still missing from java.library.path, and at that point I realised it was a hack too far for me – while not as fast, it will work correctly if an instrumented test is used instead (just move the test from src/test to src/androidTest).

Nick
  • 3,958
  • 4
  • 32
  • 47