Android 热修复 (Hot Fix) 案例全剖析(一)

   2016-10-04 0
核心提示:说到热修复技术,我们不得不先谈一下什么是冷修复。冷修复当我们发现上线的应用APK存在Bug,我们通过发布新的应用APK,去替换旧的应用APK,以达到解决Bug的目的,但是这样做存在很大的缺点,需要用户二次下载APK,浪费用户流量,费时、费力、用户体验差。热修

说到热修复技术,我们不得不先谈一下什么是冷修复。

冷修复

当我们发现上线的应用APK存在Bug,我们通过发布新的应用APK,去替换旧的应用APK,以达到解决Bug的目的,但是这样做存在很大的缺点,需要用户二次下载APK,浪费用户流量,费时、费力、用户体验差。

热修复

当我们发现上线的应用APK存在Bug,我们在用户使用过程中就把Bug修复了,优点是其过程中用户不需要把应用程序停止、卸载、重新安装、重启,大大改善了用户体验。

热修复原理解析

通常作为一款应用,最容易出现Bug的地方,是java代码。我们知道Oracle的套路,java源文件是被编译成.class文件,用ClassLoader加载.class;而安卓使用Dalvik/ART虚拟机,由于版权问题,谷歌把.class编译成了dex文件,并通过ClassLoader加载dex。我们的热修复方案,其实就是基于我之前博客中讲到的Android dex多分包方案实现的。想学习了解Android Dex多分包技术的童鞋,请点击链接查看: 彻底掌握Android多分包技术MultiDex-用Ant和Gradle分别构建(一)

为了便于大家形象具体的理解热修复技术的流程,我给大家画一幅原理图。

 Android 热修复 (Hot Fix) 案例全剖析(一)

待修复项目搭建

明白了热修复的流程以后,为了方便给大家演示热修复的流程,我们首先新建一个含有Bug的项目,该项目有一个页面,页面中包含两个按钮,一个按钮点击后会执行错误未修复的代码,另一个按钮点击后执行热修复操作。

MainActivity代码如下:

public class MainActivity extends Activity {
    Button btnOpen, btnModify;
    NullTest nt = new NullTest();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnOpen = (Button) findViewById(R.id.btn_open);
        btnModify = (Button) findViewById(R.id.btn_modify);
        btnOpen.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                nt.printAbcLength(MainActivity.this);// 执行计算
            }
        });

        btnModify.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                castielFixMethod();// 调用热修复方法
            }
        });
    }
}

出错的NullTest计算工具类:

public class NullTest {
    int a = 8;
    int b = 0;// 故意设置为0

    public void printAbcLength(Context context) {
        // 很明用8除0,一定会导致java.lang.ArithmeticException: / by zero异常
        Toast.makeText(context, "count result:" + (a/b), Toast.LENGTH_LONG).show();
    }
}

布局文件代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="猴子搬来的救兵 http://blog.csdn.net/mynameishuangshuai" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_margin="10dp"
        android:src=http://www.tuicool.com/articles/"@drawable/old" />

    <Button
        android:id="@+id/btn_open"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:layout_below="@+id/imageView1"
        android:layout_margin="10dp"
        android:text="执行操作" />

    <Button
        android:id="@+id/btn_modify"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:layout_below="@+id/btn_open"
        android:layout_margin="10dp"
        android:text="修复Bug" />

</RelativeLayout>

OK,项目源码开发到此为止,接下来,我们通过使用ant命令,对该项目进行多分包构建,这次我们一共构建了两个dex包,特地把出错的NullTest类放到classes2.dex中去,为的就是方便后面的热修复。

<!-- 构建多分包dex文件 -->

    <target
        name="multi-dex"
        depends="compile" >

        <echo message="Generate multi-dex..." />

        <exec
            executable="${tools.dx}"
            failon
error="true" >
            <arg value="--dex" />
            <arg value="--multi-dex" />
            <arg value="--set-max-idx-number=10000" />
            <arg value="--main-dex-list" />
            <!-- 主包包含class文件列表 -->
            <arg value="${main-dex-rule}" />
            <arg value="--minimal-main-dex" />
            <arg value="--output=${bin}" />
            <arg value="${bin}" />
            <!-- <arg value="${libs}" /> -->
        </exec>
    </target>

主包配置文件清单:

com/castiel/demo/MainActivity.class

完成以上所有操作后,我们将构建出来的APK安装到手机上,然后测试,点击执行操作按钮,发现项目崩溃并闪退。

 Android 热修复 (Hot Fix) 案例全剖析(一)

开发热修复补丁dex文件

1.发现并修改Bug

public class NullTest {
    int a = 8;
    int b = 1;// 这里我们将出错的0改为1

    public void printAbcLength(Context context) {
        Toast.makeText(context, "count result:" + (a/b), Toast.LENGTH_LONG).show();
    }
}

2.生成补丁dex文件修改错误代码后,我们clean一下项目,在项目的bin目录中找到生成的新的NullTest.class文件,连同该文件的包目录一并拷贝出来(注意其他的类文件通通去掉),这里我拷贝到桌面上的castiel文件夹中,同时在该文件夹中新建一个castieloutput文件夹,用于稍后存放编译的dex文件。

 Android 热修复 (Hot Fix) 案例全剖析(一)

然后在cmd命令行中,利用SDK的dx工具编译生成新的dex文件

 Android 热修复 (Hot Fix) 案例全剖析(一)

成功后,我们将生成的dex文件反编译,可以看到新的修复补丁文件已经将0改为1

 Android 热修复 (Hot Fix) 案例全剖析(一)

到这里本篇博客就结束了,下一篇博客我们要做的事情就是用我们 classes2.dex(修复好的包)去动态替换classes2.dex(有Bug的包),实现热修复操作。

 
标签: 安卓热修复
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 移动周刊第 176 期:Android 知识梳理
    移动周刊第 176 期:Android 知识梳理
    写在前面 本期移动周刊第 176 期如约而至,聚焦 Android、iOS、VR/AR/MR、直播等前沿移动开发技术,收录一周最热点,解读开发技巧,每周三移动周刊抢先看,我们希望从中能够让你有一些收获,如果你有好的文章以及优化建议,请发送邮件至mobilehub@csdn.net,
  • AssetBundle里的Shader问题
    关于Resources和AssetBundle优劣之前已经提过很多次了(参考官方教程The Resources folder),正好最近@张迪在做框架AssetBundle部分的优化,特此整理一下两个特常见的坑及对应解决办法。之前在关于Unity中的资源管理,你可能遇到这些问题里有有人提到过这个问
  • Android WebView组件
    Android WebView组件
    原生应用的用户体验不错,但是开发成本相对较高。原生应用的灵活性相对页不如 Web 页,切 Web 页相对原生有更强的控制力。原生应用出了 Bug,如果没有热补丁等热修复技术,应用就需要重新发版上线。Web 页面的控制权都在服务器端,故出了问题,在服务器端修复
  • 热修复框架HotFix源码解析
    热修复框架HotFix源码解析
    讲起 Android 的热修复,相信大家对其都略知一二。热修复可以说是继插件化之后,又一项新的技术。目前的 Android 热修复框架主要分为了两类:基于 Native Hook:使用 JNI 动态改变方法指针,比如有 Dexposed 、 AndFix 等; 基于 Java Dex 分包:改变 dex 加
  • Android插件化笔记-2-ClassLoader
    https://zhuanlan.zhihu.com/p/20524252有几个ClassLoader如MainActivity的代码所示,protectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ClassLoader classLoader = getClass
点击排行