7

我是 jni 的新手,我正在阅读一个教程来实现一个简单的本机方法,但我得到了一个 unsatisfiedlinkerror。据我所知,我完全按照教程中的步骤进行操作。请帮我。

这是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 := $(调用我的目录)

包括 $(CLEAR_VARS)

LOCAL_MODULE := squared 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
4

2 回答 2

8

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

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared

通常有两种方法可以通过 JNI 将原生 C 语言“粘合”到 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 行,静态 const char* SquaredWrapper 是一个转义字符串,其中包含要绑定平方的类的完全限定包名称。靠近底部的是 JNI_OnLoad 和 JNI_OnUnLoad 函数,它们负责绑定和取消绑定库加载和卸载时的函数。最后一块是 JNINativeMethod 数组。该数组包含一个大小为 3 的数组作为每个条目,其组成部分是方法的 Java 名称(如 const char*)、Java 方法的 JNI 签名以及绑定到该方法的本机 C 函数指针。JNI 函数签名告诉环境参数列表格式和 Java 函数的返回值。格式为“

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

祝你好运 :)

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

于 2012-07-24T13:55:54.423 回答
0

这是一种晦涩难懂的情况,但是如果您在本机代码中遇到访问冲突,Android 将掩盖抛出的异常并抛出您遇到的错误。就我而言,本机代码引发了访问冲突,但 Java 继续运行。然后它尝试在崩溃的 NDK 上调用 JNI 方法。

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

我希望这可以节省我弄清楚这一点所花费的时间。

于 2020-07-21T13:52:20.300 回答