简体   繁体   English

在 Android 中使用 jni:UNsatisfiedLinkError

[英]Using jni in Android: UNsatisfiedLinkError

I'm new to jni, and I was going over a tutorial to implement a simple native method, but I'm getting an unsatisfiedlinkerror.我是 jni 的新手,我正在阅读一个教程来实现一个简单的本机方法,但我遇到了一个不满意的链接错误。 As far as I know, I followed the steps in the tutorial exactly.据我所知,我完全按照教程中的步骤操作。 Please help me.请帮我。

Here is the java wrapper code:这是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");
   }
}

Here's what my Android.mk file looks like:这是我的 Android.mk 文件的样子:

LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(调用我的目录)

include $(CLEAR_VARS)包括 $(CLEAR_VARS)

LOCAL_MODULE := squared LOCAL_SRC_FILES := squared.c LOCAL_MODULE := 平方 LOCAL_SRC_FILES := squared.c

include $(BUILD_SHARED_LIBRARY)包括 $(BUILD_SHARED_LIBRARY)

Here's what my .c file looks like:这是我的 .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);
}

And here is what my .h file looks like:这是我的 .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

Your JNI signature doesn't match.您的 JNI 签名不匹配。 In your .c file, change:在您的 .c 文件中,更改:

JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared

to

JNIEXPORT jint JNICALL Java_com_cookbook_jni_SquaredWrapper_squared

Generally there are two ways to "glue" native C through JNI to a Java function.通常有两种方法可以通过 JNI 将原生 C 与 Java 函数“粘合”。 The first is what you're attempting to do here, that is use a predetermined signature that JNI will recognize and associate with your appropriate Java code.第一个是您在此处尝试执行的操作,即使用 JNI 将识别并与您的适当 Java 代码关联的预定签名。 The second is to pass function pointers, signatures, and Java class names into JNI when you include the library.第二种是在包含库时将函数指针、签名和 Java 类名传递给 JNI。

Here's the second method that would bind the native function to the appropriate Java code (this would be your .c file):这是将本机函数绑定到适当的 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;

}

It's a good deal longer but it gives you a lot more flexibility when binding native code.它更长,但它在绑定本机代码时为您提供了更大的灵活性。 The definition for squared and the includes are as you would expect. squared 和includes 的定义如您所料。 on the 4th line, the static const char* SquaredWrapper is an escaped string with the fully qualified package name of the class you want to bind squared to.在第 4 行,静态 const char* SquaredWrapper 是一个转义字符串,其中包含要绑定 squared 的类的完全限定包名称。 Near the bottom are the JNI_OnLoad and JNI_OnUnLoad functions that take care of binding and unbinding the functions on library load and unload.靠近底部的是 JNI_OnLoad 和 JNI_OnUnLoad 函数,它们负责在库加载和卸载时绑定和解除绑定函数。 The last piece is the JNINativeMethod array.最后一部分是 JNINativeMethod 数组。 This array contains as each entry an array of size 3 whose components are the Java name of the method as a const char*, the JNI signature of the Java method, and the native C function pointer to bind to that method.该数组的每个条目都包含一个大小为 3 的数组,其组成部分是作为 const char* 的方法的 Java 名称、Java 方法的 JNI 签名以及绑定到该方法的本机 C 函数指针。 The JNI function signature tells the environment the argument list format and return value of the Java function. JNI 函数签名告诉环境 Java 函数的参数列表格式和返回值。 The format is "(Arg1Arg2Arg3...)Ret", so a function that takes an int and double and returns a float would have a signature of "(ID)F", and a function that takes no arguments and returns void would be "()V".格式是“(Arg1Arg2Arg3...)Ret”,因此一个接受 int 和 double 并返回一个浮点数的函数将具有“(ID)F”的签名,而一个不接受任何参数并返回 void 的函数将是“()V”。 I use this handy cheat sheet to remember most of the shorthand:我使用这个方便的备忘单来记住大部分速记:

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

Good luck :)祝你好运 :)

Edit: Oh, BTW, you'll likely want to add the signatures for JNI_OnLoad and JNI_UnOnLoad to your header, and change the name of your native function prototype to reflect the new .c file.编辑:哦,顺便说一句,您可能希望将 JNI_OnLoad 和 JNI_UnOnLoad 的签名添加到您的标头中,并更改您的本机函数原型的名称以反映新的 .c 文件。

This is kind of an obscure case, but if you get an access violation in your native code, Android will cover up the thrown exception and throw the error you got.这是一种晦涩的情况,但是如果您在本机代码中遇到访问冲突,Android 将掩盖抛出的异常并抛出您得到的错误。 In my case, the native code threw an access violation but Java kept running.就我而言,本机代码引发了访问冲突,但 Java 继续运行。 It then tried to call a JNI method on the crashed NDK.然后它尝试在崩溃的 NDK 上调用 JNI 方法。

To find the access violation, I ended up moving the offending JNI method to another IDE to debug.为了找到访问冲突,我最终将有问题的 JNI 方法移动到另一个 IDE 进行调试。

I hope this saves someone the amount of time it took me to figure this out.我希望这可以为某人节省我花费的时间来解决这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM