在Android中使用jni:UNsatisfiedLinkError

时间:2012-07-24 13:48:18

标签: android java-native-interface header-files unsatisfiedlinkerror

我是jni的新手,我正在修改一个教程来实现一个简单的本机方法,但是我得到了一个不满意的链接错误。据我所知,我完全按照教程中的步骤进行操作。请帮帮我。

这是java包装器代码:

package com.cookbook.jni;

public class SquaredWrapper {

    // Declare native method (and make it public to expose it directly)
    public static native int squared(int base);

   // Provide additional functionality, that "extends" the native method
   public static int to4(int base)
   {
      int sq = squared(base);
      return squared(sq);
   }

   // Load library
   static {
      System.loadLibrary("squared");
   }
}

这是我的Android.mk文件的样子:

  

LOCAL_PATH:= $(致电my-dir)

     

包括$(CLEAR_VARS)

     

LOCAL_MODULE:=平方   LOCAL_SRC_FILES:= squared.c

     

包括$(BUILD_SHARED_LIBRARY)

这是我的.c文件的样子:

#include "squared.h"
#include <jni.h>

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared
  (JNIEnv * je, jclass jc, jint base)
{
     return (base*base);
}

这是我的.h文件的样子:

enter code here/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cookbook_jni_SquaredWrapper */

#ifndef _Included_com_cookbook_jni_SquaredWrapper
#define _Included_com_cookbook_jni_SquaredWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_cookbook_jni_SquaredWrapper
* Method:    squared
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared
  (JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

2 个答案:

答案 0 :(得分:8)

您的JNI签名不符合。在.c文件中,更改:

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared

通常有两种方法可以将本机C通过JNI“粘合”到Java函数中。第一个是您在这里尝试做的事情,即使用JNI将识别并与您的相应Java代码相关联的预定签名。第二种是在包含库时将函数指针,签名和Java类名称传递给JNI。

这是第二种将本机函数绑定到适当的Java代码的方法(这将是你的.c文件):

#include "squared.h"
#include <jni.h>

static const char* SquaredWrapper = "com/cookbook/jni/SquaredWrapper";

jint squared(JNIEnv * env, jobject this, jint base) {
     return (base*base);
}

// Methods to register for SquaredWrapper
static JNINativeMethod SquareWrapperMethods[] = {
        {"squared", "(I)I", squared}
};

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if ( (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK)
        return JNI_ERR;

    jclass class = (*env)->FindClass(env, SquaredWrapper);
    (*env)->RegisterNatives(env, class, SquaredWrapperMethods, sizeof(SquaredWrapperMethods)/sizeof(SquaredWrapperMethods[0]));

    return JNI_VERSION_1_6;
}

void JNI_OnUnload(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
        return;

    jclass class = (*env)->FindClass(env, SquaredWrapper);
    (*env)->UnregisterNatives(env, class);

    return;

}

这是一个很长的时间,但它在绑定本机代码时提供了更多的灵活性。平方和包含的定义如您所料。在第4行,static const char * SquaredWrapper是一个转义字符串,其中包含要绑定平方的类的完全限定包名。接近底部的是JNI_OnLoad和JNI_OnUnLoad函数,它们负责绑定和解除库加载和卸载时的函数绑定。最后一块是JNINativeMethod数组。此数组包含每个条目的大小为3的数组,其组件是作为const char *的方法的Java名称,Java方法的JNI签名以及绑定到该方法的本机C函数指针。 JNI函数签名告诉环境参数列表格式和Java函数的返回值。格式为“(Arg1Arg2Arg3 ...)Ret”,因此采用int和double并返回float的函数将具有“(ID)F”的签名,并且不带参数且返回void的函数将是“()V”。我用这个方便的备忘单来记住大部分的简写:

http://dev.kanngard.net/Permalinks/ID_20050509144235.html

祝你好运:)

编辑哦,顺便说一下,您可能希望将JNI_OnLoad和JNI_UnOnLoad的签名添加到标头中,并更改本机函数原型的名称以反映新的.c文件。

答案 1 :(得分:0)

这是一个晦涩的案例,但是如果您在本机代码中遇到访问冲突,Android将掩盖引发的异常并引发您得到的错误。就我而言,本机代码引发访问冲突,但Java仍在运行。然后,它尝试在崩溃的NDK上调用JNI方法。

要找到访问冲突,我最终将有问题的JNI方法移至另一个IDE进行调试。

我希望这可以为某人节省我花时间解决这个问题。