使用BaseDexClassLoader侧载Activity后JNI实现无法找到的问题求解
问题根因
你遇到的报错核心原因是类加载器隔离:
Android系统中,全限定名相同的类如果由不同的ClassLoader实例加载,在JVM中会被识别为两个完全独立的类。直接安装启动时
com.company.app.Main由宿主应用的默认PathClassLoader加载,JNI库可以正常匹配静态命名的native方法;但侧载时该类由你新建的BaseDexClassLoader加载,和JNI库默认绑定的类不匹配,所以找不到对应实现。
可行解决方案
- 方案1:显式加载对应JNI库
如果可以修改侧载的Main类代码,在类中加入静态代码块,每次类被加载时主动加载对应so,触发JNI方法重绑定:
public class Main { static { // 替换为你对应的JNI库名称,比如编译的是libbranch.so就填"branch" System.loadLibrary("branch"); } public native void Branch(); public void Init(Context context) { Log.e(TAG, "Init: " + "SUCCESS"); Branch(); } }
如果无法修改侧载的dex代码,也可以在宿主代码调用侧载类的Init方法前,先调用System.loadLibrary("branch")加载对应so。
- 方案2:修改JNI实现为动态注册
不依赖JNI默认的静态命名匹配规则,在JNI库的JNI_OnLoad方法中主动为指定类注册native方法,查找类时适配不同ClassLoader加载场景:
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) { return -1; } jclass clz = (*env)->FindClass(env, "com/company/app/Main"); if (clz == NULL) { return JNI_VERSION_1_6; } // 注册native方法,替换为你对应的方法签名 JNINativeMethod methods[] = { {"Branch", "()V", (void*)Java_com_company_app_Main_Branch} }; (*env)->RegisterNatives(env, clz, methods, sizeof(methods)/sizeof(methods[0])); return JNI_VERSION_1_6; }
- 方案3:配置BaseDexClassLoader的父加载器
初始化BaseDexClassLoader的时候,将构造方法的最后一个parent参数传入宿主应用的PathClassLoader,让侧载的类优先被父加载器加载,保证和JNI绑定的类是同一个实例:
// 宿主中初始化BaseDexClassLoader的代码示例 BaseDexClassLoader loader = new BaseDexClassLoader( dexPath, optimizedDirectory, librarySearchPath, // 传入宿主的类加载器作为父加载器 getClassLoader() );
内容的提问来源于stack exchange,提问作者user11988193
相关产品推荐
相关产品推荐

