You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 14:18:02