我有以下方案可以继续。我得到了一个共享库(libeffect.so),用于我正在为客户工作的Android项目。我没有共享库源代码,我只有.so文件。该库已预编译为可在Android设备上运行。与共享库一起,我有方法签名
public static native void doEffect(int param1, IntBuffer intBuffer);
所以现在我对如何调用源的本机方法有一些疑问,如果这可能只有.so文件,那么它们就是:
我是否需要将本机方法签名放在与.so相同的包/类中,或者我可以在项目的任何包/类中使用此签名,在运行时jvm将是能够在共享库中找到方法吗?例如,如果这个共享库首先在类mypackage.MyClass中使用,我是否需要创建相同的包,类然后将方法签名放在那里?
我在哪里需要将这个.so文件放在我的eclipse android项目中,以便在我的apk文件中部署这个文件?
这些问题可能听起来像菜鸟,但我从来没有使用过jndi所以我有点担心如果调用方法doEffect没有任何错误就可以实现。任何可以指导我的答案都非常受欢迎。
非常感谢 蒂亚戈
答案 0 :(得分:6)
- 我是否需要将本机方法签名放在同一个包/类中 当.so或我时定义的那些 可以在任何使用此签名 我的项目中的包/类 在运行时,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”)调用它;
答案 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'接口)。