jni 开发 c调用java

上一篇文章是java如何调用c ,这篇文章是c如何调用 java 


c调用java一共分为5步:

1:编写java native方法

2生成对应的头文件

3复制头文件到visule studio中

4查询方法和属性的签名,实现native方法

5编译生成.dll动态库,复制动态库到项目,然后调用


1:编写java native方法 以及要调用的方法

	public native int ranNum();


//	产生随机数  要被native调用的方法
	public int getRandomNum(int max) {
		return (new Random()).nextInt(max);
	}

2生成对应的头文件    在当前src目录下 使用命令行执行javah ,然后刷新项目,后会有头文件




3复制头文件到visule studio中

打开visual studio 创建新项目,把  jni.h  jni_md.h(这两个文件在AndroidSDK中)以刚才及java工程生成的 com_ake_Test_test.h头文件一起拷贝到visual studio中

头文件右键->添加->现有项,之后如下图


4查询方法和属性的签名,实现native方法

在命令行中  java项目的bin 目录下执行javap 命令,然后在执行javap -s -p com.ake.Test.test(类的全名)


执行完javap -s -p之后如图  系统会把当前类所有的成员变量和属性方法的签名都列出来



在这个列表中我们找到

  public int getRandomNum(int);
    descriptor: (I)I
这个方法的签名就是   (I)I


然后打开visual studio 把java 生成的头文件复制进来


然后就是写个str.c 文件实现这个方法



5编译生成.dll动态库,复制动态库到项目,然后调用

在 Visual studio 中 

选择工具栏中 debug--配置管理器--活动解决方案平台--新建--选择新平台--x64(我的电脑是64位)

配置项目生成.dll动态链接库

项目右键--常规--项目默认值--配置类型--动态库(.dll)

最后运行生成解决方法,然后复制根目录x64 --debug--.dll到java工程根目录

java调用  System.load("D:\\Android\\workspace3\\JniTest\\Project2.dll");  这里要写绝对路径


这是个基本流程, 同样访问 c 访问java的成员变量也是一样的流程,只是在c代码的实现是不一样的



 
 

//c 访问java 成员属性的实现

JNIEXPORT jstring JNICALL Java_com_ake_Test_test_accessStaticField (JNIEnv *env, jobject obj){ //1 获取obj对象 jclass cls=(*env)->GetObjectClass(env, obj); //2获取属性id jfieldID id=(*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;"); // printf("jstr:%#x\n", &id); //获取属性值 jstring js=(*env)->GetObjectField(env, obj,id); // printf("jstr:%#x\n", &js); char * ori=(*env)->GetStringUTFChars(env, js, JNI_FALSE); // printf("new_jstr:%s\n", ori); //修改属性值 char* test = "mimi"; strcat(test,ori); //设置属性值 jstring s = (*env)->NewStringUTF(env, test); (*env)->SetObjectField(env, obj,id,s); return ori; }

// c访问 java 方法的实现

JNIEXPORT jint JNICALL Java_com_ake_Test_test_ranNum (JNIEnv *env, jobject obj){ //获取class 对象 jclass cls= (*env)->GetObjectClass(env, obj); //获取方法ID 最后一个参数是我们在命令行中查到的方法的签名 jmethodID id= (*env)->GetMethodID(env, cls, "getRandomNum", "(I)I"); //调用该方法 jint i=(*env)->CallIntMethod(env, obj, id); return i; }

他们的实现套路是一样的:

1获取jclass 对象

2获取 方法或者属性 id

3获取方法或者属性 

4修改成员的值或返回方法的值


这获取方法或者属性想id时要求传入 签名  sign  下图有对应关系  如果想偷懒就用命令行在 java bin目录下 javap /javap -s -p看一xia

成员属性的签名可以直接抄就行了,方法的签名格式  (type)type  也就是  用()拼上参数的签名和返回值的签名  例如java 方法  

public static String getUUID(){
return UUID.randomUUID().toString();
}

签名为  ()Ljava/lang/String;   


public static void soutsom(){
System.out.println("soutsom 被调用!");
}

签名为 ()V



好了,谢谢大家能把它看完,有问题欢迎联系我!











猜你喜欢

转载自blog.csdn.net/qq_35599978/article/details/72811826