我是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
答案 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进行调试。
我希望这可以为某人节省我花时间解决这个问题。