1. 程式人生 > >Android熱修復與外掛化(四)AndFix

Android熱修復與外掛化(四)AndFix

一、熱修復技術種類

這裡寫圖片描述

技術對比

這裡寫圖片描述

二、AndFix的基本介紹

官網

整合階段:

1、在gradle中新增依賴
2、在程式碼中完成初始化

builde.gradle

這裡寫圖片描述

MyApplication

這裡寫圖片描述

AndFixPatchManager

這裡寫圖片描述

準備階段:

1、首先我們先builde一個有bug的old.apk安裝到手機
2、分析bug並解決bug,builde一個new的apk

(需要簽名打包的apk不要debug,自行解決)
有bug的程式碼:

public class MainActivity extends AppCompatActivity {

    private static final String FILE_END = ".apatch";
    private String patchDir;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //建立檔案路徑
patchDir = getExternalCacheDir().getAbsolutePath() + "/apatch/"; //建立資料夾 File file = new File(patchDir); //判斷資料夾是否存在 if (file == null || !file.exists()) { //不存在就建立 file.mkdir(); } } public void createBug(View view) { //列印log資訊為null,應用閃退
Utils.printLog(); } public void fixBug(View view) { AndFixPatchManager.getInstance().addPatch(getPathName()); } //構建Patch檔名 private String getPathName() { return patchDir.concat("smile").concat(FILE_END); } }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.smile.mydemotwo.activity.MainActivity">

    <Button
        android:layout_width="88dp"
        android:layout_height="50dp"
        android:text="產生bug"
        android:onClick="createBug"
        tools:layout_editor_absoluteY="0dp"
        tools:layout_editor_absoluteX="8dp"
        android:layout_margin="10dp"/>

    <Button
        android:layout_width="88dp"
        android:layout_height="50dp"
        android:text="修復bug"
        android:onClick="fixBug"
        tools:layout_editor_absoluteY="0dp"
        tools:layout_editor_absoluteX="8dp"
        android:layout_margin="10dp"/>

</LinearLayout>

Patch生成階段:

1、apkpatch命令及引數詳解

1、先下載apkpatch工具工具
解壓
這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

-f:new.apk的檔案路徑
-t:是有bug的apk檔案的路徑
-o:是輸出補丁包檔案的目錄
-k:是簽名檔案的路徑
-p:是簽名檔案的密碼
-a :是簽名檔案的別名
-e:是簽名檔案別名的密碼

2、使用apkpatch命令生成apkpatch包

這裡寫圖片描述
這裡寫圖片描述

Patch安裝階段:

將補丁檔案通過adb push放入到指定目錄(開發中都是下載到指定目錄)
點選修復bug按鈕,載入補丁檔案
再次啟動應用,點選建立bug按鈕,此時應用不會閃退,並彈出Toast

這裡寫圖片描述

到這基本就完成了更新

總結階段:

1、實際中不可能用adb push匯入補丁,應該是下載
2、能否將AndFix模組元件化,為以後複用

將AndFix元件化

AndFixPatchManager :

public class AndFixPatchManager {

    private static AndFixPatchManager mInstance = null;

    private static PatchManager mPatchManager = null;

    private AndFixPatchManager() {
    }

    public static AndFixPatchManager getInstance() {
        if (mInstance == null) {

            synchronized (AndFixPatchManager.class) {

                if (mInstance == null) {

                    mInstance = new AndFixPatchManager();

                }
            }
        }
        return mInstance;
    }

    //初始化AndFix方法
    public void initPatch(Context context) {
        mPatchManager = new PatchManager(context);
        mPatchManager.init(Utils.getVersionName(context));
        mPatchManager.loadPatch();
    }

    //載入我們的patch檔案,引數patch檔案的路徑
    public void addPatch(String path) {
        try {
            if (mPatchManager != null) {
                mPatchManager.addPatch(path);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

AndFixService

public class AndFixService extends Service {

    private static final int UPDATE_PATCH = 0x02;
    private static final int DOWNLOAD_PATCH = 0x01;
    private static final String FILE_END = ".apatch";
    //存放Patch檔案的目錄
    private String mPatchFileDir;
    //存放Patch檔案
    private String mPatchFile;
    //訊息轉發
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_PATCH:
                    checkPatchUpdate();
                    break;
                case DOWNLOAD_PATCH:
                    downloadPatch();
                    break;
            }
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化
        init();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mHandler.sendEmptyMessage(UPDATE_PATCH);
        //這個返回值如果被系統回收之後不會被系統重啟
        return START_NOT_STICKY;
    }

    //完成檔案目錄的構造
    private void init() {
        mPatchFileDir = getExternalCacheDir().getAbsolutePath() + "/apatch/";
        File file = new File(mPatchFileDir);
        try {
            if (file == null || !file.exists()) {
                file.mkdir();
            }
        } catch (Exception e) {
            e.printStackTrace();
            stopSelf();
        }
    }

    //檢查是否有新的patch檔案
    private void checkPatchUpdate() {
        //網路請求,失敗停止服務
    }

    private void downloadPatch() {
        //網路請求,失敗停止服務
        mPatchFile = mPatchFileDir.concat(System.currentTimeMillis() + "").concat(FILE_END);
    }
}