插件化的新方式把插件apk的elementsField添加到系统的BaseDexClassLoader中去

模板代码

 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机器人是不能这么搞的,插件卸载了我还要手动移除。。。

多累啊。

你可能感兴趣的:(插件化的新方式把插件apk的elementsField添加到系统的BaseDexClassLoader中去)