快速接入美團熱修復Robust

相信很多人都認識了解過 熱修復省古、熱更新粥庄、熱補丁(對于這個技術(shù)也沒有特別標準的一種叫法,下面我統(tǒng)一叫熱更新)豺妓,之后的一年里惜互,各種熱更新方案如雨后春筍般出現(xiàn)布讹,比較耳熟能詳?shù)木陀蠳uwa、Tinker训堆、Andfix 和 Dexposed 等等描验,他們之間的區(qū)別以及優(yōu)缺點就不在這里討論了,鑒于它們的實際使用和局限性坑鱼,美團的開發(fā)團隊就腦洞大開了膘流。


image.png

去年 Google 高調(diào)發(fā)布了 Android Studio 2.0,其中最重要的新特性Instant Run姑躲,實現(xiàn)了對代碼修改的實時生效(熱插拔)睡扬。美團開發(fā)團隊在了解 Instant Run 原理之后,實現(xiàn)了一個兼容性更強的熱更新方案黍析,這就是產(chǎn)品化的hotpatch框架—–Robust,對于 Robust 的原理我們后面的文章再討論屎开,本篇只針對想快速上手的入門講解

Android熱更新方案Robust

Android熱更新方案Robust開源阐枣,新增自動化補丁工具

美團 Robust 的 github demo 地址

image.png

Robust 為每個類新增了一個類型為 ChangeQuickRedirect 的靜態(tài)變量,并且在每個方法前奄抽,增加判斷該變量是否為空的邏輯蔼两,如果不為空,走打基礎包時插樁的邏輯逞度,否則走正常邏輯额划。
使用步驟

1.集成了 Robust 后,生成 apk档泽。保存期間的混淆文件 mapping.txt俊戳,以及 Robust 生成記錄文件 methodMap.robust 
2.使用注解 @Modify 或者方法 RobustModify.modify() 標注需要修復的方法 
3.開啟補丁插件,執(zhí)行生成 apk 命令馆匿,獲得補丁包 patch.jar 
4.通過推送或者接口的形式抑胎,通知 app 有補丁,需要修復 
5.加載補丁文件不需要重新啟動應用

集成方法
1渐北、在項目最外層的 build.gradle 添加兩處插件

  classpath 'com.meituan.robust:gradle-plugin:0.3.3'
  classpath 'com.meituan.robust:auto-patch-plugin:0.3.3'

2阿逃、然后在項目的 build.gradle 添加

//apply plugin: 'auto-patch-plugin'(生成補丁的時候打開)
 apply plugin: 'robust'(生成apk的時候打開)
 compile 'com.meituan.robust:robust:0.3.3'

3、需要手動 copy 一份 robust.xml 的配置文件到app的目錄下赃蛛,該文件各個配置注釋的很清楚恃锉,若沒特殊要求,不需要修改

<?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>false</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在容易和其他字節(jié)碼工具相互干擾-->
        <useAsm>true</useAsm>
        <!--<useAsm>false</useAsm>-->
    </switch>

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

    <!--不需要Robust插入代碼的包名分尸,Robust庫不需要插入代碼锦聊,如下的配置項請保留,還可以根據(jù)各個APP的情況執(zhí)行添加-->
    <exceptPackname name="exceptPackage">

    </exceptPackname>

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

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

    </noNeedReflectClass>
</resources>

現(xiàn)在可以編譯項目 時間會比較長


build.png

先解釋一下仰税,在生成 apk 的時候使用 apply plugin:'robust'构资,該插件會生成打補丁時需要的方法記錄文件 methodMap.robust,該文件在打補丁的時候用來區(qū)別到底哪些方法需要被修復陨簇,所以有它才能打補丁吐绵。而上文所說的還有 mapping.txt 文件,該文件列出了原始的類河绽,方法和字段名與混淆后代碼間的映射己单。這個文件很重要,可以用它來翻譯被混淆的代碼耙饰。但也不是必須的纹笼,如果不需要混淆,可以不保留苟跪。這兩個文件在生成apk后廷痘,分別在 build/outputs/robust/methodsMap.robust蔓涧,build/outputs/mapping/mapping.txt(需要開啟混淆后才會出現(xiàn)),我們需要自己分別拷貝到 app/robust 下笋额,在 app 目錄新建個叫 robust 的文件夾元暴,把這兩個文件放進去就 ok 了。


WX20180307-113912@2x.png

完成了第二步了兄猩。我們得到了 apk 茉盏,mapping.txt,methodMap.robust 枢冤,有了它們我們再繼續(xù)生成補丁 patch.jar鸠姨。

加載補丁的方法

  new PatchExecutor(getActivity(), new PatchManipulateImp(), new RobustCallBack() {
                    @Override
                    public void onPatchListFetched(boolean b, boolean b1) {

                    }

                    @Override
                    public void onPatchFetched(boolean b, boolean b1, Patch patch) {

                    }

                    @Override
                    public void onPatchApplied(boolean b, Patch patch) {

                    }

                    @Override
                    public void logNotify(String s, String s1) {

                    }

                    @Override
                    public void exceptionNotify(Throwable throwable, String s) {

                    }
                }).start();

注意 PatchManipulateImp
關于PatchManipulateImp這個類控制了補丁的加載策略,代碼中也增加不少的注釋淹真,在這個類中實際負責補丁的下載讶迁、校驗和使用策略等,這個類需要實現(xiàn)如下幾個方法

要加載補丁肯定得知道 patch.jar 放在哪啊是吧趟咆,打開看一眼(不要害怕只有很少代碼)添瓷,為了方便展示,就把不太重要的三個方法縮起來了值纱,copy 方法是普通文件拷貝的IO流,verifyPatch 方法本來是驗證補丁有效性的坯汤,后來發(fā)現(xiàn)對普通使用者沒有那么高要求虐唠,就改成了備份補丁的回調(diào)了,ensurePatchExist 方法就檢測補丁存在與否惰聂,好了大概知道其它的方法就詳細介紹下主要方法 fetchPatchList疆偿,回顧一下上面的xxx再聯(lián)想到這里吧,既然我們要加載補丁搓幌,那么我們得知道補丁在哪啊杆故,這個方法就是把補丁找出來給上面那個誰用的。所以說溉愁,補丁的位置你可以根據(jù)拉取下來保存的位置來找出來处铛,把路徑給 setLocalPath 就好。再有就 setPatchesInfoImplClassFullName 的包名需要和 robust.xml 配置的一樣


4.png
5.png

新增加一個頁面來測試補丁

public class RobustActivity extends AppCompatActivity {
    private TextView text2;

    @Override
    @Modify
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_robust);
        text2 = findViewById(R.id.text2);
        // text2.setText(getString());
        text2.setText(getinfo());
    }

    private String getString() {
        return "hello word";
    }

    @Add
    public String getinfo() {
        StringBuilder msg = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            msg.append(i + "\n");
        }
        return msg.toString();
    }
}

制作補丁并使用

我們所需要做的跳轉(zhuǎn)后效果是修改一下textview顯示內(nèi)容而已拐揭,那么在被修改的頁面需要怎么標注被修改的方法呢撤蟆,就像這樣,先科普一下堂污,在 robust 的注意事項里面已經(jīng)提到過家肯,修改方法和字段會有一些局限性,那是因為 android 本身ProGuard的內(nèi)聯(lián)盟猖、優(yōu)化導致的讨衣。所以要繞過這個本身的問題换棚,要必須遵循一些規(guī)律了...以后再介紹這個。修改完這些反镇,我們再去 build.gradle 修改一下固蚤,開啟打補丁那個,關閉生成apk那個愿险。之后再在終端執(zhí)行一遍生成apk的命令行颇蜡。直到終端那里出現(xiàn) auto patch end successfully

美團已經(jīng)提供了自動化生成補丁的工具
在項目的 build.gradle apply plugin: 'auto-patch-plugin'打開
注釋掉生成apk的插件
再次點擊 assembleRelease
出現(xiàn) auto patch end successfully 表示補丁已經(jīng)生成 此時在robust文件里面可以看到patch.jar


3.png

點擊load_path


image.png

如果看到 apply result true 那么就大功告成了。
再點擊jump
便可以看到加載的是補丁里面的方法

最后來張效果圖


image.png
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辆亏,一起剝皮案震驚了整個濱河市风秤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扮叨,老刑警劉巖缤弦,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異彻磁,居然都是意外死亡碍沐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門衷蜓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來累提,“玉大人,你說我怎么就攤上這事磁浇≌悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵置吓,是天一觀的道長无虚。 經(jīng)常有香客問我,道長衍锚,這世上最難降的妖魔是什么友题? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮戴质,結(jié)果婚禮上度宦,老公的妹妹穿的比我還像新娘。我一直安慰自己置森,他們只是感情好斗埂,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凫海,像睡著了一般呛凶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上行贪,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天漾稀,我揣著相機與錄音模闲,去河邊找鬼。 笑死崭捍,一個胖子當著我的面吹牛尸折,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播殷蛇,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼实夹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粒梦?” 一聲冷哼從身側(cè)響起亮航,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匀们,沒想到半個月后缴淋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡泄朴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年重抖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祖灰。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡钟沛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出局扶,到底是詐尸還是另有隱情讹剔,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布详民,位于F島的核電站,受9級特大地震影響陌兑,放射性物質(zhì)發(fā)生泄漏沈跨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一兔综、第九天 我趴在偏房一處隱蔽的房頂上張望饿凛。 院中可真熱鬧,春花似錦软驰、人聲如沸涧窒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纠吴。三九已至,卻和暖如春慧瘤,著一層夾襖步出監(jiān)牢的瞬間戴已,已是汗流浹背固该。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留糖儡,地道東北人伐坏。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像握联,于是被迫代替她去往敵國和親桦沉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容