Android热更新简介 - Go语言中文社区

Android热更新简介


如果你交给某人一个程序,你将折磨他一整天;如果你教某人如何编写程序,你将折磨他一辈子。

什么是热更新?


  • 一般我们学习一门新技术,我们都会首先去了解,这门技术是做什么的,有什么用。在百度百科中,热更新的定义是这样的:

热更新是一种各大手游等众多App常用的更新方式。简单来说,就是在用户通过App Store下载App之后,打开App时遇到的即时更新

热更新的原理

  • 说到热更新的原理,不得不提一下android中类的加载流程(这里感谢hi大头鬼hi写的一篇Android热更新实现原理文章)

  • 我们知道Java在运行时加载对应的类是通过 ClassLoader 来实现的,ClassLoader本身是一个抽象来,Android中使用PathClassLoader类作为Android的默认的类加载器,PathClassLoader其实实现的就是简单的从文件系统中加载类文件。PathClassLoade本身继承自BaseDexClassLoader,BaseDexClassLoader重写了findClass方法。

  • 该方法是ClassLoader的核心:

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
    Class c = pathList.findClass(name, suppressedExceptions);
    if (c == null) {
        ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class "" + name + "" on path: " + pathList);
        for (Throwable t : suppressedExceptions) {
            cnfe.addSuppressed(t);
        }
        throw cnfe;
    }
    return c;
}
  • 看源码可知,BaseDexClassLoader将findClass方法委托给了pathList对象的findClass方法,pathList对象是在BaseDexClassLoader的构造函数中new出来的,
    它的类型是DexPathList。看下DexPathList.findClass源码是如何做的:
public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;

        if (dex != null) {
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    if (dexElementsSuppressedExceptions != null) {
        suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
    }
    return null;
}
  • 直接就是遍历dexElements列表,然后通过调用element.dexFile对象上的loadClassBinaryName方法来加载类,如果返回值不是null,就表示加载类成功,会将这个Class对象返回。
    而dexElements对象是在DexPathList类的构造函数中完成初始化的。
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
                                           suppressedExceptions);
  • makeDexElements所做的事情就是遍历我们传递来的dexPath,然后一次加载每个dex文件。

  • 上面分析了Android中的类的加载的流程,可以看出来DexPathList对象中的dexElements列表是类加载的一个核心,一个类如果能被成功加载,那么它的dex一定会出现在dexElements所对应的dex文件中,并且dexElements中出现的顺序也很重要,在dexElements前面出现的dex会被优先加载,一旦Class被加载成功, 就会立即返回,也就是说,我们的如果想做hotpatch,一定要保证我们的hotpacth dex文件出现在dexElements列表的前面。

  • 说的通俗一点,热更新就是通过动态替换dex的方式来实现修复代码的。

使用热更新的好处

  • 现在市面上的很多项目都加入了热更新。那么热更新能给我们的项目带来什么样的好处:
  • 我们先来看一个项目正常的发布流程
    这里写图片描述

  • 这种发布流程的存在的问题:

    • 重新发版,需要重新上架审核,耗时费力
    • 用户需要重新下载安装,用户体验差
    • Bug修复不及时,成本高
  • 有时候我们甚至修改了一两行代码也要重新发布一个新版本,这样不论是对用户,还是对开发人员来说,体验都是非常不好的。

  • 而如果我们使用热更新,流程则如下:
    这里写图片描述

  • 可见,热更新能够以更低的成本,更灵活的方式应对Bug修复。

选择适合你的热更新解决方案

  • 当前市面的热补丁方案有很多,其中比较出名的有阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案,还有微信用的Tinker。
  • 我们先来对比一下这几种热更新方案的区别:
    这里写图片描述
  • 一般对于项目选用何种热更新方案,可根据项目需求评估一下。这里我自己用的是tinker的方案。

热更新已知缺陷

  • 当然,热更新也是存在着缺陷的,不过目前来说热更新的利远远大于弊

  • 就拿tinker的方案来说,它存在的已知缺陷就有以下几点:

    • Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的Activity);
    • 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
    • 在Android N上,补丁对应用启动时间有轻微的影响;
    • 不支持部分三星android-21机型,加载补丁时会主动抛出”TinkerRuntimeException:checkDexInstall failed”;
    • 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。

对热更新的介绍暂时就到这里过,接下来我会写一篇关于Tinker方案的使用过程,以及注意事项!

  • 有问题感谢指出,觉得不错的话下面点个赞
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qwer971211/article/details/78842346
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 20:53:54
  • 阅读 ( 1467 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢