报错如下:
在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吧。