Using existing shared library (.so) in Android application

后端 未结 2 2018
攒了一身酷
攒了一身酷 2021-02-08 12:23

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 c

2条回答
  •  孤街浪徒
    2021-02-08 13:09

    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').

提交回复
热议问题