Android JNI native extension question

V Vincent Lagneau 3 years 6 months ago
8 0 0

Hi guys, I’m currently working with Rhodes 5.0.30 (on Mac OS X 10.10.2) on the integration of FFMPEG in our Android application.

There are many projects on Github that can help you compile the FFMPEG libraries for Android. I used this one and customize it a bit so it fits our configuration.
So anyway, I now have the libraries headers and .so files ready to be used on an Android device running on an ARM CPU architecture.

Using this documentation I was able to build a native extension called ffmpeg. Using the files generated by the extension, I created a native Java function that takes a string as an input and returns another as an output.
Here’s this function implementation:

package com.rho.ffmpeg;

import java.util.LinkedList;
import java.util.List;

import com.rhomobile.rhodes.api.IMethodResult;

class FfmpegSingleton extends FfmpegSingletonBase implements IFfmpegSingleton {
    public FfmpegSingleton(FfmpegFactory factory) {
        super();
    }

    List getIDs() {
        List ids = new LinkedList();
        ids.add("SCN1");
        ids.add("SCN2");
        return ids;
    }

    @Override
    public void test(String path, IMethodResult result) {
        result.set("/your/path");
    }

}

So basically, in one of my view, I am calling, like below, this function and everything works as expected: I am getting a string « /your/path » as a return.

So this is a good start! But now I need to use JNI in order to be able to use the generated libraries for Android with C code, and that's my current problem.

So I learned from various tutorials in order to use JNI on an Android device, especially this one, which is really good.
I used this tutorial to build an equivalent for my already existing Rhodes project, creating the files in my extension directories.
I created a Java wrapper, converted it into a C header file with javah, and put it in the already existing jni directory located in /extension/my_extension/ext/platform/android/
I also created the C source associated with this header, and two files called « Android.mk » and « Application.mk » in order for the NDK to build this file as a module that my wrapper would use.
Finally, I changed my function test to use the wrapper.

My latest state of the extension is available as a zip at the bottom of this message.

Anyway, the project is building, and the command rake build:android:extensions runs perfectly, I don’t have any error.

But when trying to call the JNI function via the test function in my application, I have a Java error:

java.lang.UnsatisfiedLinkError: Couldn’t load toto from loader dalvik.system.PathClassLoader[…]

The reason is quite simple: the « toto » library that should be built (and called libtoto.so) isn’t, or at least does not seem to be deployed in the application.apk.

Even when building the library myself with the NDK and putting it into my app/lib directory, it is not integrated in the .apk and so not usable.

As I was not able to find any issue or recent example (because this mechanism seems to have changed since rhodes 2.2), I turn to you to know if anyone as an idea or example of how to make this library to be created ?
Or if I am wrong, can you explain me how to do in order to be able to call a C source that is working with shared libraries ?

I'm working with ruby 2.1.5 and Android NDK r9b.

Thanks for your time and your help.

CONTACT
Can’t find what you’re looking for?