Jni 反射 Kotlin 静态内部类成员函数

名字有点绕口,大概意思是使用JNI反射一个Kotlin类的成员,这个成员是自定义类,并且我要调用这个类的函数。
在JAVA中调用一个static函数比较直接的,这个在百度上有比较多的例子。

如下

调用了JniHelper这个类的changeVoice静态函数

jclass clazz = jniEnv->FindClass("com/xiaomakj/voicechanger/utils/JniHelper");
    if (clazz == NULL) {
        LOGI("%s", "com/xiaomakj/voicechanger/utils/JniHelper");
        return;
    }
jmethodID  id = jniEnv->GetStaticMethodID(clazz, "changeVoice", "(Ljava/lang/String;II)V");
if (id == NULL) {
    LOGI("%s", "method reChangeVoice not found");
} else {
    jstring newpath = jniEnv->NewStringUTF("/storage/emulated/0/com.xiaomakj.voicechanger/newVoice.wav");
    //jstring thispath = stoJstring(jniEnv, path);
    jniEnv->CallStaticVoidMethod(clazz, id, newpath, mode, save);
    LOGI("%s", "env->CallStaticVoidMethod(clazz,id)");
}
然而

在Kotlin中我们知道是没有static修饰符的,而是被companion object{} 函数体统一包裹的方法体
如下:

 companion object {
       public fun setPosition(time: Int) {            
        }
    }
那么

我们使用调用Java的static函数的方式就会出现如下JNI DETECTED ERROR错误,既JNI找不到该函数的定义

JNI DETECTED ERROR IN APPLICATION: can't call void XXX on instance of java.lang.Class
接下来

我们看看是什么原因

步骤一

使用jadx-gui反编译发现其源码中生成了一个Companion的静态内部类
Jni 反射 Kotlin 静态内部类成员函数_第1张图片

步骤二

那么问题就比较好解决了:
我们只需要获取这个Companion静态成员,并调用其内部setPosition函数即可。

下面给出JIN的调用过程

#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"axe",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"axe",FORMAT,##__VA_ARGS__);

//获取OperationActivity和Companion的两个jclass 注意$Companion为内部类的意思
jclass OperationActivityClazz = jniEnv->FindClass(
        "com/xiaomakj/voicechanger/mvvm/ui/activity/OperationActivity");
jclass CompanionClazz = jniEnv->FindClass(
        "com/xiaomakj/voicechanger/mvvm/ui/activity/OperationActivity$Companion");
if (OperationActivityClazz == NULL) {
    LOGI("%s", "method OperationActivityClazz not found");
    return;
} 
//获取Companion成员ID(注意 参数1:OperationActivityClazz )
jfieldID OperationActivity$CompanionID = jniEnv->GetStaticFieldID(OperationActivityClazz, "Companion",                                                            "com/xiaomakj/voicechanger/mvvm/ui/activity/OperationActivity$Companion");
//获取Companion成员(注意 参数1:OperationActivityClazz )
jobject Companion = jniEnv->GetStaticObjectField(OperationActivityClazz, OperationActivity$CompanionID);
//获取Companion成员setPosition的函数ID(注意 参数1:CompanionClazz)
jmethodID OperationActivityClazzId = jniEnv->GetMethodID(CompanionClazz, "setPosition", "(I)V");
if (OperationActivityClazzId == NULL) {
    LOGI("%s", "method OperationActivityClazzId not found");
    return;
} 
//调用Companion成员setPosition的函数
jniEnv->CallVoidMethod(Companion, OperationActivityClazzId, pos);
//手动回收  避免内存泄露
jniEnv->DeleteLocalRef(OperationActivityClazz);
jniEnv->DeleteLocalRef(Companion);

你可能感兴趣的:(JNI)