JNI中Kotlin和C++相互调用例子通解
一、概述
案例:回顾JNI开发,主要回顾Java调用C/C++函数及C/C++调用Java类的方法
1.JNI与Java数据类型对照表:
2.JNI各种签名对照表:
二、Java和C/C++相互操作的示例代码
1.定义一个Person.kt实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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++方法的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** * 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.具体的调用类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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的案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #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); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探