再说jni

来源:互联网 发布:图片base64编码php 编辑:程序博客网 时间:2024/05/02 03:08
         前一段时间做过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。