robust 熱修復實踐

weixin_33912445發表於2018-06-29
一、匯入專案

在專案根目錄的build.gradle下新增

dependencies {
    classpath 'com.android.tools.build:gradle:3.1.2'
    //robust外掛
    classpath "com.meituan.robust:gradle-plugin:${robustVersion}"
    classpath "com.meituan.robust:auto-patch-plugin:${robustVersion}"
    
}

gradle.properties新增版本號(或者寫死,可以忽略):

#meituan hotfix
robustVersion = 0.4.82

在app目錄下的build.gradle下新增

if(isMakeHot.toBoolean()){
    //製作補丁開啟
    apply plugin: 'auto-patch-plugin'
}else{
    //生成apk開啟
    apply plugin: 'robust'
}

dependencies {
     compile "com.meituan.robust:robust:${robustVersion}"
}

gradle.properties中新增開關,以後打包或者打補丁只要修改這個引數:

#Make a patch please set true
isMakeHot=false
二、配置檔案

在app目錄下新增robust.xml配置檔案,一般修改patchPackname和hotfixPackage就可以了:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <switch>
        <!--true代表開啟Robust,請注意即使這個值為true,Robust也預設只在Release模式下開啟-->
        <!--false代表關閉Robust,無論是Debug還是Release模式都不會執行robust-->
        <turnOnRobust>true</turnOnRobust>
        <!--<turnOnRobust>false</turnOnRobust>-->

        <!--是否開啟手動模式,手動模式會去尋找配置項patchPackname包名下的所有類,自動的處理混淆,然後把patchPackname包名下的所有類製作成補丁-->
        <!--這個開關只是把配置項patchPackname包名下的所有類製作成補丁,適用於特殊情況,一般不會遇到-->
        <!--<manual>true</manual>-->
        <manual>false</manual>

        <!--是否強制插入插入程式碼,Robust預設在debug模式下是關閉的,開啟這個選項為true會在debug下插入程式碼-->
        <!--但是當配置項turnOnRobust是false時,這個配置項不會生效-->
        <!--<forceInsert>true</forceInsert>-->
        <forceInsert>true</forceInsert>

        <!--是否捕獲補丁中所有異常,建議上線的時候這個開關的值為true,測試的時候為false-->
        <catchReflectException>true</catchReflectException>
        <!--<catchReflectException>false</catchReflectException>-->

        <!--是否在補丁加上log,建議上線的時候這個開關的值為false,測試的時候為true-->
        <!--<patchLog>true</patchLog>-->
        <patchLog>false</patchLog>

        <!--專案是否支援progaurd-->
        <proguard>true</proguard>
        <!--<proguard>false</proguard>-->

        <!--專案是否支援ASM進行插樁,預設使用ASM,推薦使用ASM,Javaassist在容易和其他位元組碼工具相互干擾-->
        <useAsm>true</useAsm>
        <!--<useAsm>false</useAsm>-->
    </switch>

    <!--需要熱補的包名或者類名,這些包名下的所有類都被會插入程式碼-->
    <!--這個配置項是各個APP需要自行配置,就是你們App裡面你們自己程式碼的包名,
    這些包名下的類會被Robust插入程式碼,沒有被Robust插入程式碼的類Robust是無法修復的-->
    <packname name="hotfixPackage">
        <name>包名</name>
    </packname>

    <!--不需要Robust插入程式碼的包名,Robust庫不需要插入程式碼,如下的配置項請保留,還可以根據各個APP的情況執行新增-->
    <exceptPackname name="exceptPackage">
        <name>com.meituan.robust</name>
        <name>com.meituan.sample.extension</name>
    </exceptPackname>

    <!--補丁的包名,請保持和類PatchManipulateImp中fetchPatchList方法中設定的補丁類名保持一致( setPatchesInfoImplClassFullName("com.meituan.robust.patch.PatchesInfoImpl")),
    各個App可以獨立定製,需要確保的是setPatchesInfoImplClassFullName設定的包名是如下的配置項,類名必須是:PatchesInfoImpl-->
    <patchPackname name="patchPackname">
        <name>cn.superh.patch</name>
    </patchPackname>

    <!--自動化補丁中,不需要反射處理的類,這個配置項慎重選擇-->
    <noNeedReflectClass name="classes no need to reflect">

    </noNeedReflectClass>
</resources>

三、思路(需要結合專案的實際情況而定)

先說說我們專案中用的原理

首先,介面方面(和美團建議不一致,也沒辦法,不是我們寫 ~ ),後臺小夥伴把熱修復介面資訊,在每個介面中都會返回,啊~~ 這是要幹嘛~,所以我是按這樣介面返回來寫的。

我們把本地的app版本號和補丁版本號在通過Heads傳遞給後臺,來識別是否需要補丁資訊。

1.在網路攔截器中,對response進行處理攔截,獲取到熱修復資訊後,去下載。當然在下載的時候,肯定還有多個介面會返回資訊,需要做下處理。

2.需要對修復完的版本,本地儲存一份,並快取版本號資訊,下次啟動需要載入。

3.補丁版本只能針對某一個大版本(app的版本),不能升級應用後,以前的補丁還應用了。

4.安全性的一些考慮。(目前我們只做了檔案MD5驗證,沒有做加密的操作)

四、具體Demo

https://github.com/super-hu/hotfix_android

五、釋出流程
正常釋出apk
  1. 修改gradle.properties
isMakeHot=false
  1. 去除掉 之前的修復的bug檔案含有 @Modify @Add 的註解(如果有)

  2. 儲存好outputs/mapping/環境/mapping.txt、outputs/robust/robust.apkhash 檔案


釋出補丁

1.修改有bug的方法增加@Modify或新增方法或者類@Add

2.把之前保留的mapping.txt和robust.apkhash,複製到app專案下的robust目錄

3.修改gradle.properties

isMakeHot=true

4.修改app目錄下的robust配置開關(一般不用動,詳細看註釋)。

5.執行打包命令,最後會在outputs/robust 下生成patch.jar補丁檔案,釋出到伺服器。


注意事項

1.打補丁檔案,如果之前未對程式碼做混淆,需要自行建立mapping.txt(正式環境都是混淆的,可忽略)

如果你們的app沒有使用proguard優化程式碼,那麼一切處理起來都比較簡單了,Robust插樁部分與Proguard沒有依賴關係,所以Robust插樁部分可以放心使用,至於自動化嘛就需要做一些手腳了:

首先需要建立一個mapping.txt檔案,請注意檔案的命名哈,然後放到app/robust目錄下
其他操作和使用說明中的操作一樣,只不過需要你在mapping檔案中加入幾行,比如說我們需要對com.meituan.mainactivity這個類修改bug 需要在mapping檔案新增如下程式碼:
com.meituan.mainactivity ->com.meituan.mainactivity:
                int field ->field
其中com.meituan.mainactivity就是你要修改的類,field是你類中的任一欄位,類中的方法名不需要填寫(包括修改的方法),mapping檔案只能包含這兩行,不能有多餘的空行,多餘空格也不行

2.支援的修復

支援方法級別的修復,支援靜態方法
支援新增方法和類

3.不支援的修復

介面、無方法類、構造方法、抽象方法、native方法、synthetic方法等不插住程式碼

so不支援:

新增欄位
修復構造方法
資源和 so 修復
返回值是 this 的方法支援不太好(需要看情況處理)
可能會出現深度方法內聯導致的不可預知的錯誤(機率很小可以忽略)

4.TODO

沒有安全校驗,需要在載入補丁之前自己做驗證

  • 初步是檢驗檔案MD5值
  • 檔案加密解密處理

相關文章