Android JNI, problem with libraries

The goal of this article is to explain how to support “shorcuts” in libraries on Android.

On Linux you have this type of structure
* /lib/x86_64-linux-gnu/libusb-1.0.so -> Link to libusb-1.0.so.0
* /lib/x86_64-linux-gnu/libusb-1.0.so.0 -> Link to libusb-1.0.so.0.1.0
* /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0

I need to support some libraries using this naming convention: x.so.4, where you have the version of the library at the end of the library. When you have multiple libraries and call between the different libraries, you need to be able to support *.so.version.

The problem with android is that you can only deploy a library like {something}.so. You cannot deploy {something}.so.version

As an example liba.so.4, need access to libb.so.5. If you only have liba.so and libb.so, you cannot find libb.so.5.

The secret is to create a symlink on deployement.

Phase 1

Add to your project the libs you want to support. Just install the *.so file: Example: libusb-0.1.so. Take care of copying the real version of the lib in your project, not the shortcut.

As an example, if you only support “armabi”, you can copy them into /libs/armeabi/

Phase 2

Create a static enumeration of the libraries

private static String LIBS[] = new String[] { "libusb-0.1.so.4",
"libiconv.so.2", ...};

Phase 3

Create the symlinks and Load the libraries

private static boolean isLibInit = false;

private void initLib(Activity activity) throws IOException {

if (isLibInit) {
return;
}

File pathLib = new File(activity.getApplicationInfo().nativeLibraryDir);
File pathDest = new File(activity.getFilesDir(), "lnlib");
pathDest.mkdirs();

// We only have the ".so" libs => we need to create a symlink to the
// .so.3, .so.1 name!
// It's what this loop does!
{

for (String f : LIBS) {
int p = f.lastIndexOf(".so.");
if (p >= 0) {

String orf = f.substring(0, p + 3);

File src = new File(pathLib, orf);
File dest = new File(pathDest, f);

if (!dest.exists()) {
Process proc = Runtime.getRuntime().exec(
new String[] { "ln", "-s",
src.getAbsolutePath(),
dest.getAbsolutePath() });
try {
proc.waitFor();
} catch (Throwable t) {
t.printStackTrace();
}

}

}
}

}

// Load libs
for (String f : LIBS) {
File dest = new File(pathDest, f);
System.load(dest.getAbsolutePath());
}

isLibInit = true;
}

Just call this method before accessing the libraries, and you are done!