天天看點

Android熱修複技術(一)

現在的android熱修複技術大行其道,各大公司基本都有自己的一套熱修複機制,頓覺是時候學習一波了,通過閱讀了阿裡的android熱修複技術原理,收益頗豐,在這裡寫下一些了解。

線上出現了bug怎麼辦?

1、傳統的更新流程是緊急修複,然後重新釋出,但是需要使用者進入應用商店,下載下傳完成更新,顯然使用者體驗非常差

2、是以有人想出了一種解決方案,采用Hybrid方案,把需要經常變更的業務邏輯用H5抽象出來,但是不僅增加了傳統的java開發人員的學習成本,一些難以轉換為H5的代碼依舊是無法解決上述的問題。

3、插件化方案,比如Atlas,但是移植成本比較高,需要學習整套插件化工具,對于小中型的app,顯得不合适了。

4、熱修複技術。把更新更新檔上傳到雲端,此時app直接從雲端拉取出更新檔并應用生效。是以出現bug後的流程是打出更新檔,推送給使用者,使用者自動拉取更新檔修複。

熱修複方案好壞判斷的名額

DEX修複,資源更新,so庫更新,性能損耗,四大元件,生成更新檔, 接入成本,安全機制,服務端支援等。

阿裡的sopfix在以上各方面基本領先于微信的Tinker和餓了嗎的Amigo,比如在DEX修複上支援即時生效和冷啟動生效,在性能損耗上低,傻瓜式接入,隻是不能支援四大元件修複,因為如果要支援,就必須在manifest裡預先插入代理元件,并盡可能的聲明所有的權限,這樣使得app很臃腫。

代碼修複方案

一種是阿裡系的底層替換方案,另一種是騰訊系的類加載方案。

兩種方法都各有優劣,底層替換方案限制比較多,但是時效性好,加載輕快;

類加載時效性差,需要冷啟動才有效,但是修複範圍廣,限制少。

底層替換方案

底層替換方案是在已經加載了的類中替換已經存在的原有方法,不能對原有類進行字段和方法的增删。

1、對類的方法不能增删的原因是一旦對方法進行了增删,勢必會導緻原有方法數的變化以及dex方法索引的變化,通路方法時就不能正常的通路了。

2、對字段不能進行增删的原因也大緻一樣,而且如果某一個類生成了一個執行個體,他原來的類的結構是無法改變的,如果新的方法使用老的對象通路新的字段這個肯定會出現問題的。

另外底層替換也是很不穩定的!

一般來說,傳統的底層替換方案都是直接依賴于修改虛拟機方法實體的具體字段,例如更改jni函數指針,改類或者方法的通路權限。但是由于android是開源的,各大廠商都能對android底層源碼進行修改,但是熱修複方案中的ArtMethod的結構體是寫死的,那麼就容易發生問題。

sopfix 方案:

出于對相容性和擴充性的考慮,sopfix實作了一種無視底層具體結構的替換方式,隻要保證ArtMethod數組是以線性的結構進行排列,就能直接應用起來。具體是如何實作的,後面再闡述。

類加載方案

類加載方案的原理是在app重新啟動後讓Classloader去加載新的類。

往往将兩種方法結合才是好的,針對小修改,在底層替換方案的限制内,就直接采用底層替換方案,可以做到代碼的立即修複,如果代碼修改超出底層替換限制的,會使用類加載替換。

資源修複方案

大多數的熱修複方案都是參考了Instant Run的代碼,Instant Run的資源修複方案分為兩步:

1、構造出一個AssetManager,通過反射調用addAssetPath,并把這個完整的新的資源包加入到AssetManager中,這樣就得到了一個含有所有新資源的AssetManager。

2、找到原來所有用到原來AssetManager的地方,利用反射,将引用處進行替換。

sopfix 方案:

構造了一個package id 為0x66 的資源包,這個包裡隻有改變了的資源項,直接在原有的AssetManager中addAssetPath就可以了,由于更新檔包中的package id 為0x66 與原來的不一樣,是以可以直接加入到原有的AssetManager中,并且在原有的AssetManager對象上進行析構和重構, 這樣原有的AssetManager對象的引用是沒有發生變化的。

好處:1、不修改AssetManager的引用,替換更快更安全。(對比Instant run)

2、不必下發完整包。(對比Instant Run 和Amigo)

3、不需要在運作時合成完整包,不占用計算機的記憶體資源。(對比Tinker)

SO庫修複

sophix方案:

采用類似類修複反射注入方式,把更新檔so庫的路徑插入到nativeLibraryDirectories數組最前面,達到加載so庫的時候加載的是更新檔的so庫。