【问题标题】:Using existing shared library (.so) in Android application在 Android 应用程序中使用现有的共享库 (.so)
【发布时间】:2011-06-23 04:07:24
【问题描述】:

我有以下情况要处理。我获得了一个共享库(libeffect.so),可以在我为客户工作的 Android 项目中使用。我没有共享库源代码,我只有 .so 文件。该库已预编译以在 android 设备上运行。除了共享库,我还有方法签名

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

所以现在我有一些关于如何调用这个源代码的本机方法的问题,如果这可能只有 .so 文件,那么它们就是:

  1. 我是否需要将本机方法签名放置在与 .so 时定义的相同的包/类中,或者我可以在我的项目中的任何包/类中使用此签名,在运行时 jvm 将是能在共享库中找到方法吗?例如,如果这个共享库首先用在一个类mypackage.MyClass中,我是否需要创建相同的包、类然后把方法签名放在那里?

  2. 我需要将此 .so 文件放置在我的 eclipse android 项目中的什么位置,以便将此文件部署到我的 apk 文件中?

这些问题听起来可能很菜鸟,但我以前从未使用过 jndi,所以我有点担心调用方法 doEffect 是否可以实现没有任何错误。任何可以指导我的答案都非常受欢迎。

非常感谢 蒂亚戈

【问题讨论】:

    标签: android java-native-interface android-ndk


    【解决方案1】:
    1. 我是否需要将本机方法签名放在同一个包/类中 那些在 .so 是或 I 时定义的 可以在任何情况下使用此签名 我的项目中的包/类 在运行时 jvm 将能够 在共享库中找到方法? 例如,如果这个共享库 首次在课堂上使用 mypackage.MyClass,我需要创建吗 相同的包,类,然后放 那里的方法签名?

    无需创建相同的包/类。您可以将方法签名放在任何包中。

    public class NativeLib {
    
      static {
        System.loadLibrary("so_file");
      }
    
      public static native void doEffect(int param1, IntBuffer intBuffer);
    
    }
    

    2.我需要把这个 .so 文件放在我的 eclipse android 项目中的什么地方 将此文件部署到我的 apk 文件中?

    您已将此 .so 文件放在应用程序的 lib 文件夹中。如果 lib 文件夹不存在,那么您可以创建一个 lib 文件夹并放置 .so 文件。您可以使用 System.loadLibrary("so_file");

    调用它

    【讨论】:

    • 谢谢@Sujit。我在看这个教程android10.org/index.php/articlesother/…,我看到生成的C++代码sn-p有由java包和方法名组成的方法名。这不会影响我使用本机签名的方式吗?我认为我应该遵循创建共享库时使用的相同名称约定。另一个问题,一旦我的 AndroidProject/lib 文件夹中有 .so 文件,这个文件会与 APK 文件一起导出吗?我需要创建子文件夹 armeabi 文件夹吗?非常感谢,T
    【解决方案2】:

    1 我需要将本机方法签名放在同一个 包/类作为.so 时定义的那些,或者我可以使用它 在我的项目中的任何包/类中签名,在运行时 jvm能在共享库中找到方法吗?

    根据http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html,您必须使用匹配的包和类名。

    我只观察过 JNI 方法,其中 C 端函数被称为 Java_com_company_whatever_SomeClass_someMethod,这意味着您必须将“本机”声明放在名称相似的 Java 类中。

    使用工具“nm”或“nm++”(它们位于 NDK 的预编译文件夹中)查看 .so 文件并查看其中定义的函数被调用。如果你看到任何开始的 Java_,那就是你想要的。

    我对前面的说法表示怀疑,即您可以调用未以 Java_PACKAGE_CLASS_METHOD 格式命名的函数;如果它确实有效,它可能是一种遗留行为,但即使可以,它也似乎很危险——你可能会弄错。

    2 我需要将此 .so 文件放在我的 eclipse android 中的什么位置 将这个文件部署到我的 apk 文件中的项目?

    您的 .so 位于 libs/armeabi、libs/armeabi-v7a、libs/x86 和/或 libs/mips 中,具体取决于您使用的平台数量,其中“libs”是“src”的对等体和'res'。我不知道 Android 是否在没有平台限定符的情况下在 libs/ 中查找,但这并没有明显的好处。大多数/所有英特尔设备(包括允许它们在 x86 硬件上执行大多数 ARM 库的先进技术)使情况稍微复杂。

    此外,我喜欢声明一个 JNI 类的接口并提供一个工厂(为了简洁起见,这里是一个方法,但我更喜欢一个工厂类),如果出现问题,它提供接口的无操作实现:它便于单元测试,并且避免在调用其方法之前必须对空值进行测试(假设您对交付的库永远不会丢失或更改方法签名感到满意 - 您的集成测试应该检查这一点):

    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();
    }
    

    我通常不将接口称为“xxxI”,但我假设您的库的 JNI 类没有像 UtilityJNI 那样被称为很好的东西(因此我将接口称为“Utility”)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      • 2021-07-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-09
      相关资源
      最近更新 更多