JNI中Kotlin和C++相互调用例子通解
一、概述
案例:回顾JNI开发,主要回顾Java调用C/C++函数及C/C++调用Java类的方法
1.JNI与Java数据类型对照表:
2.JNI各种签名对照表:
二、Java和C/C++相互操作的示例代码
1.定义一个Person.kt实体
package com.yw.player.myjni import android.util.Log /** * 人 */ class Person( var name: String? = "洛洛杨", var age: Int = 0 ) { fun getPersonString(): String { return "$TAG $name | $age 岁" } companion object { val TAG = "YW_JNI_LOG" @JvmStatic//需要加上@JvmStatic不然jni中C++调用kotlin的静态方法会找不到方法名 fun getPersonName(): String { return "洛洛杨" } @JvmStatic fun setPersonName(name: String) { Log.e("$TAG", name) } } }
2.定义一个调用C/C++方法的类
** * JNI测试工具类 * 主要测试C++调用Java以及Java调用C++ */ class MyJNI { /** * 操作单属性 */ external fun addPerson(name:String,age:Int) /** * 操作数组 * @param names 小名和大名 * @param ages 阴历和阳历 */ external fun optionArrays(names:Array<String>,ages:IntArray) /** * 操作直接传过去的对象 */ external fun addPerson(bean:Person) /** * 操作未传过去的对象 */ external fun optionObject() }
3.具体的调用类
jniBean = MyJNI() jniBean?.addPerson("洛洛杨,我儿子",4) var names = arrayOf<String>("洛洛杨","小洛洛") var ages = IntArray(2) ages[0] = 3 ages[1] = 4 jniBean?.optionArrays(names,ages) jniBean?.addPerson(Person().apply{ name = "小洛洛小宝宝" age = 4; }) jniBean?.optionObject()
4.Java调用C/C++的具体实现方法及C/C+调用Java的案例
#include <jni.h> #include <string> #include <android/log.h> #define TAG "YW_JNI_LOG" // 这个是自定义的LOG的标识 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型 #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型 #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型 /** * 操作普通内容 */ extern "C" JNIEXPORT void JNICALL Java_com_yw_player_myjni_MyJNI_addPerson__Ljava_lang_String_2I(JNIEnv *env, jobject thiz, jstring name, jint age) { //获取从Java传递过来的String参数 const char *c_name = env->GetStringUTFChars(name, 0); LOGE("用户名:%s", c_name); LOGE("年龄:%d", age); //释放String字符串 env->ReleaseStringUTFChars(name, c_name); } /** * 操作数组 */ extern "C" JNIEXPORT void JNICALL Java_com_yw_player_myjni_MyJNI_optionArrays(JNIEnv *env, jobject thiz, jobjectArray names, jintArray ages) { int size = env->GetArrayLength(names); for (int i = 0; i < size; i++) { jstring name_index = static_cast<jstring>(env->GetObjectArrayElement(names, i)); const char *c_name = env->GetStringUTFChars(name_index, NULL); LOGE("姓名:%s", c_name); env->ReleaseStringUTFChars(name_index, c_name); } jint *ages_arr = env->GetIntArrayElements(ages,NULL); int ageSize = env->GetArrayLength(ages); for (int i = 0; i < ageSize; i++) { LOGE("年龄:%d", *(ages_arr+i)); } } /** * 在C++中操作java * 中的对象 */ extern "C" JNIEXPORT void JNICALL Java_com_yw_player_myjni_MyJNI_addPerson__Lcom_yw_player_myjni_Person_2(JNIEnv *env, jobject thiz, jobject bean) { //在C++中操作Java类 //操作person中的方法 jclass beanClass = env->GetObjectClass(bean);//获取字节码 //获取对象方法 jmethodID getPersonStringId = env->GetMethodID(beanClass,"getPersonString", "()Ljava/lang/String;"); jstring returnStr = static_cast<jstring>(env->CallObjectMethod(bean,getPersonStringId)); const char * c_str = env->GetStringUTFChars(returnStr,NULL); LOGE("返回的字符串为:%s",c_str); env->ReleaseStringUTFChars(returnStr,c_str); //操作对象的静态方法-->带返回值 jmethodID staticMethodId = env->GetStaticMethodID(beanClass,"getPersonName","()Ljava/lang/String;"); jstring static_name = static_cast<jstring>(env->CallStaticObjectMethod(beanClass,staticMethodId)); const char * static_c_name = env->GetStringUTFChars(static_name,NULL); env->ReleaseStringUTFChars(static_name,static_c_name); LOGE("静态方法返回的姓名为:%s",static_c_name); //操作对象的静态方法,带参数 jmethodID staticMethodId2 = env->GetStaticMethodID(beanClass,"setPersonName", "(Ljava/lang/String;)V"); jstring str2 = env->NewStringUTF("老杨是洛洛杨的老爸");//需要new一个jstring字符串 env->CallStaticVoidMethod(beanClass,staticMethodId2,str2); //操作属性 jfieldID fieldId = env->GetFieldID(beanClass,"name","Ljava/lang/String;"); jstring fieldValue = env->NewStringUTF("洛洛杨小宝宝真是个小天才"); env->SetObjectField(bean,fieldId,fieldValue); jstring fieldValue2 = static_cast<jstring>(env->GetObjectField(bean,fieldId)); const char* c_fieldValue2 = env->GetStringUTFChars(fieldValue2,NULL); LOGE("更改属性后的值:%s",c_fieldValue2); } /** * 操作未传过去的对象 */ extern "C" JNIEXPORT void JNICALL Java_com_yw_player_myjni_MyJNI_optionObject(JNIEnv *env, jobject thiz) { //创建一个java的class对象 jclass beanClass = env->FindClass("com/yw/player/myjni/Person"); LOGE("创建Class对象成功"); //创建构造方法(构造函数需要传<init>) jmethodID constructorMethodId = env->GetMethodID(beanClass,"<init>","(Ljava/lang/String;I)V"); jstring name = env->NewStringUTF("您好啊,洛洛杨小宝宝"); LOGE("构造函数创建成功"); //创建一个对象 jobject beanObject = env->NewObject(beanClass,constructorMethodId,name,4); LOGE("对象创建成功"); //调用方法 jmethodID getStringId = env->GetMethodID(beanClass,"getPersonString","()Ljava/lang/String;"); jstring returnStr = static_cast<jstring>(env->CallObjectMethod(beanObject,getStringId)); const char * returnStr_c = env->GetStringUTFChars(returnStr,NULL); LOGE("返回值的字符串为:%s",returnStr_c); }