报错如下:
在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方法IDjmethodID setReadOnlyID = (*env)->GetMethodID(env, fileClass, "setReadOnly", "()Z");if (setReadOnlyID == NULL) {LOGI("找到setReadOnly方法");}//调用方法(*env)->CallBooleanMethod(env, file,fileClass,setReadOnlyID);
}
方法者找到了,不报方法找不到的错误了,但最终还是报了其他的错。
搜了一下,用反射调用setReadOnly可能有各种兼容问题:
还是放弃反射调用吧,还是回调到java里设置setReadOnly吧。