【问题标题】:Error loading existing shared library (.so) on Android app (unsatisfiedlinkerror native method not found)在 Android 应用上加载现有共享库 (.so) 时出错(未找到 unsatisfiedlinkerror 本机方法)
【发布时间】:2014-07-18 20:29:08
【问题描述】:

这是我的场景:

-) 我有一个由 ndk-build 生成的名为 libpsp.so 的共享库。这个库是使用大约 30 个 .c 文件生成的。

使用的Android.mk:

    LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Here we give our module name and source file(s)
LOCAL_MODULE    := psp
LOCAL_SRC_FILES := (My .c files)

include $(BUILD_SHARED_LIBRARY)

-) ndk-build 自动将 libpsp.so 放入目录 /libs/armeabi

-) 在我的 Java 代码中,我有:

    private native int calculateCoefficient(double w, double v_st_e_prev, double c_l);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    **//Loads successfully
    System.loadLibrary("psp");**

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
    TextView lv = (TextView)findViewById(R.id.textView);

    **//Returns an error: unsatisfiedlinkerror native method not found
    lv.setText(Integer.toString(calculateCoefficient(1,1,1)));**
}

-) 用于构建共享库的 .c 文件之一具有带有签名的 calculateCoefficient 方法:

sint32_t calculateCoefficient(double_t w, double_t v_st_e_prev, double_t *c_l);

那么如果 .so 库中存在 calculateCoefficient 方法,为什么 Android 找不到呢?我刚开始使用 NDK,如果我遗漏了一些显而易见的事情,我深表歉意,但我已经做了一些研究,但找不到答案。

UPDATE1:我无权访问实际代码,该库是由其他人生成的,我所拥有的只是带有方法签名的 .h 文件。所以我不能编辑用于创建库的 .c 文件。

【问题讨论】:

  • 首先,使用带有 -d 标志的 ndk objdump 来反汇编你的 .so 并将它的 grep 用于函数名称以找出实际存在的内容。接下来,使用隐式 root 模拟器的 adb shell,或者在设备上使用带有调试版本的 run-as 工具来检查安装并查看实际解压的内容。

标签: java android c linux android-ndk


【解决方案1】:

您的签名错误。它必须是 JNIEXPORT int JNICALL Java_classname_methodname(JNIENV* env, jobject obj, ...) 其中 ... 是您实际要传递的参数。指针不能被传递,如果你想要一个数组,你会使用一个 jdoublearray,如果你只想通过引用传递一个双精度,你需要传递一个包含双精度的类并在对象上设置该字段。

【讨论】:

  • 签名是从我可以访问的头文件中获得的,但是我不能改变C代码和方法签名。
  • 抱歉,我之前的评论部分不正确。缺少的 Java_classname_etc 前缀确实可以解释问题。如果您无法修复当前库,则使用正确命名的 jni 兼容函数编写一个新库,该函数包装并调用现有库。首先加载现有库,然后加载包装器。
  • 那么,我必须为每个要调用的函数创建一个带有 JNI 函数的 .c 文件?
  • 是的。确切的方法名称和签名需要匹配。这就是Java知道调用什么的方式。但是编写一个包装层来连接现有的 C 库和 Java 的情况并不少见。
  • 创建一个标记为本地方法的 Java 方法,然后让 JNI 标头生成器“javah”从 Java 文件生成正确的 .h 文件。您应该阅读有关 JNI 及其工作原理的更多信息。
猜你喜欢
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多