Using existing shared library (.so) in Android application

18,825

Solution 1

  1. Do I need to place the native method signature in the same package/class as those defined when the .so was or I can use this signature in any package/class in my project that during runtime the jvm will be able to find the method in the shared library? For example, if this shared library was firstly used in a class mypackage.MyClass, do I need to create the same package, class and then put the method signature there?

No need to create same package/class. You can put the method signature in any package.

public class NativeLib {

  static {
    System.loadLibrary("so_file");
  }

  public static native void doEffect(int param1, IntBuffer intBuffer);

}

2.Where do I need to place this .so file inside my eclipse android project to get this file deployed inside my apk file?

You have put this .so file in lib folder of your application . IF lib folder is not there then you can create a lib folder and put the .so file. you can call it by using System.loadLibrary("so_ file");

Solution 2

1 Do I need to place the native method signature in the same package/class as those defined when the .so was or I can use this signature in any package/class in my project that during runtime the jvm will be able to find the method in the shared library?

According to http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html you have to use a matching package and class name.

I've only observed JNI methods where the C side functions are called things like Java_com_company_whatever_SomeClass_someMethod, which means that you have to put the 'native' declarations in a similarly-named Java class.

Use the tool 'nm' or 'nm++' (they're in the precompiled folders in the NDK) to look at the .so file and see what the functions defined in it are called. If you see any starting Java_, those're what you want.

I'm sceptical of the preceding claim that you can call functions which aren't named in the Java_PACKAGE_CLASS_METHOD format; it may be a legacy behaviour if it actually works, but even if you can, it seems dangerous - you might get the wrong one.

2 Where do I need to place this .so file inside my eclipse android project to get this file deployed inside my apk file?

Your .so lives in libs/armeabi, libs/armeabi-v7a, libs/x86, and/or libs/mips depending on how many platforms you're working with, where 'libs' is a peer of 'src' and 'res'. I don't know whether Android looks in libs/ without the platform qualifier, but there's no evident benefit in that. The situation is slightly complicated by most/all Intel devices including fancy technology allowing them to execute most ARM libraries on x86 hardware.

Further, I like to declare an interface of a JNI class and provide a factory (it's a method here for brevity, but I prefer a factory class) that supplies a no-op implementation of the interface if things go wrong: it facilitates unit testing and also avoids having to mess about testing for null values before calling its methods (assuming you're comfortable that your shipped library will never have missing or changed method signatures - your integration tests should check that):

public interface YourLibI {
    @Override
    public native yourMethod();

    public static final NO_OP = new YourLibI() {
        @Override
        public void yourMethod(){}
    }
}

public class YourLib extends YourLibI {
    public newYourLibI() {
        try {
            return new YourLib();
        }
        catch (UnsatisfiedLinkError e) {
            Log.e("YourLibJNI", "Load failed, returning NO-OP dummy", e);
            return YourLibI.NO_OP;
        }
    }

    static {
        System.loadLibrary("arbitronSDK");
    }

    private YourLib() {
    }

    @Override
    public native void yourMethod();
}

I don't normally call interfaces 'xxxI' but I'm assuming your library's JNI class isn't called something nice like UtilityJNI (whereupon I'd call the interface 'Utility').

Share:
18,825
Thiago
Author by

Thiago

Updated on June 04, 2022

Comments

  • Thiago
    Thiago almost 2 years

    I have the follow scenario to work on. I was given a shared library (libeffect.so) to use in a Android project i am working for a client. I dont have the shared library source code, i have just the .so file with me. The library is pre-compiled to work on android devices. Along with the shared library I have the method signature

    public static native void doEffect(int param1, IntBuffer intBuffer);
    

    So now I have some questiosn on how to make the call to this native method, of source, if this is possible having just the .so file, so there they are:

    1. Do I need to place the native method signature in the same package/class as those defined when the .so was or I can use this signature in any package/class in my project that during runtime the jvm will be able to find the method in the shared library? For example, if this shared library was firstly used in a class mypackage.MyClass, do I need to create the same package, class and then put the method signature there?

    2. Where do I need to place this .so file inside my eclipse android project to get this file deployed inside my apk file?

    These question might sound noob, but I have never worked with jndi before so I am a bit concerned if calling the method doEffect without any error can be achieve. Any answer that can guide me is very welcome.

    Many Thanks Thiago

  • Thiago
    Thiago almost 13 years
    Thanks @Sujit. I was looking at this tutorial, android10.org/index.php/articlesother/…, and I see that the generated C++ code snippet has the method name composed by the java package and method name. Wont this affect the way I use the native signature? I tought that I should follow the same name conventions used when the shared library was created. Another question, once I have the .so file in my AndroidProject/lib folder, will this file be exported with the APK file? Do I need to create the sub folder armeabi folder? Many thanks, T