在Android应用程序中使用现有的共享库(.so)

时间:2011-06-23 04:07:24

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

我有以下方案可以继续。我得到了一个共享库(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文件中部署这个文件?

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

    非常感谢 蒂亚戈

2 个答案:

答案 0 :(得分:6)

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

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

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”)调用它;

答案 1 :(得分:1)

  

1我是否需要将本机方法签名放在同一个中   package / class是当.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'接口)。