android下jni开发总结

对于开发Android来说jni是一个相对应用得比较少的玩意(相对于Android系统来说),正好最近这一阵子公司的项目比较轻松有一定的空闲时间,就利用起来整理了一下android下jni开发常用到的知识点和一些比较重要的用法,发话不多说直接进入主题。

在这里,对于jni的一些基本的介绍我就不多说了感兴趣的可以去问度娘或者谷歌,我在这里主要是以代码为主讲解关于jni的主要用法,如果有什么遗漏或者错误的地方希望大家勿喷额。直接上代码来看看我定义的本地方法,域和方法名:

    
    <pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 18px; line-height: 26px;">    private int x = 0;

private int y = 0; private String name; public static final String TAG="skywang--NdkParam"; /** Called when the activity is first created. */ private Person person=null;
private static final String DEBUGTAG = "NATIVE"; private String myString; private static int si=0; private static String helloString = "What‘s your name"; //对基本数据类型的访问 private native String GetNativeString(String str);//访问字串 private native int SumArray(int
[] ar, int length);//传一个数组的长度 private native int SumArrayA(int [] ar);//不传长度 private native int SumArray2D(int [][]ar2d);//传一个二维数组,返回一个长度 private native int [][] ModifyArray2d(int [][]ar2d);//传入一个二维数组,返回一个二维数组 //这一部分是对成员和方法的访问 private native void AccessField();//访问静态成员
private native void AccessMethod(); private native void signature(String str1, int i,byte b,char c,boolean bl,long l,double d,float f,short sh); // jni中注册的方法 public native String HelloLoad(); public native int add(int x, int y); public native void change();//通过本地方法修改java属性
public native void change_int();//通过落本地方法修改java蛇形 public native void calljavamethod(); /* ***************** 定义本地方法 ******************* */ // 输入常用的数值类型(Boolean,Byte,Char,Short,Int,Float,Double) public native void displayParms(String showText, int i, boolean
bl); // 调用一个静态方法 //public native int add( int a, int b); // 输入一个数组 public native void setArray(boolean[] blList); // 返回一个字符串数组 public native String[] getStringArray(); // 返回一个结构 public native DiskInfo getStruct(); // 返回一个结构数组 public native DiskInfo[] getStructArray();
// jni中注册的方法 private native int getPersonInfoByIndex(Person person, int index); public static String sayHello(String name) { return "Hello, " + name + "!"; } public String sayHello() { return "Hello, " + name + "!"; } private void callback(String strFromNative,int
i,byte b,char c,boolean bl,long l,double d,float f,short sh){ Log.d(DEBUGTAG,"CALL FROM NATIVE:"+strFromNative +i+b+c+bl+l+d+f+sh); System.out.println("CALL FROM NATIVE:"+strFromNative +i+b+c+bl+l+d+f+sh); } private static String callStaticBack(){ System.out.println("What‘s
your name "); return "What‘s your name "; }


上面的代码就是定义的一些本地方法,域和相关方法名,下面来看看我是怎么实现对本地方法的调用同时怎么实现c语言调用java函数和修改java里面的域值,下面直接上代码

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>

// 获取数组的大小
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
// 指定要注册的类,对应完整的java类名
#define JNIREG_CLASS "com/skywang/ndk/NdkLoad"
#define JNIPAR_CLASS "com/skywang/ndk/Person"
// 引入log头文件
#include <android/log.h>  

// log标签
#define  TAG    "hello_load"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)

// 硬盘信息
struct    {
     char  name[ 256 ];
     int  serial;
} DiskInfo;

jstring nativeTojstring( JNIEnv* env,const char* str );
char* jstringToNative(JNIEnv *env, jstring jstr);
jstring stoJstring(JNIEnv* env, const char* pat)  ;

// jfieldID结构体,用于保存类“Person.java”的filedID
struct PersonOffsets
{
    jfieldID    name;
    jfieldID    age;
    jfieldID    height;
} gPersonOffsets;

// 与“Person.java”对应的结构体,用于保存数据,并将数据赋值给Person.java的成员
typedef struct tagPerson
{
    char    mName[10];
    int     mAge;
    float   mHeight;
}Person;

// 定义了3个Person
static Person gPersons[] = {
    {"skywang", 25, 175},
    {"eman"   , 30, 166},
    {"Dan"    , 51, 172},
};
#define GPERSON_NUM NELEM(gPersons)

// 返回字符串"hello load jni"
JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz)
{
    return (*env)->NewStringUTF(env, "hello load jni.");
}

JNIEXPORT jint JNICALL native_add(JNIEnv *env, jclass clazz, jint x, jint y)
{
		return x+y;
}

//修改java中的String属性
JNIEXPORT void JNICALL native_change(JNIEnv *env, jobject this)
{
			jfieldID fid;
			jclass cls;
			// 先获得class对象
            cls = (*env)->FindClass(env, JNIREG_CLASS);
		      // 获取属性ID, 通过属性名和签名
            fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
            if (fid != 0)
            {
                const char* name = "icejoywoo";
                jstring arg = (*env)->NewStringUTF(env, name);
                (*env)->SetObjectField(env, this, fid, arg); // 修改属性
            }
}

//修改java中的int属性
JNIEXPORT void JNICALL native_change_int(JNIEnv *env, jobject this)
{
			jfieldID fid;
			jclass cls;
			// 先获得class对象
            cls = (*env)->FindClass(env, JNIREG_CLASS);
		      // 获取属性ID, 通过属性名和签名
            fid = (*env)->GetFieldID(env, cls, "x", "I");
            if (fid != 0)
            {
                jint arg = 5;
                (*env)->SetIntField(env,this, fid, arg); // 修改属性
            }
}

//修改java中的方法
JNIEXPORT void JNICALL native_calljavamethod(JNIEnv *env, jobject this)
{
			jfieldID fid;
			jclass cls;
			jmethodID mid;
			// 先获得class对象
            cls = (*env)->FindClass(env, JNIREG_CLASS);  

			// 获取方法ID, 通过方法名和签名, 调用静态方法
			// 获取方法ID, 通过方法名和签名, 调用静态方法
            mid = (*env)->GetStaticMethodID(env, cls, "sayHello", "(Ljava/lang/String;)Ljava/lang/String;");
			if (mid != 0)
            {
                const char* name = "World";
                jstring arg = (*env)->NewStringUTF(env, name);
                jstring result = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid, arg);
                const char* str = (*env)->GetStringUTFChars(env, result, 0);
				LOGI("%s info\n", __func__);
                LOGD("%s debug\n", __func__);
                LOGE("%s error\n", __func__);
				LOGI("Result of sayHello: %s\n\n", str);
                printf("Result of sayHello: %s\n", str);
				(*env)->ReleaseStringUTFChars(env, result, str);
            }

			// 调用成员方法
            mid = (*env)->GetMethodID(env, cls, "sayHello", "()Ljava/lang/String;");
            if (mid != 0)
            {
                jstring result = (jstring)(*env)->CallObjectMethod(env, this, mid);
                const char* str = (*env)->GetStringUTFChars(env, result, 0);
				LOGI("Result of sayHello: %s\n\n", str);
                printf("Result of sayHello: %s\n", str);
				(*env)->ReleaseStringUTFChars(env, result, str);
            }
}

//输入常用的数值类型 Boolean,Byte,Char,Short,Int,Float,Double
JNIEXPORT void JNICALL native_displayParms(JNIEnv *env, jobject this, jstring s, jint i, jboolean b)
{
	const char* szStr = (*env)->GetStringUTFChars(env, s, 0 );
	LOGI( "String = [%s]\n", szStr );
    printf( "String = [%s]\n", szStr );
	LOGI( "int = %d\n", i );
    printf( "int = %d\n", i );
	LOGI("boolean = %s\n", (b==JNI_TRUE ? "true" : "false"));
    printf( "boolean = %s\n", (b==JNI_TRUE ? "true" : "false") );
    (*env)->ReleaseStringUTFChars(env, s, szStr );
}

///输入一个数组,这里输入的是一个Boolean类型的数组
JNIEXPORT void JNICALL native_setArray(JNIEnv *env, jobject this, jbooleanArray ba)
{
    jboolean* pba = (*env)->GetBooleanArrayElements(env,ba, 0 );
    jsize len = (*env)->GetArrayLength(env, ba);
    int i=0;
    // change even array elements
    for( i=0; i < len; i+=2 )
    {
        pba[i] = JNI_FALSE;
        printf( "boolean = %s\n", (pba[i]==JNI_TRUE ? "true" : "false") );
		LOGI( "boolean = %s\n", (pba[i]==JNI_TRUE ? "true" : "false") );
    }
    (*env)->ReleaseBooleanArrayElements(env, ba, pba, 0 );
}

////返回一个字符串数组
JNIEXPORT jobjectArray JNICALL native_getStringArray(JNIEnv * env, jobject this)
{
	jstring str;
	jobjectArray args = 0;
	jsize len = 5;
	int   i=0;
	char * sa[]=  { "Hello,", "world!", "JNI", "is", "fun" };
	args = (*env)->NewObjectArray(env,len,(*env)->FindClass(env,"java/lang/String"),0);
    for( i=0; i < len; i++ )
    {
        str = (*env)->NewStringUTF(env, sa[i] );
        (*env)->SetObjectArrayElement(env, args, i, str);
    }
    return args;
}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    getStruct
 * Signature: ()Lcom/skywang/ndk/DiskInfo;
 */

//返回一个结构,这里返回一个硬盘信息的简单结构类型
JNIEXPORT jobject JNICALL native_getStruct(JNIEnv *env , jobject this)
{
	 /* 下面为获取到Java中对应的实例类中的变量*/

    //获取Java中的实例类
    jclass objectClass = (*env)->FindClass(env,"com/skywang/ndk/DiskInfo");
	jmethodID mid = (*env)->GetMethodID(env, objectClass, "<init>","()V");
    jobject obj   = (*env)->NewObject(env, objectClass, mid); 

    //获取类中每一个变量的定义
    //名字
    jfieldID str = (*env)->GetFieldID(env,objectClass,"name","Ljava/lang/String;");
	if(str != 0)
	{
		LOGI("str !=0 \n");
	}

    //序列号
    jfieldID ival = (*env)->GetFieldID(env,objectClass,"serial","I");

	if(ival != 0)
	{
		LOGI("ivals !=0 \n");
	}

    //给每一个实例的变量付值
    (*env)->SetObjectField(env, obj, str, (*env)->NewStringUTF(env,"my name is D:"));
    (*env)->SetIntField(env, obj, ival, 10);

    return obj;
}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    getStructArray
 * Signature: ()[Lcom/skywang/ndk/DiskInfo;
 */
//返回一个结构数组,返回一个硬盘信息的结构数组
JNIEXPORT jobjectArray JNICALL native_getStructArray(JNIEnv *env, jobject this)
{
	//申明一个object数组
    jobjectArray args = 0;

    //数组大小
    jsize        len = 5;

    //获取object所属类,一般为ava/lang/Object就可以了
    jclass objClass = (*env)->FindClass(env, "java/lang/Object");

    //新建object数组
    args = (*env)->NewObjectArray(env, len, objClass, 0);

    /* 下面为获取到Java中对应的实例类中的变量*/

    //获取Java中的实例类
    jclass objectClass = (*env)->FindClass(env, "com/skywang/ndk/DiskInfo");
    jmethodID mid = (*env)->GetMethodID(env, objectClass, "<init>","()V");
    jobject obj   = (*env)->NewObject(env, objectClass, mid); 

    //获取类中每一个变量的定义
    //名字
    jfieldID str = (*env)->GetFieldID(env, objectClass,"name","Ljava/lang/String;");
    //序列号
    jfieldID ival = (*env)->GetFieldID(env, objectClass,"serial","I");

    //给每一个实例的变量付值,并且将实例作为一个object,添加到objcet数组中
	int i = 0;
    for(i=0; i < len; i++ )
    {
        //给每一个实例的变量付值
        jstring jstr = nativeTojstring(env,"我的磁盘名字是 D:");
		//jstring jstr = stoJstring(env,"我的磁盘名字是 D:");
        //(env)->SetObjectField(_obj,str,(env)->NewStringUTF("my name is D:"));
        (*env)->SetObjectField(env, obj, str, jstr);
        (*env)->SetIntField(env, obj, ival, 10);

        //添加到objcet数组中
        (*env)->SetObjectArrayElement(env, args, i, obj);
    }
    //返回object数组
    return args;

}

/*
 * 根据index获取Person信息。
 * 参数说明:
 *         env : JNI 接口指针。
 *        claszz : Java 类对象。
 *        person : 输入参数,java对象
 *        index : 输入参数,序列号。
 */
JNIEXPORT jint JNICALL
getPersonInfoByIndex(JNIEnv *env, jobject clazz, jobject person, jint index)
{
	//若index无效,则直接返回-1
	if((int)index < 0 || (int)index>=GPERSON_NUM)
		return -1;

	// 将Person数组(gPersons)中的第index个成员赋值给pPerson指针
    Person *pPerson = &gPersons[index];

	//设置java对象person的nName
	jstring name = (*env)->NewStringUTF(env, pPerson->mName);
	(*env)->SetObjectField(env, person, gPersonOffsets.name, name);

    // 设置java对象person的mAge
    (*env)->SetIntField(env, person, gPersonOffsets.age, pPerson->mAge);
    // 设置java对象person的mHeight
    (*env)->SetFloatField(env, person, gPersonOffsets.height, pPerson->mHeight);

    LOGD("%s index-%d  mName:%s, mAge:%d, mHeight:%f\n",
            __func__, index, pPerson->mName, pPerson->mAge, pPerson->mHeight);

    return 0;
}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    GetNativeString
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
jstring JNICALL native_GetNativeString(JNIEnv *env, jobject obj, jstring str)
 {
	const char * pStr;
	const char * pUTF8Str = "From jni String";
	char outbuff[128] = {0};

	//获取传入字串中的所有字串
    pStr = (*env)->GetStringUTFChars(env, str, NULL);
    if (pStr == NULL)
       return NULL;
    strcat(outbuff, pStr);
    (*env)->ReleaseStringUTFChars(env, str, pStr); //这里要释放,否则内存泄漏
    strcat(outbuff, "/"); //加一个分隔符
    //从传入字串第三个位置开始,获取4个,到字串尾
    (*env)->GetStringUTFRegion(env, str, 3, 4, outbuff + strlen(outbuff));
    strcat(outbuff, "/");    //加一个分隔符
    strcat(outbuff, pUTF8Str);    //联接一个本地字串
    //从buff中构建一个jstring返回给java,这个新构建的字串由虚拟机负责回收
    return (*env)->NewStringUTF(env, outbuff);
 }

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    SumArray
 * Signature: ([II)I
 */
JNIEXPORT jint JNICALL native_SumArray(JNIEnv * env, jobject obj, jintArray arr, jint length)
{
	int i, sum = 0;
	jint *pOutbuf = NULL;
	if(length > 0)
         pOutbuf = (jint*) malloc(length * sizeof(jint));//开辟内存
    else
         return 0;

	(*env)->GetIntArrayRegion(env, arr, 0, length, pOutbuf);//获取int数组
	for(i = 0; i < 10; i++)
	{
		sum += pOutbuf[i];
	}
	free(pOutbuf);
	return sum;
}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    SumArrayA
 * Signature: ([I)I
 */
 /*
 *
 *    ReleaseIntArrayElements
 *        第三个参数就是决定更新与否的。
 *             取值 零(0) 时,更新数组并释放所有元素;
 *             取值 JNI_COMMIT 时,更新但不释放所有元素;
 *             取值 JNI_ABORT 时,不作更新但释放所有元素;
 *      #define JNI_COMMIT 1 // copy content, do not free buffer
 *      #define JNI_ABORT  2 // free buffer w/o copying back ^/
 *         //获取数组长度,注意jarray是指所有类型j<类型>array
 *         typedef jarray jintArray //其他的jbyteArray或jfloatArray都是jarray.
 *       jsize       (*GetArrayLength)(JNIEnv*, jarray);
 */
JNIEXPORT jint JNICALL native_SumArrayA(JNIEnv * env, jobject obj, jintArray arr)
{
	int i, j, sum = 0;
	jint* buf;
	j = (*env)->GetArrayLength(env, arr);
	//另外,这里返回的值,是jint*,不是const jint*,也就是说可以对其中的值进行修改
    buf = (*env)->GetIntArrayElements(env, arr, NULL);//这一句其实也告java内存回收器,不要回收arr数组的内存,或者不要整理内存
                                                      //如果回收器,回收和整理内存,那么我们在c中,访问的地址就可能错了
	for(i = 0; i < j; i++)//这里是求和
	{
		sum += buf[i];
	}

	//现在我们来修改一下buf中的元素,看看返回后,会不会把buf中的值,更新到java中的arr里去
	//经过验证修改是成功的
    buf[0] = 100;
    buf[1] = 200;

    (*env)->ReleaseIntArrayElements(env, arr, buf, 0);//调用这个方法,告诉java内存回收器,我忆用完了arr,,现在可以回收arr的内存了
    return sum;

}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    AccessField
 * Signature: ()V
 */
 /**
 *    访问java中的成员[通用的逻辑]
 *    注意:访问的是java中非静态成员,非静态成员是属于对象的.另外还要访问静态成员,静态成员属于类
 *    步骤:
 *    1:先找到对象的类
 *    2:根据成员的名称和类型,获取该成员的id引用
 *    3:根据id引用,获取该成员的域引用
 *    4:根据域引用再得到具体的内容
 *
 */
JNIEXPORT void JNICALL native_AccessField(JNIEnv *env, jobject obj)
{
	jclass cls;//void* 指针
	jfieldID fid;//抽象的结构体指针
    jstring jstr;//void*指针
    jint value;
    const char* str;

	cls = (*env)->GetObjectClass(env,obj);//得到类的引用
	fid = (*env)->GetFieldID(env, cls, "myString", "Ljava/lang/String;");//得到成员id的引用

	if( fid == NULL ){//检测根据给定的信息是否找到了id,
        return ;
    }

	jstr = (*env)->GetObjectField(env, obj, fid);//得到对象的引用
    str = (*env)->GetStringUTFChars(env, jstr, NULL);//从对象引用中得到内容
    if( str == NULL ){
        return ;
    }

	//printf(" c.s = "%s"\n", str ) ;
	LOGI(" c.s = %s\n", str );
	(*env)->ReleaseStringUTFChars(env, jstr, str);//更新或释放,不过最好用SetObjectField来操作。

	jstr = (*env)->NewStringUTF(env, "accedfild");//创建一个新的字串,这个是用java的方法创建的
    if( jstr == NULL ){
        return ;
    }
    //用jstr,更新obj对象的fid域.
    (*env)->SetObjectField(env, obj, fid, jstr);//设置域对象

	    //===============访问int静态成员=======================
    fid = (*env)->GetStaticFieldID(env,cls,"si","I");
    if(NULL == fid)
        return;
    value = (*env)->GetStaticIntField(env, cls, fid);//注意第二个参数是类,不是对象,因为是静态成员
    value = 100;
    (*env)->SetStaticIntField(env, cls, fid, 100);
    //===============访问String静态成员=======================
    fid = (*env)->GetStaticFieldID(env, cls, "helloString", "Ljava/lang/String;");
    jstr = (*env)->GetStaticObjectField(env, cls, fid);//注意第二个参数是类,不是对象,因为是静态成员
    str = (*env)->GetStringUTFChars(env, jstr, NULL);
    //可以对str做一些处理
    (*env)->ReleaseStringUTFChars(env, jstr, str);
    jstr = (*env)->NewStringUTF(env, "static string");
    (*env)->SetStaticObjectField(env, cls, fid, jstr);//注意第二个参数是类,不是对象,因为是静态成员

    return;
}

/*
 * Class:     com_skywang_ndk_NdkLoad
 * Method:    AccessMethod
 * Signature: ()V
 */
 /*
 * 访问java中的方法
 * 并传递了所有java中的数据类型,对象类型除外
 *
 *
 */
JNIEXPORT void JNICALL native_AccessMethod(JNIEnv *env, jobject obj)
{
	   jclass cls;
    jmethodID mid;
    const char  *str = "hello call back";
    jstring jstr;

    jboolean    z = 1;
    jbyte       b = 0xff;
    jchar       c = 'c';
    jshort      s = 60;
    jint        i = 100;
    jlong       j = 568978523;
    jfloat      f = 125643.22222;
    jdouble     d = 123456789.12654789;
    //jobject     l = ;

    cls = (*env)->GetObjectClass(env,obj);//得到类的引用

    //从静态方法中得到str,再传回给callback方法
    mid = (*env)->GetStaticMethodID(env, cls,"callStaticBack","()Ljava/lang/String;");
    jstr = (*env)->CallStaticObjectMethod(env,cls,mid);

    mid = (*env)->GetMethodID(env, cls, "callback", "(Ljava/lang/String;IBCZJDFS)V");

    if (mid == NULL) {
        return; /* method not found */
    }
    //printf("In C\n");

    //jstr = (*env)->NewStringUTF(env, str);
    (*env)->CallVoidMethod(env, obj, mid,jstr,i,b,c,z,j,d,f,s);
}

// Java和JNI函数的绑定表
static JNINativeMethod method_table[] = {
    { "HelloLoad", "()Ljava/lang/String;", (void*)native_hello },//绑定
	{"add", "(II)I", (void*)native_add},
	{"change", "()V", (void*)native_change},
	{"change_int", "()V", (void*)native_change_int},
	{"calljavamethod", "()V", (void*)native_calljavamethod},
	{"displayParms", "(Ljava/lang/String;IZ)V", (void*)native_displayParms},
	{"setArray", "([Z)V", (void*)native_setArray},
	{"getStringArray", "()[Ljava/lang/String;", (void*)native_getStringArray},
	{"getStruct", "()Lcom/skywang/ndk/DiskInfo;", (void*)native_getStruct},
	{"getStructArray", "()[Lcom/skywang/ndk/DiskInfo;", (void*)native_getStructArray},
	{"getPersonInfoByIndex", "(Lcom/skywang/ndk/Person;I)I", (void*)getPersonInfoByIndex },//绑定
	{"GetNativeString", "(Ljava/lang/String;)Ljava/lang/String;", (void*)native_GetNativeString},//绑定
    {"SumArray", "([II)I", (void*)native_SumArray},//绑定
	{"SumArrayA", "([I)I", (void*)native_SumArrayA},//绑定
	{"AccessField", "()V", (void*)native_AccessField},//绑定
	{"AccessMethod", "()V", (void*)native_AccessMethod},//绑定
};

char* jstringToNative(JNIEnv *env, jstring jstr)
{
	if ((*env)->ExceptionCheck(env) == JNI_TRUE || jstr == NULL)
	{
		(*env)->ExceptionDescribe(env);
		(*env)->ExceptionClear(env);
		printf("jstringToNative函数转换时,传入的参数str为空");
		return NULL;
	} 

	jbyteArray bytes = 0;
	jthrowable exc;
	char *result = 0;
	if ((*env)->EnsureLocalCapacity(env,2) < 0)
	{
		return 0; /* out of memory error */
	}
	jclass jcls_str = (*env)->FindClass(env,"java/lang/String");
	jmethodID MID_String_getBytes = (*env)->GetMethodID(env,jcls_str, "getBytes", "()[B"); 

	bytes = (jbyteArray)(*env)->CallObjectMethod(env,jstr, MID_String_getBytes);
	exc = (*env)->ExceptionOccurred(env);
	if (!exc)
	{
		jint len = (*env)->GetArrayLength(env, bytes);
		result = (char *)malloc(len + 1);
		if (result == 0)
		{
			//JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 	0);
			(*env)->DeleteLocalRef(env,bytes);
			return 0;
		}
		(*env)->GetByteArrayRegion(env,bytes, 0, len, (jbyte *)result);
		result[len] = 0; /* NULL-terminate */
	}
	else
	{
		(*env)->DeleteLocalRef(env, exc);
	}
	(*env)->DeleteLocalRef(env, bytes);
	return (char*)result;
} 

jstring nativeTojstring( JNIEnv* env,const char* str )
{
	#if 0
	jclass strClass = (*env)->FindClass(env, "java/lang/String");
	jmethodID ctorID = (*env)->GetMethodID(env, strClass, "<init>",
		"([BLjava/lang/String;)V"); 

	if ((*env)->ExceptionCheck(env) == JNI_TRUE || str == NULL)
	{
		(*env)->ExceptionDescribe(env);
		(*env)->ExceptionClear(env);
		printf("nativeTojstring函数转换时,str为空/n");
		return NULL;
	} 

	jbyteArray bytes = (*env)->NewByteArray(env, strlen(str));
	//如果str为空则抛出异常给jvm

	(*env)->SetByteArrayRegion(env, bytes, 0,  strlen(str), (jbyte*)str);
	//jstring encoding = env->NewStringUTF( "GBK");
	jstring encoding = (*env)->NewStringUTF(env, "UTF8");
	jstring strRtn = (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);
	//释放str内存
	// free(str);
	return strRtn;
	#endif

			//定义java String类 strClass
	jclass strClass = (*env)->FindClass(env,"java/lang/String");
	//获取java String类方法String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String
	jmethodID ctorID = (*env)->GetMethodID(env, strClass, "<init>", "([BLjava/lang/String;)V");
	//建立byte数组
	jbyteArray bytes = (*env)->NewByteArray(env, (jsize)strlen(str));
	//将char* 转换为byte数组
	(*env)->SetByteArrayRegion(env, bytes, 0, (jsize)strlen(str), (jbyte*)str);
	//设置String, 保存语言类型,用于byte数组转换至String时的参数
	jstring encoding = (*env)->NewStringUTF(env, "utf-8");
	//将byte数组转换为java String,并输出
	return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);

}

//char* to jstring
jstring stoJstring(JNIEnv* env, const char* pat)
{
       jclass strClass = (*env)->FindClass(env, "java/lang/String");
       jmethodID ctorID = (*env)->GetMethodID(env, strClass, "<init>", "([BLjava/lang/String;)V");
       jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));
       (*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);
       jstring encoding = (*env)->NewStringUTF(env, "utf-8");
       return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);
}  

// 注册native方法到java中
static int registerNativeMethods(JNIEnv* env, const char* className,
        JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

// 初始化函数,用于获取Java中各个成员对应的fieldID。
static void nativeClassInit (JNIEnv *env)
{
    jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS);
    // 获取Person的mName成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.name     = (*env)->GetFieldID(env, personClass, "mName"  , "Ljava/lang/String;");
    // 获取Person的mAge成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.age      = (*env)->GetFieldID(env, personClass, "mAge"   , "I");
    // 获取Person的mHeight成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.height   = (*env)->GetFieldID(env, personClass, "mHeight", "F");
}

int register_ndk_load(JNIEnv *env)
{
    nativeClassInit(env);

    // 调用注册方法
    return registerNativeMethods(env, JNIREG_CLASS,
            method_table, NELEM(method_table));
}

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1; 

    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return result;
    }   

    register_ndk_load(env);

    // 返回jni的版本
    return JNI_VERSION_1_4;
}

    上面的代码我已经添加了比较详细的代码注释了,只要有一定的jni基础的就能看懂了,这些代码片段是我整理网上的一些相关片段同时我一一运行验证过了,并且加上了一些自己的注释。jni基本的和重要的一些用法大概就这些了,如果大家想更加详细的了解jni编程可以详细的看看jni编程指南,它比较详细的讲解了jni的相关知识。希望上述能对大家学习jni有帮助。
时间: 2024-11-09 00:19:57

android下jni开发总结的相关文章

cocos搭建android下的开发环境

没想到cocos3.2也出现了一点bug,还要经过一周晚上的努力,全部搞定.可以在android下使用啦 上个截图庆祝下 有需要的可以看http://item.taobao.com/item.htm?id=40745006457 cocos搭建android下的开发环境,布布扣,bubuko.com

Android的JNI开发

变量的定义 int i; typedef int x;//定义一个int x数据类型 x a=10; printf("size=%d",sizeof(i));//获取int类型长度(4个字节) system("pause");//不让窗体立即消失 循环 在c语言中,循环的变量必须在外面生命 int i for(i=0;i<10;i++){ printf("i=%d",i); } 指针变量 int i=10; int* p;//声明一个指针变

android下NDK开发环境搭建及TestJNI入门实例完整过程

1.先搭建好基本的ndk的开发环境 在windows下安装下面两个软件 1. Android NDK 安装 2. 安装Cygwin与使用NDK编译 本文建立在已经完成Android开发环境搭建的基础上.其基础环境至少需要包含以下内容: 1. JDK 2. Eclipse 3. Android SDK and ADT 一.Android NDK 安装与配置 下载Android NDK.下载地址:http://developer.android.com/tools/sdk/ndk/index.htm

android之JNI开发环境搭建

研究了很久怎么编译.so动态库,感觉在linux的安卓源码下编译太麻烦了,所以就找网上找找有没有方便的办法. 现在终于实现了,现在一起总结下. 1.在windows环境下开发jni需要c/c++编译器的支持,使用GNUStep,下载地址http://www.gnustep.org/windows/installer.html. 2.下载安装后,验证是否成功.打开GNUstep->Shell,输入make -v 和 gcc -v命令,如图所示. 3.下载NDK,地址http://developer

实现Android Studio JNI开发C/C++使用__android_log_print输出Log

相信很多人在刚开始学习Android JNI编程的时候,需要输出Log,在百度Google搜索的时候都是说需要在Android.mk中加入LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib -llog ,其实这是在eclipse开发上的方式,Android Studio并不是这么使用. Android Studio的Android.mk是自动生成的,就算修改也是没用了,实际Android Studio的Android.mk是根据gradle文件生成的,那么就需要修改gradl

01_c++下jni开发说明

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBo

android下前端开发诡异bug记录&amp;解决方法

1.border-radius有bug,围不住background 描述:设置了border-radius后,背景色依然会从圆角里冒出来 解决方法:在设置了border-radius的容器加上background-clip:padding-box;一定要把background样式提到background-clip样式前!!(被这个bug坑死了,花了大半天时间在近乎绝望的情况下找出了原因) 不断补充中…

linux下JNI开发—HelloWord为例

转自:https://www.cnblogs.com/snake-hand/archive/2012/05/25/2517412.html 前期准备: 1.Java JDK 2.gcc 3.g++ 确保上述准备工作完成后开始下边的工作: Java代码: public class Hello { static { try { System.loadLibrary("HelloWord" ); } catch (UnsatisfiedLinkError e) { e.printStackT

Android Studio下jni应用

最近在将一个小应用从eclipse开发迁移到android studio,程序中有native代码实现,在eclipse是靠Android.mk这么个mk文件来组织编译的,但到android studio上就不行了,因其是靠gradle组织,所以makefile里的配置要转换为build.gradle里的语句(尽管实际上gradle也是组织一个mk文件),同时在迁移过程中遇到了一些问题,这里记录一下,以备后查. Android的JNI开发主要有两中情况:一种是使用已经编译好的.so动态库:一种是