【问题标题】:JNI- java.lang.UnsatisfiedLinkError: Native method not foundJNI-java.lang.UnsatisfiedLinkError:找不到本机方法
【发布时间】:2014-08-25 07:27:36
【问题描述】:

我正在使用 OpenCV 开发一个 Android 项目。有些方法没有Java版本,所以我必须使用NDK才能在我的项目中使用它们。

这是我第一次使用NDK,所以在搜索了一些示例后,我编写了代码,在我的设备上运行它,并收到以下错误消息:

07-04 10:26:19.555  21270-21270/com.example.MyTest E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.UnsatisfiedLinkError: Native method not found: com.example.MyTest.JNIlib.readImg:()I
            at com.example.MyTest.JNIlib.readImg(Native Method)
            at com.example.MyTest.MyActivity$2.onClick(MyActivity.java:60)
            at android.view.View.performClick(View.java:4211)
            at android.view.View$PerformClick.run(View.java:17267)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4898)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
            at dalvik.system.NativeStart.main(Native Method)

我多次重新生成 .so 文件,并检查 jni 函数的命名。我还在 jni 函数中添加了 'extern "C"' 包装器。但这些解决方案都没有奏效。

注意:我一直使用 Intellij Idea 开发 JAVA 程序,由于 Idea 不支持 NDK,我必须使用 Eclipse 才能进入 NDK,所以……这也是我第一次使用 Eclipse。我本可以犯很多愚蠢的错误。哈哈

以下是我的 c++ 代码和 makefile。

LocalMain.cpp

#include <stdio.h>
#include <iostream>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp>

#include <opencv2/opencv.hpp>  
#include <jni.h>
#include <android/log.h>
#include "LocalFeature.h"
using namespace cv;  
using namespace std;  



int readImg()
{  
    /* do something*/

    return 0;  
}  


// JNI interface functions, be careful about the naming.
extern "C"
{
    JNIEXPORT jint JNICALL Java_com_example_MyTest_JNIlib_readImg(JNIEnv * env, jobject obj);
};

JNIEXPORT jint JNICALL Java_com_example_MyTest_JNIlib_readImg(JNIEnv * env, jobject obj)
{
    return (jint)readImg();
}

LocalFeatures.h 和 LocalFeatures.cpp 没有显示,但我确定问题不在于它们。

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := nonfree_prebuilt
LOCAL_SRC_FILES := libnonfree.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := opencv_java_prebuilt
LOCAL_SRC_FILES := libopencv_java.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
# Modify LOCAL_C_INCLUDES with your path to OpenCV for Android.
LOCAL_C_INCLUDES:= E:/Java/libs/OpenCV-2.4.9-android-sdk/sdk/native/jni/include
LOCAL_MODULE    := mytest_lib
LOCAL_CFLAGS    := -Werror -O3 -ffast-math
LOCAL_LDLIBS    += -llog -ldl 
LOCAL_SHARED_LIBRARIES := nonfree_prebuilt opencv_java_prebuilt
LOCAL_SRC_FILES := LocalMain.cpp \
LocalFeature.h \
LocalFeature.cpp

include $(BUILD_SHARED_LIBRARY)

那些 .cpp 文件和 .mk 文件位于 Eclipse 项目中。 libmytest_lib.so、libopencv_java.so、libnonfree.so 可以正确生成。 以下 .java 文件位于 Intellij Idea 项目中。我已将这些 .so 文件复制到 Idea 项目中的 \lib 中。

JNIlib.java

public class JNIlib {
    static
    {
        try
        {
            // Load necessary libraries.
            System.loadLibrary("opencv_java");
            System.loadLibrary("nonfree");
            System.loadLibrary("mytest_lib");
        }
        catch( UnsatisfiedLinkError e )
        {
            System.err.println("Native code library error.\n");
        }
    }
    public static native int readImg();
}

MainActivity.java 的一部分

public class MyActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2{

    public View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            JNIlib.readImg();
        }
    };

    /*Other irrevelant code*/
}

非常感谢!

【问题讨论】:

    标签: android opencv java-native-interface


    【解决方案1】:

    从以下位置删除 static

    public static native int readImg(); 
    

    即写成这样:

    public native int readImg();
    

    如果你真的希望你的readImg() 方法是静态的,你应该如下声明JNI 方法(用jclass 而不是jobject):

     JNIEXPORT jint JNICALL Java_com_example_MyTest_JNIlib_readImg(JNIEnv * env, jclass obj);
    

    【讨论】:

    • 你解决了我一半的问题,让我意识到问题不仅在于我的代码,还在于我的项目结构。谢谢:)
    • 其实这个没关系。 JNIEXPORT jint JNICALL Java_com_example_MyTest_JNIlib_readImg(JNIEnv * env, jobject obj)JNIEXPORT jint JNICALL Java_com_example_MyTest_JNIlib_readImg(JNIEnv * env, jclass obj),因为在 C 中,jclassjobject 是同义词。
    • @SteveM 你能详细说明一下吗? static 隐藏所有设备上的方法,而 jobject 仅在正确使用时为 void*
    【解决方案2】:

    在遵循 JonesV 的建议后,我从代码中删除了静态。但在那之后,问题仍然存在。

    最后我调试了我的程序,当运行到这一行时:

    System.loadLibrary("opencv_java");
    

    程序抛出错误,而不是像我想象的那样正常运行。真是愚蠢的错误:

    现在我发现了一个我以前从未注意到的错误。

    java.lang.UnsatisfiedLinkError: Couldn't load opencv_java: findLibrary returned null
    

    这意味着,没有加载任何库。所以我检查了我的项目结构,发现我将 .so 文件放在 libs/ 文件夹中,而不是 libs/armeabi/ 文件夹中。

    解决方法在这里: Android NDK java.lang.UnsatisfiedLinkError: findLibrary returned null

    【讨论】:

      【解决方案3】:

      我加了

      extern "C"
      

      在函数声明之前 例如:

      extern "C"
      jstring
      Java_lara_myapplication_MainActivity_stringFromJNI(
              JNIEnv *env,
          jobject /* this */) {
          std::string hello = "Hello from C++";
          return env->NewStringUTF(hello.c_str());
      }
      

      然后错误消失了

      【讨论】:

      • 预期标识符或'('
      【解决方案4】:

      对我来说,我在

      中使用了错误的类(MyClass)
      extern "C" JNIEXPORT jstring JNICALL
      Java_package_MyClass_test(JNIEnv* env, jobject)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多