简书链接:插件化的新方式把插件apk的elementsField添加到系统的BaseDexClassLoader中去 文章字数:205,阅读全文大约需要1分钟 模板代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 String cachePath = context.getCacheDir().getAbsolutePath(); String apkPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/plugin.apk"; DexClassLoader dexClassLoader = new DexClassLoader(apkPath, cachePath, cachePath, context.getClassLoader()); // 第一步 找到 插件的Elements数组 dexPathlist ----?dexElement try { Class myDexClazzLoader=Class.forName("dalvik.system.BaseDexClassLoader"); Field myPathListFiled=myDexClazzLoader.getDeclaredField("pathList"); myPathListFiled.setAccessible(true); Object myPathListObject =myPathListFiled.get(dexClassLoader); Class myPathClazz=myPathListObject.getClass(); Field myElementsField = myPathClazz.getDeclaredField("dexElements"); myElementsField.setAccessible(true); // 自己插件的 dexElements[] Object myElements=myElementsField.get(myPathListObject); // 第二步 找到 系统的Elements数组 dexElements PathClassLoader pathClassLoader= (PathClassLoader) context.getClassLoader(); Class baseDexClazzLoader = Class.forName("dalvik.system.BaseDexClassLoader"); Field pathListFiled = baseDexClazzLoader.getDeclaredField("pathList"); pathListFiled.setAccessible(true); Object pathListObject = pathListFiled.get(pathClassLoader); Class systemPathClazz = pathListObject.getClass(); Field systemElementsField = systemPathClazz.getDeclaredField("dexElements"); systemElementsField.setAccessible(true); //系统的 dexElements[] Object systemElements = systemElementsField.get(pathListObject); // 第三步 上面的dexElements 数组 合并成新的 dexElements 然后通过反射重新注入系统的Field (dexElements )变量中 // 新的 Element[] 对象 // dalvik.system.Element int systemLength = Array.getLength(systemElements); int myLength = Array.getLength(myElements); // 找到 Element 的Class类型 数组 每一个成员的类型 Class<?> sigleElementClazz = systemElements.getClass().getComponentType(); int newSysteLength = myLength + systemLength; Object newElementsArray=Array.newInstance(sigleElementClazz, newSysteLength); //融合 for (int i = 0; i < newSysteLength; i++) { // 先融合 插件的Elements if (i < myLength) { Array.set(newElementsArray, i, Array.get(myElements, i)); }else { Object value = Array.get(systemElements, i - myLength); Array.set(newElementsArray,i, value); } } Field elementsField=pathListObject.getClass().getDeclaredField("dexElements");; elementsField.setAccessible(true); // 将新生成的EleMents数组对象重新放到系统中去 elementsField.set( pathListObject,newElementsArray); } catch (Exception e) { e.printStackTrace(); }
这样的方式就实现了class不需要class.forname()
指定插件classloader了。这种方式弊端就是我这个qq机器人是不能这么搞的,插件卸载了我还要手动移除。。。
多累啊。