Robust初探

InstantRun

不得不說(shuō) InstantRun 真是個(gè)好東西顿苇。目前主流的熱修復(fù)框架都有或多或少的參考 InstantRun 的某些技術(shù)點(diǎn) 掷匠。

我們知道,InstantRun 對(duì)應(yīng)三種更新機(jī)制:

  • 冷插拔岖圈,我們稱之為重啟更新機(jī)制
  • 溫插拔,我們稱之為重啟Activity更新機(jī)制
  • 熱插拔钙皮,我們稱之為熱更新機(jī)制

Robust 蜂科,其熱修復(fù)的關(guān)鍵技術(shù)點(diǎn)就是采用了 InstantRun 中的熱更新機(jī)制,對(duì)應(yīng)于多 ClassLoader 的動(dòng)態(tài)加載方案短条,即一個(gè) dex 文件對(duì)應(yīng)一個(gè)新建 ClassLoader 导匣。

優(yōu)勢(shì)

  1. 支持Android2.3-7.X版本
  2. 高兼容性、高穩(wěn)定性茸时,修復(fù)成功率高達(dá)三個(gè)九
  3. 補(bǔ)丁下發(fā)立即生效贡定,不需要重新啟動(dòng)
  4. 支持方法級(jí)別的修復(fù),包括靜態(tài)方法
  5. 支持增加方法和類
  6. 支持ProGuard的混淆可都、內(nèi)聯(lián)缓待、優(yōu)化等操作

大概流程

image

集成方法

  1. 在App的build.gradle,加入如下依賴
apply plugin: 'com.android.application'
//制作補(bǔ)丁時(shí)將這個(gè)打開(kāi)渠牲,auto-patch-plugin緊跟著com.android.application
//apply plugin: 'auto-patch-plugin'
apply plugin: 'robust'
compile 'com.meituan.robust:robust:0.4.2'
  1. 在整個(gè)項(xiàng)目的build.gradle加入classpath
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
         classpath 'com.meituan.robust:gradle-plugin:0.4.2'
         classpath 'com.meituan.robust:auto-patch-plugin:0.4.2'
   }
}
  1. 項(xiàng)目發(fā)release版本,把簽名文件在gradle中寫好
   signingConfigs {
        debug {
            storeFile file("../robust.jks")
            storePassword "123456"
            keyAlias "robust"
            keyPassword "123456"
        }

        release {
            storeFile file("../robust.jks")
            storePassword "123456"
            keyAlias "robust"
            keyPassword "123456"
        }
    }

4.開(kāi)啟proguard混淆開(kāi)關(guān)旋炒,robust做了混淆文件和代碼的映射。

5.將robust項(xiàng)目源碼中的app/src/robust.xml拷貝到自己項(xiàng)目下的app/src路徑下


image

打開(kāi)robust.xml修改兩個(gè)地方


image

6.執(zhí)行命令

./gradlew clean  assembleRelease --stacktrace --no-daemon

7.app/build/outputs文件夾下會(huì)生成mapping.txt,methodsMap.robust文件签杈,將他們拷貝到app/robust文件夾中保存.


image

image

methodMap.robust瘫镇,該文件在打補(bǔ)丁的時(shí)候用來(lái)區(qū)別到底哪些方法需要被修復(fù),所以有它才能打補(bǔ)丁答姥。而上文所說(shuō)的還有 mapping.txt 文件铣除,該文件列出了原始的類,方法和字段名與混淆后代碼間的映射鹦付。

寫代碼

基本的配置就已經(jīng)配置好了尚粘,寫點(diǎn)簡(jiǎn)單的代碼,先看效果圖


image

功能很簡(jiǎn)單敲长,第二個(gè)按鈕跳轉(zhuǎn)到第二個(gè)Activity背苦。第一個(gè)按鈕加載一會(huì)兒生成的patch文件。跳轉(zhuǎn)代碼如下

  findViewById(R.id.loaddPatch).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //關(guān)鍵是第二個(gè)參數(shù)
                new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new Callback()).start();
            }
        });

        findViewById(R.id.jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,RobustActivity.class));
            }
        });

看下類PatchManipulateImp的代碼潘明,代碼是從官方拷貝過(guò)來(lái)的行剂,很簡(jiǎn)單。大致看一下

public class PatchManipulateImp extends PatchManipulate {
    /***
     * connect to the network ,get the latest patches
     * l聯(lián)網(wǎng)獲取最新的補(bǔ)丁
     * @param context
     *
     * @return
     */
    @Override
    protected List<Patch> fetchPatchList(Context context) {
        //將app自己的robustApkHash上報(bào)給服務(wù)端钳降,服務(wù)端根據(jù)robustApkHash來(lái)區(qū)分每一次apk build來(lái)給app下發(fā)補(bǔ)丁
        //apkhash is the unique identifier for  apk,so you cannnot patch wrong apk.
        //String robustApkHash = RobustApkHashUtils.readRobustApkHash(context);
        //connect to network to get patch list on servers
        //在這里去聯(lián)網(wǎng)獲取補(bǔ)丁列表
        Patch patch = new Patch();
        patch.setName("123");
        //we recommend LocalPath store the origin patch.jar which may be encrypted,while TempPath is the true runnable jar
        //LocalPath是存儲(chǔ)原始的補(bǔ)丁文件厚宰,這個(gè)文件應(yīng)該是加密過(guò)的,TempPath是加密之后的,TempPath下的補(bǔ)丁加載完畢就刪除铲觉,保證安全性
        //這里面需要設(shè)置一些補(bǔ)丁的信息澈蝙,主要是聯(lián)網(wǎng)的獲取的補(bǔ)丁信息。重要的如MD5撵幽,進(jìn)行原始補(bǔ)丁文件的簡(jiǎn)單校驗(yàn)灯荧,以及補(bǔ)丁存儲(chǔ)的位置,這邊推薦把補(bǔ)丁的儲(chǔ)存位置放置到應(yīng)用的私有目錄下盐杂,保證安全性
        patch.setLocalPath(Environment.getExternalStorageDirectory().getPath()+ File.separator+"robust"+File.separator + "patch");

        //setPatchesInfoImplClassFullName 設(shè)置項(xiàng)各個(gè)App可以獨(dú)立定制逗载,需要確保的是setPatchesInfoImplClassFullName設(shè)置的包名是和xml配置項(xiàng)patchPackname保持一致,而且類名必須是:PatchesInfoImpl
        //請(qǐng)注意這里的設(shè)置
        patch.setPatchesInfoImplClassFullName("cx.com.robustdemo.PatchesInfoImpl");
        List  patches = new ArrayList<Patch>();
        patches.add(patch);
        return patches;
    }

    /**
     *
     * @param context
     * @param patch
     * @return
     *
     * you can verify your patches here
     */
    @Override

    protected boolean verifyPatch(Context context, Patch patch) {
        //do your verification, put the real patch to patch
        //放到app的私有目錄链烈,拷貝到自己的目錄下厉斟。執(zhí)行。
        patch.setTempPath(context.getCacheDir()+ File.separator+"robust"+File.separator + "patch");
        //in the sample we just copy the file
        try {
            copy(patch.getLocalPath(), patch.getTempPath());
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("copy source patch to local patch error, no patch execute in path "+patch.getTempPath());
        }

        return true;
    }
    public void copy(String srcPath,String dstPath) throws IOException {
        File src=new File(srcPath);
        if(!src.exists()){
            throw new RuntimeException("source patch does not exist ");
        }
        File dst=new File(dstPath);
        if(!dst.getParentFile().exists()){
            dst.getParentFile().mkdirs();
        }
        InputStream in = new FileInputStream(src);
        try {
            OutputStream out = new FileOutputStream(dst);
            try {
                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }
    /**
     *
     * @param patch
     * @return
     *
     * you may download your patches here, you can check whether patch is in the phone
     */
    @Override
    protected boolean ensurePatchExist(Patch patch) {
        return true;
    }
}

這里一定要注意

//后綴必須是PatchesInfoImpl  强衡,前面的要和robust.xml中<package>節(jié)點(diǎn)下的包名對(duì)應(yīng)
  patch.setPatchesInfoImplClassFullName("cx.com.robustdemo.PatchesInfoImpl");

繼承了PatchManipulate擦秽,有3個(gè)方法。

@Override
fetchPatchList() 方法主要是設(shè)置patch的路徑等配置信息漩勤,然后返回
@Override
verifyPatch() //放到app的私有目錄感挥,是加載的真正的路徑
@Override
protected boolean ensurePatchExist(Patch patch): 

生成patch包

小小修改下第二個(gè)Activity的代碼!

image
image

執(zhí)行剛才的打包命令

./gradlew clean  assembleRelease --stacktrace --no-daemon

命令跑到中間會(huì)錯(cuò),如下圖,但是看到patch包已經(jīng)生成了。


image

生成路徑如下圖


image

執(zhí)行命令

adb push app/build/outputs/robust/patch.jar /sdcard/robust

最后一步越败,點(diǎn)擊第一個(gè)按鈕链快,再點(diǎn)擊跳轉(zhuǎn)到第二個(gè)按鈕。先看效果眉尸,會(huì)發(fā)下hello robust 變?yōu)闊岣恕?/p>

image

點(diǎn)擊加載patch文件按鈕


image

剛剛增加的代碼打出的log,熱更新成功了域蜗。


image

項(xiàng)目代碼

不足

  1. 每次都要手動(dòng)拷貝map文件,每次的都要替換插件來(lái)生成patch包噪猾。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霉祸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子袱蜡,更是在濱河造成了極大的恐慌丝蹭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坪蚁,死亡現(xiàn)場(chǎng)離奇詭異奔穿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)敏晤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門贱田,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嘴脾,你說(shuō)我怎么就攤上這事男摧∈叨眨” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵耗拓,是天一觀的道長(zhǎng)拇颅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乔询,這世上最難降的妖魔是什么樟插? 我笑而不...
    開(kāi)封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮竿刁,結(jié)果婚禮上黄锤,老公的妹妹穿的比我還像新娘。我一直安慰自己们妥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布勉吻。 她就那樣靜靜地躺著监婶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪齿桃。 梳的紋絲不亂的頭發(fā)上惑惶,一...
    開(kāi)封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音短纵,去河邊找鬼带污。 笑死,一個(gè)胖子當(dāng)著我的面吹牛香到,可吹牛的內(nèi)容都是我干的鱼冀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼悠就,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼千绪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起梗脾,我...
    開(kāi)封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荸型,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后炸茧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瑞妇,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年梭冠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辕狰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡控漠,死狀恐怖柳琢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤柬脸,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布他去,位于F島的核電站,受9級(jí)特大地震影響倒堕,放射性物質(zhì)發(fā)生泄漏灾测。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一垦巴、第九天 我趴在偏房一處隱蔽的房頂上張望媳搪。 院中可真熱鬧,春花似錦骤宣、人聲如沸秦爆。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)等限。三九已至,卻和暖如春芬膝,著一層夾襖步出監(jiān)牢的瞬間望门,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工锰霜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筹误,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓癣缅,卻偏偏與公主長(zhǎng)得像厨剪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子友存,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

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

  • 轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/snailbaby_soko/article/detai...
    BmobSnail閱讀 4,006評(píng)論 15 32
  • 成功的路上的確不擁擠 其實(shí)自己也很多次想放棄 但是幸好堅(jiān)持到現(xiàn)在了 畫不是為了模仿 而是為了創(chuàng)造 所以在畫的時(shí)候已...
    落瀟瀟落閱讀 260評(píng)論 0 1
  • 把溪流作海洋 以為星火可燎原 見(jiàn)一葉落便謂知秋 攜一管窺妄言觀天 輕信一見(jiàn)可鐘情 一笑便可傾心
    jianshuxuhan閱讀 313評(píng)論 0 0