Android熱修復(Hot Fix)案例全剖析(一)

    說到熱修復技術,我們不得不先談一下什麼是冷修復。

冷修復

    當我們發現上線的應用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分別構建(一)

爲了便於大家形象具體的理解熱修復技術的流程,我給大家畫一幅原理圖。

這裏寫圖片描述

待修復項目搭建

    明白了熱修復的流程以後,爲了方便給大家演示熱修復的流程,我們首先新建一個含有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="@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}"
            failonerror="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安裝到手機上,然後測試,點擊執行操作按鈕,發現項目崩潰並閃退。

這裏寫圖片描述

開發熱修復補丁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文件。

這裏寫圖片描述

    然後在cmd命令行中,利用SDK的dx工具編譯生成新的dex文件

這裏寫圖片描述

    成功後,我們將生成的dex文件反編譯,可以看到新的修復補丁文件已經將0改爲1

這裏寫圖片描述

    到這裏本篇博客就結束了,下一篇博客我們要做的事情就是用我們 classes2.dex(修復好的包)去動態替換classes2.dex(有Bug的包),實現熱修復操作。

Android熱修復(Hot Fix)案例全剖析(二)

發佈了79 篇原創文章 · 獲贊 89 · 訪問量 91萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章