android开发分享热修复插件化原理分析

插件化原理分析插件化要解决的三个核心问题:类加载、资源加载、组件生命周期管理。类加载:Android中常用的两种类加载器:PathClassLoader和DexClassLoader,它们都继承于BaseDexClassLoader。DexClassLoader的构造函数比PathClassLoader多了一个,optimizedDirectory参数,这个是用来指定dex的优化产物odex的路径,在源码注释中,指出这个参数从API 26后就弃用了。PathClassLoader主要用来加载系统类和

 

热修复插件化原理分析

 

 

热修复插件化原理分析

 

热修复插件化原理分析

 

热修复插件化原理分析

 

 

 

 

 

 

 

 

热修复

ClassLoader 
DexClassLoader PathClassLoader

loadClass  findLoadedClass  findClass

DexClassLoader BaseDexClassLoader

DexPathList pathList

Element dexElements    dex

javac   .java  .class  d8 patch.dex

dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.github.xch168.hotfixdemo-2/base.apk”],
nativeLibraryDirectories=[/data/app/com.github.xch168.hotfixdemo-2/lib/arm64, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]]]

class dalvik.system.BaseDexClassLoader

DexPathList[[zip file “/data/app/com.github.xch168.hotfixdemo-2/base.apk”],
nativeLibraryDirectories=[/data/app/com.github.xch168.hotfixdemo-2/lib/arm64, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]]

zip file “/data/app/com.github.xch168.hotfixdemo-2/base.apk”

pathList dexElements

DexClassLoader

.loadClass        .newInstance

.invoke

loadClass

lo

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = pathList.findClass(name);

        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }

        return clazz;
    }

DexPathList pathList

parent.loadClass

  findBootstrapClassOrNull 
  
  
  findClass
  
DexPathList.findClass
    public Class findClass(String name) {
        for (Element element : dexElements) {
            DexFile dex = element.dexFile;

            if (dex != null) {
                Class clazz = dex.loadClassBinaryName(name, definingContext);
                if (clazz != null) {
                    return clazz;
                }
            }
        }

        return null;
    }
    
    dexElements
    
    PathClassLoader    dexElements
    
    dex =dexElements[0]        setField

 

1
接来下开始load我们刚刚写入在dex文件中的ClassStudent类:

Class<?> aClass = dexClassLoader.loadClass(“ClassStudent”);
1
然后我们对其进行初始化,并调用相关的get/set方法对其进行验证,在这里我传给ClassStudent对象一个字符串,然后调用它的get方法获取在方法内合并后的字符串:

    Object instance = aClass.newInstance();
    Method method = aClass.getMethod(“setName”, String.class);
    method.invoke(instance, “Sahadev”);

    Method getNameMethod = aClass.getMethod(“getName”);
    Object invoke = getNameMethod.invoke(instance););
1
2
3
4
5
6
最后我们实现的代码可能是这样的:

    /**
     * 加载指定路径的dex
     *
     * @param apkPath
     */
    private void loadClass(String apkPath) {
        ClassLoader classLoader = getClassLoader();

        File file = new File(apkPath);

        try {

            DexClassLoader dexClassLoader = new DexClassLoader(apkPath, file.getParent() + “/optimizedDirectory/”, “”, classLoader);
            Class<?> aClass = dexClassLoader.loadClass(“ClassStudent”);
            mLog.i(TAG, “ClassStudent = ” + aClass);

            Object instance = aClass.newInstance();
            Method method = aClass.getMethod(“setName”, String.class);
            method.invoke(instance, “Sahadev”);

              伪代码相当于    void setName(string) {}

            Method getNameMethod = aClass.getMethod(“getName”);
            Object invoke = getNameMethod.invoke(instance);

         伪代码相当于    void getName() {}

 

            mLog.i(TAG, “invoke result = ” + invoke);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

 

 

 

 

 

插件化原理分析
插件化要解决的三个核心问题:类加载、资源加载、组件生命周期管理。
类加载:Android中常用的两种类加载器:PathClassLoader和DexClassLoader,它们都继承于BaseDexClassLoader。
DexClassLoader的构造函数比PathClassLoader多了一个,optimizedDirectory参数,这个是用来指定dex的优化产物odex的路径,在源码注释中,指出这个参数从API 26后就弃用了。
PathClassLoader主要用来加载系统类和应用程序的类,在ART虚拟机上可以加载未安装的apk的dex,在Dalvik则不行。
DexClassLoader用来加载未安装apk的dex。
资源加载:Android系统通过Resource对象加载资源,因此只需要添加资源(即apk文件)所在路径到AssetManager中,即可实现对插件资源的访问。由于AssetManager的构造方法时hide的,需要通过反射区创建。
组件生命周期管理:对于Android来说,并不是说类加载进来就可以使用了,很多组件都是有“生命”的;因此对于这些有血有肉的类,必须给他们注入活力,也就是所谓的组件生命周期管理。
在解决插件中组件的生命周期,通常的做法是通过Hook相应的系统对象,实现欺上瞒下,后面将通过Activity的插件化来进行讲解。

    // 第一步:反射得到 ListenerInfo 对象
        Method getListenerInfo = View.class.getDeclaredMethod(“getListenerInfo”);
        //android.view.View$ListenerInfo android.view.View.getListenerInfo()
        getListenerInfo.setAccessible(true);
        Object listenerInfo = getListenerInfo.invoke(view);//View$ListenerInfo
        // 第二步:得到原始的 OnClickListener事件方法
        Class<?> listenerInfoClz = Class.forName(“android.view.View$ListenerInfo”);//class android.view.View$ListenerInfo
        Field mOnClickListener = listenerInfoClz.getDeclaredField(“mOnClickListener”);//public android.view.View$OnClickListener android.view.View$ListenerInfo.mOnClickListener
        mOnClickListener.setAccessible(true);
        View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(listenerInfo);//MainActivity@4846
        // 第三步:用 Hook代理类 替换原始的 OnClickListener

        View.OnClickListener hookedOnClickListener = new HookedClickListenerProxy(originOnClickListener);
        mOnClickListener.set(listenerInfo, hookedOnClickListener);
        
        
        
           @UnsupportedAppUsage
    static public INotificationManager getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService(“notification”);
        sService = INotificationManager.Stub.asInterface(b);
        return sService;
    }
    
    
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
                                          

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/896471.html

(0)
上一篇 2021年10月22日
下一篇 2021年10月22日

精彩推荐