APP熱更新方案(轉)

本文轉載自[http://creator.cnblogs.com/]java

博客地址:Zealot Yinandroid

 

爲何要作熱更新git

當一個App發佈以後,忽然發現了一個嚴重bug須要進行緊急修復,這時候公司各方就會忙得焦頭爛額:從新打包App、測試、向各個應用市場和渠道換包、提示用戶升級、用戶下載、覆蓋安裝。github

重點是還會有原來的版本遺留,不管你怎麼提示都有人放棄治療,不肯意升級,強制不能使用體驗又足夠糟糕到讓人不能啓齒。編程

若是這是一個影響公司收入或者體驗影響極其很差的Bug,那完蛋了,可能公司老闆會對整個技術團隊的技術能力喪失信心,其對技術人員的傷害是致命的。數組

最後最致命的是:服務器

有時候僅僅是由於不當心寫錯了一行代碼,就讓全部的加班都付之東流,苦不苦,冤不冤,想一想都苦。微信

還有一種劇情是研發總監把鍋甩給測試團隊,測試不過關,測試攤攤手說我也不是神啊,總會有漏網之魚.app

那能不能神不知鬼不覺再沒有產生較大影響前把bug快速修復了呢?框架

 

熱更新的行業狀況

先來講說Android

並非由於Android更有料就先說他,而是它的用戶量級比Iphone大,咱們寫文章也是講究大數據分析的不是..

Andoid端在15年熱補丁就比較火,前後出現了Dexposed、AndFix,Qzone超級補丁的類Nuwa方式,微信的Tinker, 大衆點評的nuwa、百度金融的rocooFix, 餓了麼的amigo以及美團的robust.

 

再來看看Iphone端

技術上要在 iOS 上作到原生動態化比 Android 更容易,iOS 開發語言 Objective-C 天生動態,運行時都能隨意替換方法,運行時加載動態庫又是項很老的技術,只要我把增量的代碼和資源打包到一個 framework 裏,動態下發運行時加載,修 bug,加功能都不在話下,性能徹底無損,這件事就結束了。

可是呢。蘋果把加載動態庫的功能給封了,動態庫必須跟隨安裝包一塊兒簽名才能被加載,沒法經過別的途徑簽名後再下發。

因而有了 waxPatch 和 JSPatch 這樣的方案,以及異軍突起不侷限於熱修復Bug而能作主體功能發佈的React Native 和 Weex,後面又有了吊口味的滴滴的DynamicCocoa方案和OCScript

 

熱更新的技術原理

先來講JAVA

技術派系:

Native,表明有阿里的Dexposed、AndFix與騰訊的內部方案KKFix;

Java,表明有Qzone的超級補丁、大衆點評的nuwa、百度金融的rocooFix, 餓了麼的amigo以及美團的robust。

Native流派與Java流派都有着本身的優缺點,它們具體差別你們可參考上文。事實上歷來都沒有最好的方案,只有最適合本身的。

 

 

下面咱們來一一簡單看下各熱更新的實現方案:

Dexposed

阿里開源項目,基於Xposed的AOP框架,方法級粒度,能夠進行AOP編程、插樁、熱補丁、SDK hook等功能。

不一樣的是,Xposed經過劫持 zygote(須root),而dexposed經過劫持 java method ( 而非樓上說的劫持class loader方法),將java method改變爲native,而且將這個方法的實現連接到一個通用的Native Dispatch方法上.)用處,最大的天然是hotpatch,用這種東西來熱替換某個致使崩潰的方法。手淘還有作的一件事,就是用它做性能監控。這主要得益於無侵入式的方法調用Befor和After事件,可以讓咱們很好的記錄和分析一個方法的調用時間。開源項目promeG/XLog就是基於dexposed實現的方法調用logging

使用方法:

dexposed提供了3個使用方法:

 

beforeHookedMethod
afterHookedMethod
replaceHookedMethod

 

來看看使用方式,也極其簡單.

 

 

優缺點:

來講說硬傷吧,不支持art,不支持art,不支持art。

不支持Dalvik 3.0. 

 

因此註定它會逐步失聲,再多的優勢也是徒勞

 

插播一條硬廣: 技術文章轉發收錄太多,此文出處 http://www.cnblogs.com/Creator/ 以及微信公衆號: 互聯網手藝人

 

Qzon的超級補丁方案

該方案基於的是android dex分包方案的,關於dex分包方案自己更可能是爲了解決Android的64K方法調用限制問題,具體的緣由是:

• DexOpt 會把每個類的方法 id 檢索起來,存在一個鏈表結構裏面,可是這個鏈表的長度是用一個 short 類型來保存的,致使了方法 id 的數目不可以超過65536個。當一個項目足夠大的時候,顯然這個方法數的上限是不夠的。

•Dexopt 使用 LinearAlloc 來存儲應用的方法信息。Dalvik LinearAlloc 是一個固定大小的緩衝區。在Android 版本的歷史上,LinearAlloc 分別經歷了4M/5M/8M/16M限制。Android 2.2和2.3的緩衝區只有5MB,Android 4.x提升到了8MB 或16MB。當方法數量過多致使超出緩衝區大小時,也會形成dexopt崩潰

儘管在新版本的 Android 系統中,DexOpt 修復了方法數65K的限制問題,而且擴大了 LinearAlloc 限制,可是這套技術機制保留了下來

 

分包的方案簡單來講就是在打包時將應用的代碼分紅多個 dex,使得主 dex 的方法數和所需的 LinearAlloc 不超過系統限制。在應用啓動或運行過程當中,首先是主 dex 啓動運行後,再加載從 dex,這樣就繞開了這兩個限制。

如何拆分和如何加載能夠查看Google官方的方案MultiDex

http://developer.android.com/intl/zh-cn/tools/building/multidex.htm

 

Qzon的超級補丁方案玩的是什麼招呢?

把BUG方法修復之後,放到一個單獨的DEX裏,插入到dexElements數組的最前面,讓虛擬機去加載修復完後的方法。

Patch.dex中的A.class會有優先加載,後續的dex中的A.class就不會加載直接跳過,達到修復目的。

 

核心問題:

當兩個調用關係的類不在同一個DEX時,就會產生異常報錯。咱們知道,在APK安裝時,虛擬機須要將classes.dex優化成odex文件,而後纔會執行。在這個過程當中,會進行類的verify操做,若是調用關係的類都在同一個DEX中的話就會被打上CLASS_ISPREVERIFIED的標誌,而後纔會寫入odex文件。具體如何解決這個問題能夠參見QQ空間終端開發團隊QQ空間終端開發團隊發佈的」 安卓App熱補丁動態修復技術介紹」

 

優缺點:

1.沒有合成整包(和微信Tinker比起來),產物比較小,比較靈活

2.能夠實現類替換,兼容性高。(某些三星手機不起做用)

不足:

1.不支持即時生效,必須經過重啓才能生效。

2.爲了實現修復這個過程,必須在應用中加入兩個dex!dalvikhack.dex中只有一個類,對性能影響不大,可是對於patch.dex來講,修復的類到了必定數量,就須要花很多的時間加載。對手淘這種航母級應用來講,啓動耗時增長2s以上是不可以接受的事。

3.在ART模式下,若是類修改告終構,就會出現內存錯亂的問題。爲了解決這個問題,就必須把全部相關的調用類、父類子類等等所有加載到patch.dex中,致使補丁包異常的大,進一步增長應用啓動加載的時候,耗時更加嚴重。

 

 

微信Tinker

根據微信內部人士介紹:微信tinker項目之初最大難點在於如何突破Qzone方案的性能問題,經過研究Instant Run的冷插拔與buck的exopackage給了咱們靈感。它們的思想都是全量替換新的Dex

 

由於使用全新的dex,因此天然繞開了Art地址可能錯亂的問題,在Dalvik模式下也不須要插樁,加載全新的合成dex便可。

焦點問題是合併的過程會不會有問題,會不會耗時或者效率低? 爲此騰訊在DEX方面也花了不少時間研究內部的格式以及如何作Merge和進行校驗工做,詳細瞭解能夠查看」 大騰訊的第一個開源項目「Tinker」」這篇文章

優點:

1. 合成整包,不用在構造函數插入代碼,防止verify,verify和opt在編譯期間就已經完成,不會在運行期間進行

2. 性能提升。兼容性和穩定性比較高。

3. 開發者透明,不須要對包進行額外處理。

不足:

1. 與超級補丁技術同樣,不支持即時生效,必須經過重啓應用的方式才能生效。

2. 須要給應用開啓新的進程才能進行合併,而且很容易由於內存消耗等緣由合併失敗。

3. 合併時佔用額外磁盤空間,對於多DEX的應用來講,若是修改了多個DEX文件,就須要下發多個patch.dex與對應的classes.dex進行合併操做時這種狀況會更嚴重,所以合併過程的失敗率也會更高。

 

 

阿里Andfix方案

爲什麼惟獨Andfix可以作到即時生效呢?

緣由是這樣的,在app運行到一半的時候,全部須要發生變動的Class已經被加載過了,在Android上是沒法對一個Class進行卸載的。而騰訊系的方案,都是讓Classloader去加載新的類。若是不重啓,原來的類還在虛擬機中,就沒法加載新類。所以,只有在下次重啓的時候,在還沒走到業務邏輯以前搶先加載補丁中的新類,這樣後續訪問這個類時,就會Resolve爲新的類。從而達到熱修復的目的。

Andfix採用的方法是,在已經加載了的類中直接在native層替換掉原有方法,是在原來類的基礎上進行修改的。

以Art爲例,每個Java方法在art中都對應着一個ArtMethod,ArtMethod記錄了這個Java方法的全部信息,包括所屬類、訪問權限、代碼執行地址等等。經過env->FromReflectedMethod,能夠由Method對象獲得這個方法對應的ArtMethod的真正起始地址。而後就能夠把它強轉爲ArtMethod指針,從而對其全部成員進行修改。

這很C/C++ 研發的味道,實際上Andfix的核心代碼replaceMethod就是用cpp寫的。

 

面臨的挑戰:

由於安卓各ROM亂象的緣由,ArtMethod的結構可能會不同, ArtMethod類包含些什麼其實都是在編譯階段,在運行階段可能不是這麼回事,例如sizeof(ArtMethod)可能實際在各平臺就徹底不同,可是咱們在編譯的時候就肯定了值,直接操做容易改亂內存數據致使奔潰。

有什麼好的方法來解決這個問題呢?

來看看奇技淫巧

因爲f1和f2都是static方法,因此都屬於direct ArtMethod Array。因爲NativeStructsModel類中只存在這兩個方法,所以它們確定是相鄰的。

那麼咱們就能夠在JNI層取得它們地址的差值:

而後,就以這個methSize做爲sizeof(ArtMethod),代入以前的代碼。

問題就迎刃而解了。即便之後的Android版本不斷修改ArtMethod的成員,只要保證ArtMethod數組還是以線性結構排列就能完美兼容。

著:此方法最新方案並不在開源的方案中

 

最大的優點在於

1. BUG修復的即時性

2. 補丁包一樣採用差量技術,生成的PATCH體積小

3. 對應用無侵入,幾乎無性能損耗

不足:

1. 不支持新增字段,以及修改<init>方法,也不支持對資源的替換。

 

 

再來看看IOS的熱更新技術:

蘋果把加載動態庫的功能給封了,動態庫必須跟隨安裝包一塊兒簽名才能被加載,沒法經過別的途徑簽名後再下發。

 

Wax

最先要從 Wax 這個項目開始說,你們都知道 Objective-C 有着很是強大的動態特性。好比說:

•運行時構造類和方法

•運行時替換方法的實現實際上這兩個能力是很是恐怖的像腳本語言那樣,文本即代碼,無須編譯。後來出現了一個叫作 Wax的項目(這個項目目前由阿里巴巴維護),這個項目打出的口號是用 Lua 來寫 iOS 原生應用,固然現實中沒有人會這樣幹,由於寫起來實在是太痛苦了。可是鑑於 iOS 應用審覈比寫 Wax 還痛苦,因此 Wax 成爲了作 HotFix 的最佳選擇。

這個項目的作法是經過加載 Lua 腳本,動態的生成 Objective-C 的方法,一般用來替換掉出了問題的那個,Lua 腳本是能夠動態下發的,因此也就實現了修復線上 bug 的使命。

固然,Wax 用起來是極爲痛苦的,尤爲是和 Objective-C 的類型轉換。

 

JSPatch

iOS 7 的時候 Apple 推出了 JavaScriptCore,這是一個很是有趣的框架,他是 JS 與原生交互的橋樑,讓你在原生和 JS 之間穿梭自如,如今 iOS 平臺各類動態技術大多都是基於此。

JSCore 推出不久以後,一個更優秀的項目誕生了:由 bang 寫的 JSPatch。這個項目無疑從各類角度碾壓了 Wax,而且 JS 也比 Lua 更爲人熟知,因此也就迅速替代 Wax 成爲了熱修復的主流選擇。

JSPatch 的接入成本很是低,對項目的影響也很是小,不須要引入額外的腳本解釋器(由於已經有 JSCore 了),而且 JS 寫起來真的比 Lua 要爽不少。

3月8日,不少iOS開發者發了警告郵件,聲稱其App違規使用動態方法,責令限時整改,Jspatch一直就被打入冷宮了

此次警告事件無疑是對iOS平臺Native動態化是一次嚴重打擊,其影響甚至可能波及到Android平臺,畢竟Google也是禁止加載遠程代碼的,而且執行更爲嚴格,只是管不到中國的Android開發而已。

 

滴滴的DynamicCocoa

DynamicCocoa這種方案,繞了一個更大的道,從編譯階段入手,經過 clang 把 OC 代碼編譯成本身定製的 JS 格式,再動態下發去執行,作到原生開發,動態運行,主打動態添加功能,固然順便把修 bug 也給支持了。手機 QQ 內部也有一個相似的方案,不過更進一步,他們經過 clang 把 OC 代碼編譯成本身定製的字節碼動態下發,而後開發一個虛擬機去執行(驚呆了),一樣實現了原生開發,動態運行,都是 NB 得很的方案。只要底層處理作得足夠好,也是個成本低收益高的方案,不過目前都還沒開源,在github上是一個只有兩行README可是有1000+Star的神奇項目

 

DynamicCocoa與Jspatch 思路上都是實現 JS 和 OC 的互調:DynamicCocoa 的重點是動態化能力,優點在於徹底不用寫 JS 和更多的語法特性支持;對於 HotPatch 來講 JSPatch 是更加小巧、輕量的解決方案。

 

聽說在滴滴 App 已經上線並使用了好幾個版本,如滴滴小巴、專車接送機都有過 10k 級別的動態化模塊上線。

 

20170612 蘋果已經正式禁止熱更新,給涉及到檢測出來的開發者發了郵件,同時提供 App Store 「自動更新的分階段發佈」 功能。

蘋果是如何檢測的呢,大概能夠從給開發者的郵件看出來:

 

 

最後咱們來看看蘋果的灰度發佈功能吧,對於一個花了將近3年時間作國內超大規模私有云的我來講,感覺到了熟悉的味道(服務器端灰度發佈也是一個套路)

相關文章
相關標籤/搜索