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);
}

  

 

posted on 2022-08-05 11:45  飘杨......  阅读(1537)  评论(0编辑  收藏  举报