您的位置:首页 > 其它

再说jni

2012-06-05 17:05 113 查看
前一段时间做过jni的调用,也成功通过了。最近在开发一个新的项目的时候用前一个项目的so库,反复提示UnsatisfiedLinkerror+库名字。无奈各种google下发现是因为新项目路径有所不同导致。只能自己在当前项目重新编译生成库文件。

温习一遍编译过程,非常简单:首先生成了要调用的java文件 我的是 。到项目的bin目录下运行命令行:javah -classpath classes -d jni xx.xx.xx.ESInterface 生成头文件 xx.xx.xx.ESInterface.h。将此头文件复制一份改成相应的c文件xx.xx.xx.ESInterface.c。然后就是相应的c文件的实现了。

关于c文件的实现说下,如果你之前已经写好了一个c文件,比如叫做:a.c。可以在ESInterface.c中调用a.c中的函数。省的再写一遍了。。不过调用要符合jni编程规范,jni 数据类型跟纯c是不一样的,至少外观不一样。我这儿也犯2了,直接调用a.c中的函数,当然不成功,还是问的一个同事才醒悟。给出一个调用的示例:

/*

* Class: xx.xx.xx.ESInterface

* Method: getDCGGMaxMoney

* Signature: ([Ljava/lang/Object;[III)F

*/

JNIEXPORT jfloat JNICALL Java_com_esun_cheetah_view_personal_lib_ESInterface_getDCGGMaxMoney (JNIEnv* env , jclass obj , jobject touZhuData_ , jintArray orgGGTypeArr , jint beiShu , jint allGameNum) {

const int size = (*env)->GetArrayLength(env, touZhuData_);

struct touZhuData dataArray[size];

int k=0;

for(k=0;k<size;k++)

{

jobject* objTmp = (*env)->GetObjectArrayElement(env, touZhuData_, k);

//struct touZhuData* data = (struct touZhuData*)malloc(sizeof(struct touZhuData));

jclass objectClass = (*env) -> FindClass(env , "com/esun/libc/TouZhuData");

// 胜赔率

jfieldID winPL = (*env) -> GetFieldID(env ,objectClass,"winPL","F");

// 平赔率

jfieldID drawPL = (*env) -> GetFieldID(env ,objectClass,"drawPL","F");

// 负赔率

jfieldID losePL = (*env) -> GetFieldID(env ,objectClass,"losePL","F");

// 是否为胆码

jfieldID isDan = (*env) -> GetFieldID(env ,objectClass,"isDan","I");

// 是否为有效场次

jfieldID isEff = (*env) -> GetFieldID(env ,objectClass,"isEff","I");

dataArray[k].winPL = (*env) -> GetFloatField(env , objTmp , winPL);

dataArray[k].drawPL = (*env) -> GetFloatField(env , objTmp , drawPL);

dataArray[k].losePL = (*env) -> GetFloatField(env , objTmp , losePL);

dataArray[k].isDan = (*env) -> GetIntField(env , objTmp , isDan);

dataArray[k].isEff = (*env) -> GetIntField(env , objTmp , isEff);

//dataArray[k] = data;

}

jint* pValue = (*env) -> GetIntArrayElements(env ,orgGGTypeArr , NULL);

jsize len = (*env) -> GetArrayLength(env ,orgGGTypeArr);

int* array[len];

int i=0;

for( i=0;i<len;i++)

{

array[i] = pValue[i];

}

return (jfloat)getDCGGMaxMoney(dataArray , array , beiShu , allGameNum);

}

当然,仅仅这样还是不够的。既然调用了额外的c函数自然要在Android.mk中搞一下了:

LOCAL_SRC_FILES := a.c (这个是被调用的c文件)

LOCAL_SRC_FILES +:xx.xx.xx.ESInterface.c (这个是你的jni的c文件)

好了,最后给出Android.mk的完整内容:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := libesunlib

LOCAL_SRC_FILES := a.c

LOCAL_SRC_FILES +::xx.xx.xx.ESInterface.c

LOCAL_C_INCLUDES := E:\android-ndk-r7\sources\libesunlib\jni

include $(BUILD_SHARED_LIBRARY)

各个含义网上的介绍很多,在此不提。

最后编译so文件:

将上面的4个文件:

xx.xx.xx.ESInterface.h

xx.xx.xx.ESInterface.c

a.c

Android.mk

所在的文件夹放到 ndk 的sources 下,或者apps下等都行,运行你的cygwin: $NDK/ndk-build 搞定。($NDK 是你自己配置的路径,嫌麻烦的话直接cd到ndk-build的目录下也行)。

但是,但是,运行,竟然报UnsatisfiedLinkerror+函数名 错误。再搞,返现函数名啥的都没有问题呀,包含头文件之类的也ok。。。

最后将ESInterface.c中 从.h中拷贝过来的

#ifndef _Included_com_esun_cheetah_view_personal_lib_ESInterface

#define _Included_com_esun_cheetah_view_personal_lib_ESInterface

#ifdef __cplusplus

extern "C" {

#endif

之类的统统拿掉,重新编译,ok,运行,ok。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: