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的靜態內部類
jadx

步驟二

那麼問題就比較好解決了:
我們只需要獲取這個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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章