DexclassLoader读取dex在Android14上遇到问题

报错如下:

在Android 14(API 级别 34)及以后版本中,DexClassLoader 被进一步限制,只能用于加载只读文件中的代码。这意味着你不能再使用 DexClassLoader 来加载从应用的内部存储空间中读取的文件。

我想通过JNI来修改只读文件,网上查找的方案如下:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
 
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_yourapp_FileUtils_setFileReadOnly(JNIEnv *env, jobject obj, jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);
    int result = chmod(path, S_IRUSR);
    env->ReleaseStringUTFChars(path_, path);
 
    if (result == -1) {
        // 错误处理
        return JNI_FALSE;
    }
 
    return JNI_TRUE;
}

C语言中提示修改成功。但是使用DexClassLoader的时候还是报上面一样的错误,应该是修改已读没有修改成功。

于是我换方案,通过反射调用Java中File类的setReadOnly方法试一下,代码如下:

//反射创建Java中的File对象
JNIEXPORT jobject JNICALL
Java_FileUtils_createFile(JNIEnv *env, jobject obj, jstring path) {
    // 获取File类
    jclass fileClass = (*env)->FindClass(env, "java/io/File");
    if (fileClass == NULL) {
        return NULL; // 类未找到
    }

    // 获取File(String path)构造器
    jmethodID ctorID = (*env)->GetMethodID(env, fileClass, "<init>", "(Ljava/lang/String;)V");
    if (ctorID == NULL) {
        return NULL; // 方法未找到
    }
    // 使用构造器创建File对象
    jobject fileObject = (*env)->NewObject(env, fileClass, ctorID, path);

    return fileObject;
}

//反射调用setReadOnly方法
JNIEXPORT void JNICALL
Java_FileUtils_setJavaFileReadOnly(JNIEnv *env, jobject obj, jstring path) {

    jobject  file = Java_FileUtils_createFile(env,obj,path);

    // 获取File类
    jclass fileClass = (*env)->FindClass(env, "java/io/File");
    if (fileClass == NULL) {
        LOGI("找到File class");
    }
    // 获取setReadOnly方法ID
    jmethodID setReadOnlyID = (*env)->GetMethodID(env, fileClass, "setReadOnly", "()Z");
    if (setReadOnlyID == NULL) {
        LOGI("找到setReadOnly方法");
    }
    //调用方法
  (*env)->CallBooleanMethod(env, file,fileClass,setReadOnlyID);
}

方法者找到了,不报方法找不到的错误了,但最终还是报了其他的错。

搜了一下,用反射调用setReadOnly可能有各种兼容问题:

还是放弃反射调用吧,还是回调到java里设置setReadOnly吧。