<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                去年一整年android社區中刮過了一陣熱修復的風,各大廠商,逼格大牛紛紛開源了熱修復框架,恩,產品過程中怎么可能沒有bug呢?重新打包上線?成本太高用戶體驗也不好,咋辦?上熱修復唄。 好吧,既然要開始上熱修復的功能,那么就得調研一下熱修復的原理。下面我將分別講述一下熱修復的原理,各大熱修復框架的比較,以及自身產品中熱修復功能的實踐。 **熱修復的原理** 1. 通過更改dex加載順序實現熱修復 最新github上開源了很多熱補丁動態修復框架,大致有: [HotFix ](https://github.com/dodola/HotFix) [Nuwa ](https://github.com/jasonross/Nuwa) [DroidFix ](https://github.com/bunnyblue/DroidFix) 上述三個框架呢,根據其描述,原理都來自: [安卓App熱補丁動態修復技術介紹](https://mp.weixin.qq.com/s?__biz=MzI1MTA1MzM2Nw==&mid=400118620&idx=1&sn=b4fdd5055731290eef12ad0d17f39d4a&scene=1&srcid=1106Imu9ZgwybID13e7y2nEi#wechat_redirect),以及[Android dex分包方案](http://my.oschina.net/853294317/blog/308583),其核心原理就是通過更改含有bug的dex文件的加載順序。在dex的加載中,若以找到方法則不會繼續查找,所以如果能讓修復之后的方法在含有bug的方法之前加載就能達到修復bug的目的,而這個框架都是基于這個思路實現的,當然了具體實現過程中有很多坑,大家可以參考一下上面提到的兩篇文章。 2. 通過Native替換方法指針的方式實現熱修復 這里主要是阿里開源的兩個熱修復框架:[Dexpost ](https://github.com/alibaba/dexposed) [AndFix](https://github.com/alibaba/AndFix)都是通過Native層使用指針替換的方法替換bug,達到修復bug的目的的,具體可參考其github文章。 **各大熱修復框架的比較** 這里暫時比較了Dexpost,AndFix,HotFix,Nuwa,DroidFix等框架。 * Dexpost:(未測試) 1)原理:在底層虛擬機運行時hoop方法; 2)地址:https://github.com/alibaba/dexposed; 3)缺點:適配方面存在一些問題,目前不支持android6.0,5,1;art運行時; 4)優點:無需重啟就可以達到修復bug的目的; * AndFix:(已測試) 1)原理:在Native層使用指針替換的方法替換bug方法,達到修復bug的目的; 2)地址:https://github.com/alibaba/AndFix; 3)缺點:底層替換,穩定性方面可能需要實際檢測; 4)優點:無需中期就可以達到修復bug的目的; * HotFix:(個人維護,可能存在坑) 1)原理:通過替換類加載器中bugclass,達到修復bug的目的; 2)地址:https://github.com/dodola/HotFix; 3)缺點:需要重新啟動才可以修復bug; 4)優點:java運行層修復,穩定性較好; * Nuwa:(個人維護,可能存在坑) 1)原理:通過替換類加載器中bugclass,達到修復bug的目的; 2)地址:https://github.com/jasonross/Nuwa; 3)缺點:需要重新啟動才可以修復bug; 4)優點:java運行層修復,穩定性較好; * DroidFix:(個人維護,可能存在坑) 1)原理:通過替換類加載器中bugclass,達到修復bug的目的; 2)地址:https://github.com/bunnyblue/DroidFix; 3)缺點:需要重新啟動才可以修復bug; 4)優點:java運行層修復,穩定性較好; **其他的方面**: Dexposed不支持Art模式(5.0+),且寫補丁有點困難,需要反射寫混淆后的代碼,粒度太細,要替換的方法多的話,工作量會比較大。 AndFix支持2.3-6.0,但是不清楚是否有一些機型的坑在里面,畢竟jni層不像java曾一樣標準,從實現來說,方法類似Dexposed,都是通過jni來替換方法,但是實現上更簡潔直接,應用patch不需要重啟。但由于從實現上直接跳過了類初始化,設置為初始化完畢,所以像是靜態函數、靜態成員、構造函數都會出現問題,復雜點的類Class.forname很可能直接就會掛掉。 ClassLoader方案支持2.3-6.0,會對啟動速度略微有影響,只能在下一次應用啟動時生效,在空間中已經有了較長時間的線上應用,如果可以接受在下次啟動才應用補丁,是很好的選擇。 總的來說,在兼容性穩定性上, ClassLoader方案很可靠 ,如果需要應用 不重啟就能修復 ,而且方法足夠簡單,可以使用 AndFix ,而 Dexposed由于還不能支持art,所以只能暫時放棄,希望開發者們可以改進使它能支持art模式,畢竟xposed的種種能力還是很吸引人的。 **熱修復實踐** 最終我們App的熱修復方案選擇的是AndFix,原因有三: (1)AndFix支持android2.3-6.0,所以在機型上的是適配上是沒問題的; (2)AndFix是由阿里開源的,并且持續維護中,目前不少公司已經使用其作為自身App的熱修復方案; (3)通過修改Dex加載順序的方式實現熱修復需要重新啟動App,并且相應的開源框架多多少少存在著問題,沒有持續的維護; 因此我們最終選擇了AndFix作為我們的開源方案。具體的AndFix集成方式可參考[github中AndFix的介紹](https://github.com/alibaba/AndFix) 這里簡單介紹一下具體的繼承流程 (1)在App的Application的onCreate方法中執行AndFix的初始化操作; (2)判斷服務器端是否有可更新的熱修復差異包 (3)若無則直接退出,若有則下載并執行修復動作 (4)修復完成之后刪除下載的補丁差異包 (5)在判斷服務器端是否有可更新的補丁包的時候可添加灰度,如版本,渠道,用戶等,實現對補丁包定制化的修復 另外需要說明的是:若一個版本中存在著多個bug,則一般的都是讓后一個補丁包覆蓋前一個補丁包,并刪除前一個補丁包,簡單來說就是對于每一個版本至多有一個補丁包。 最后貼上App端AndFix的實現源碼: ~~~ /** * Created by aaron on 2016/3/7. * 主要用于實現熱修復邏輯 * 采用阿里巴巴開源框架-andfix * */ public class AndfixManager { public static final String TAG = AndfixManager.class.getSimpleName(); // AndfixManager單例對象 private static AndfixManager instance = null; // 補丁文件名稱 public static final String PATCH_FILENAME = "/patchname.apatch"; public static PatchManager patchManager = null; private AndfixManager() {} /** * 線程安全之懶漢模式實現單例模型 * @return */ public static synchronized AndfixManager getInstance() { return instance == null ? new AndfixManager() : instance; } /** * 執行andfix初始化操作 */ public static void init(Context mContext) { if (mContext == null) { L.i("初始化熱修復框架,參數錯誤!!!"); return; } patchManager = new PatchManager(mContext); // 初始化patch版本,這里初始化的是當前的App版本; patchManager.init(VersionUtils.getVersionName(mContext)); // 加載已經添加到PatchManager中的patch patchManager.loadPatch(); downLoadAndAndPath(mContext); } /** * 請求服務器獲取補丁文件并加載 */ public static void downLoadAndAndPath(final Context mContext) { // 請求服務器獲取差異包 ExtInterface.GetShContent.Request.Builder request = ExtInterface.GetShContent.Request.newBuilder(); // 獲取本地保存的補丁包版本號 final String patchVersion = AndfixSp.getPatchVersion(mContext); L.i(TAG, "patchVersion:" + patchVersion); if (!TextUtils.isEmpty(patchVersion)) { request.setShVersion(patchVersion); } else { request.setShVersion("0"); } NetworkTask task = new NetworkTask(Cmd.CmdCode.GetShContent_SSL_VALUE); task.setBusiData(request.build().toByteArray()); NetworkUtils.executeNetwork(task, new HttpResponse.NetWorkResponse<UUResponseData>() { @Override public void onSuccessResponse(UUResponseData responseData) { if (responseData.getRet() == 0) { try { ExtInterface.GetShContent.Response response = ExtInterface.GetShContent.Response.parseFrom(responseData.getBusiData()); // 若返回成功,則更新腳本下載補丁包 if (response.getRet() == 0) { ByteString zipDatas = response.getContent(); // 數據解壓縮 byte[] oriDatas = GZipUtils.decompress(zipDatas.toByteArray()); String patchFileName = mContext.getCacheDir() + PATCH_FILENAME; L.i(TAG, "patchFileName:" + response.getShVersion()); // 將byte數組數據寫入文件 boolean boolResult = getFileFromBytes(patchFileName, oriDatas); // 寫入文件成功則加載 if (boolResult) { patchManager.removeAllPatch(); patchManager.addPatch(patchFileName); // 保存補丁版本號 AndfixSp.putPatchVersion(mContext, response.getShVersion()); // 刪除補丁文件 File files = new File(patchFileName); if (files.exists()) { files.delete(); } } } else { // -1 請求失敗 // 1 請求成功,但是沒有更新版本的腳本 } } catch (Exception e) { e.printStackTrace(); } } } @Override public void onError(VolleyError errorResponse) { } @Override public void networkFinish() { } }); } /** * 根據數組獲取文件 * @param path * @param oriDatas */ public static boolean getFileFromBytes(String path, byte[] oriDatas) { boolean result = false; if (TextUtils.isEmpty(path)) { return result; } if (oriDatas == null || oriDatas.length == 0) { return result; } try { FileOutputStream fos = new FileOutputStream(path); fos.write(oriDatas); fos.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } } ~~~ **總結**: android的熱修復原理大體上分為兩種,其一是通過dex的執行順序實現Apk熱修復的功能,但是其需要將App重啟才能生效,其二是通過Native修改函數指針的方式實現熱修復,有興趣的同學可以深入研究。 [android產品研發(一)-->實用開發規范 ](http://blog.csdn.net/qq_23547831/article/details/51534013) [android產品研發(二)-->啟動頁優化 ](http://blog.csdn.net/qq_23547831/article/details/51541277) [android產品研發(三)-->基類Activity ](http://blog.csdn.net/qq_23547831/article/details/51546974) [android產品研發(四)-->減小Apk大小](http://blog.csdn.net/qq_23547831/article/details/51559066) [android產品研發(五)-->多渠道打包](http://blog.csdn.net/qq_23547831/article/details/51569261) [Android產品研發(六)–>Apk混淆](http://blog.csdn.net/qq_23547831/article/details/51581491)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看