androidandroid-ndkhyperledger-indy

How to add prebuilt *.so libraries in android studio?


I am trying to integrate the Hyperledger indy SDK. However, when running my code I get the error

E/AndroidRuntime: FATAL EXCEPTION: main
    java.lang.UnsatisfiedLinkError: dlopen failed: library "libgnustl_shared.so" not found
 at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
 at java.lang.System.loadLibrary(System.java:1657)

I am trying to follow the documentation provided in the project repo. I tried using the sample project on this blog .

static{
        System.loadLibrary("indy");
    }
cmake_minimum_required(VERSION 3.4.1)
add_library(indy SHARED IMPORTED)
include_directories(src/main/jniLibs/${ANDROID_ABI}/include)

My gradle file includes:

android{
 defaultconfig{
 ...
    ndk{
            moduleName "indy"
            abiFilters 'armeabi-v7a'
        }
 }
...
 sourceSets {
        main {
            jniLibs.srcDir  'src/main/jniLibs'
        }
    }
    externalNativeBuild {
        cmake {
            path file('../CMakeLists.txt')
        }
    }
}

Still, keep on getting the same error when I launch the app. I am aware that the bash script that builds the libraries on linux uses the android-ndk-r16b-linux-x86_64 tools so I tried downgrading my ndk in android studio to use the same version but had no luck.

The output of the build script is

include/
  indy_anoncreds.h
  indy_core.h
  ...
lib/
  libindy.a
  libindy.so
  libindy_shared.so

How can I use this libraries in my android studio project?


Solution

  • The issue is mainly related to the nature of libraries. Libraries are dynamic in Android and needs to be linked at runtime.

    libindy.so depends on stl, openssl, libsodium and libzmq. You will find libgnustl_shared.so in NDK. All the other needed prebuilt libraries are also available here.

    What you need to do is make sure these libraries are present in the jniLibs folder and load these in order libraries before libindy.

    System.loadLibrary("libgnustl_shared");
    .
    .
    System.loadLibrary("indy");
    

    Alternate approach:

    There is a subproject in Indy where we are using libindy as dependency and we try to create a one fat dynamic library which has all the dependencies. Link

    If you follow the steps like vcx you don't have to have all the dependant libraries in jniLibs as they will be already part of the final .so file

    The command which make one fat dynamic library with all the symbols and dependencies is this (from the link pasted above)

    ${LIBVCX}/target/${CROSS_COMPILE}/release/libvcx.a \
    ${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libz.so \
    ${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libm.a \
    ${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/liblog.so \
    ${LIBINDY_DIR}/libindy.a \
    ${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so \
    ${OPENSSL_DIR}/lib/libssl.a \
    ${OPENSSL_DIR}/lib/libcrypto.a \
    ${SODIUM_LIB_DIR}/libsodium.a \
    ${LIBZMQ_LIB_DIR}/libzmq.a \
    ${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so -Wl,--no-whole-archive -z muldefs