Android JNI子线程调用FindClass抛出ClassNotFoundException问题求助
问题根因
你在自行创建的Native线程中调用AttachCurrentThread时,第二个参数传了nullptr,没有绑定应用的类加载器上下文。新attach的线程默认使用系统类加载器,仅能加载Android系统框架类,无法识别应用APK中内置的业务类,这就是报错中DexPathList仅指向系统库目录、找不到自定义TWMainActivity类的核心原因。你观察到的「配置jniLibs后才出问题」是干扰现象,和问题本身没有直接关联,不要因此走偏排查方向。
可行解决方案
- 方案1:提前缓存jclass全局引用(推荐,性能最优)
你已经验证过通过Java层传入的对象全局引用可以正常获取jclass,只需要在Java层触发的Native方法执行时,把拿到的jclass存为全局引用,后续Native线程直接复用即可,无需再调用FindClass。
示例代码:
extern "C" JNIEXPORT void JNICALL Java_com_tally_twandroidconsolesimulator_TWMainActivity_InitializeMain (JNIEnv * pEnv, jobject pObj) { // 原有逻辑不变,新增下面两行缓存jclass jclass localCls = pEnv->GetObjectClass(pObj); jclass g_mainActivityCls = (jclass)pEnv->NewGlobalRef(localCls); JavaVM * sJavaVm; jint jv_version = pEnv->GetVersion (); pEnv->GetJavaVM (&sJavaVm); jobject ref = pEnv->NewGlobalRef (pObj); std::thread thread1 (NativeThread, sJavaVm, jv_version, ref ); thread1.detach (); }
后续在NativeThread中直接使用全局缓存的g_mainActivityCls即可。
- 方案2:Attach线程时绑定应用类加载器
如果确实需要在Native线程动态查找不同类,可以在Attach的时候传入配置了应用类加载器的参数,让线程的类加载器可以识别应用内的类。
首先在Java层触发的Native方法中缓存应用类加载器全局引用:
jobject g_appClassLoader; // 全局变量存储类加载器 extern "C" JNIEXPORT void JNICALL Java_com_tally_twandroidconsolesimulator_TWMainActivity_InitializeMain (JNIEnv * pEnv, jobject pObj) { // 新增缓存类加载器逻辑 jclass activityCls = pEnv->GetObjectClass(pObj); jmethodID getClassLoaderMid = pEnv->GetMethodID(activityCls, "getClassLoader", "()Ljava/lang/ClassLoader;"); jobject localClassLoader = pEnv->CallObjectMethod(pObj, getClassLoaderMid); g_appClassLoader = pEnv->NewGlobalRef(localClassLoader); // 原有逻辑不变 JavaVM * sJavaVm; jint jv_version = pEnv->GetVersion (); pEnv->GetJavaVM (&sJavaVm); jobject ref = pEnv->NewGlobalRef (pObj); std::thread thread1 (NativeThread, sJavaVm, jv_version, ref ); thread1.detach (); }
然后修改Native线程的Attach逻辑:
static void NativeThread(JavaVM * pJavaVm, jint pJVersion, jobject pObjGblRfrnc){ JNIEnv * env; auto get_env_result = pJavaVm->GetEnv ((void **) &env, pJVersion); if (get_env_result == JNI_EDETACHED) { // 构造带类加载器的Attach参数 JavaVMAttachArgs attachArgs; attachArgs.version = pJVersion; attachArgs.name = "CustomNativeThread"; // 自定义线程名方便调试 attachArgs.group = nullptr; attachArgs.classLoader = g_appClassLoader; // 传入缓存的应用类加载器 if (pJavaVm->AttachCurrentThread(&env, &attachArgs) != JNI_OK) { return; } } // 此处调用FindClass已经可以正常找到应用类 jclass cls = env->FindClass ("com/tally/twandroidconsolesimulator/TWMainActivity"); //... 剩余业务代码 }
- 方案3:排查混淆配置
如果上述两种方案都未解决,检查gradle配置是否开启了R8/ProGuard混淆,如果开启了需要给你要查找的类添加混淆豁免规则,避免类名被混淆后FindClass找不到对应类。你提到相同代码在原生Android Studio项目中可以正常运行,大概率是原生项目默认未开启混淆,当前项目开启了混淆导致的,可以先临时关闭混淆验证问题是否消失。
内容的提问来源于stack exchange,提问作者TruthSeeker
相关产品推荐
相关产品推荐

