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);
}
浙公网安备 33010602011771号