增量更新與Dex文件簡析

增量更新

概述

簡單點來說就是兩個文件:old和new,可通過差分工具生成它們的差分包patch,當我們需要時,再可以通過另外一個合成工具在只有old和patch的情況下,恢復生成new文件。這在Android中有什么用呢?它的應用場景很廣泛,拿一個常見的場景來舉例,利用這個技術,可以省流量更新我們手機上已安裝的App,目前各大應用市場基本都實現(xiàn)增量更新。我們安裝在手機上的App在我們的存儲卡上都保留有對應的安裝包,可以理解為old文件,它位于“/data/app/”文件夾下。當我們進行版本迭代時,會上傳給應用市場一個完整的安裝包,應用市場會更據(jù)以前的安裝包跟最新的安裝包生成對應的差分包對用戶進行下發(fā),在用戶端再進行差分包與原有版本的合成,達到省流量的目的。當然這其中過程中還涉及到對文件完整性MD5校驗與簽名校驗,以及可能出現(xiàn)差分包比原始包更大的情況,需要采取合適的下發(fā)策略。不僅是應用市場,我們的應用內(nèi)更新也可以采取相同方案。此處不再贅述。

增量更新與全量更新

  • 增量更新 就是根據(jù)歷史某一個節(jié)點和最新的一個節(jié)點,對二者進行一個差分包的生成,然后再合成的一個方案。通常我們在發(fā)布某一版本的App時,前面已經(jīng)發(fā)布了很多的版本,服務端可根據(jù)最近的幾個版本分別做一下差分包進行下發(fā),更遠的版本可不用考慮,直接給一個完整的安裝包。

  • 全量更新 可以理解為我們直接給一個完整的安裝包,當我們生成的差分包文件很大或者版本太多,差分包的管理太繁瑣時,可采用全量更新策略

增量更新與熱修復

很多人對增量更新與熱修復的概念比較模糊,這里著重強調一下,增量更新是在版本更新時,根據(jù)差分包生成一個新的安裝包然后再安裝,會有一個安裝的過程。熱修復是用來修復bug的,比如QQ控件熱修復方案,利用dx命令對某個出現(xiàn)bug的類打包成dex補丁包,然后再利用類加載機制,通過hook技術替換已加載的類達到修復的目的,這個過程是無感知的,不會重新安裝apk,本質上安裝在手機里的還是原來版本的apk。

常用差分、合成工具

網(wǎng)上有文章對BSDiff/Patch、HDiffPatch和XDelta三種差分包實現(xiàn)方案做對比測試,在Android APK的差分更新實現(xiàn)上,XDelta差分方案實現(xiàn)是最優(yōu)的。但是BSDiff/Patch 實現(xiàn)方案是最多的,網(wǎng)上一大堆都是這個方案的實現(xiàn),Android系統(tǒng)也整合了這個實現(xiàn),所以這里也使用它作為實例講解怎么使用。

BSDiff

它是基于二進制來比較兩個文件的大小,與文件格式無關,所以生成的安裝包大小也不穩(wěn)定。官網(wǎng)下載網(wǎng)址為

http://www.daemonology.net/bsdiff/

下載完后可以看到如下文件

在window環(huán)境下可以通過CLion來編譯生成exe,當然用vs也可以,喜歡的同學可以自己去探究

bsdiff

bsdiff是用來生成差分包的,可以通過如下命令來生成

C:\Users\XXX\Desktop\bsdiff>bsdiff old.apk new.apk patch.apk

介紹下上面命令的用法:

bsdiff:固定寫法

old.apk:舊文件名稱

new.apk: 新文件名稱

patch.apk :生成的差分包名稱,可隨便取名

最終生成

old、new是我們的歷史版本與最新版本,patch.apk就是我們生成的目標文件

bspatch

下面介紹下,我們Android端怎么使用bspatch來合成我們的安裝包,上面演示的是在windows環(huán)境下生成差分包,但我們Android是基于linux的,自然不能使用exe文件,我們得把源碼拿過來在我們的App內(nèi)生成so庫再使用。關于NDK基礎部分我們略過。

1.新建c/c++工程,并把源碼拷貝過來,配置好cmake文件

2.編寫native方法

 



其中圖中的executePatch方法為源文件中的main方法,只是這里為了方便辨識,給改了個名字而已

3.合成差分包并安裝

最終在activity中調用patch方法即可進行安裝包的合成


patch包在這里由手動放在data/data/packagename/cache/目錄下的來模擬從服務器請求的情況,app.apk即為我們生成的目標文件,通過安裝它來更新App

demo源碼鏈接如下:

https://github.com/xuchengpu/BSPatch.git

Dex文件簡析

Dex文件是Android系統(tǒng)的可執(zhí)行文件,包含應用程序的全部操du作指令以及運行時數(shù)據(jù)。 當java程序編譯成class后,還需要使用dx工具將所有的class文件整合到一個dex文件,目的是其中各個類能夠共享 數(shù)據(jù),在一定程度上降低了冗余,同時也使文件結構更加緊湊,實驗表明,dex文件是傳統(tǒng)jar文件大小的50%左 右。dex 文件可以分為3個模塊,頭文件、索引區(qū)、數(shù)據(jù)區(qū)。頭文件概況的描述了整個 dex 文件的分布,包括每一個索 引區(qū)的大小跟偏移。索引區(qū)表示每個數(shù)據(jù)的標識,索引區(qū)主要是指向數(shù)據(jù)區(qū)的偏移。

從圖中可以看出,像String_ids、Type_ids等這些每個文件共有的信息,都被整合到一起,減少文件體積大小。

我們可以使用010Editor查看工具打開一個dex來同步分析。

image-20200908110318953

Header

是dex文件的頭部,記錄整個dex文件的相關屬性,長度為112個字節(jié)。

頭文件里包含以下部分:

magic(魔數(shù)):每個文件的頭文件里前8個字節(jié),代表文件的格式

checksum: 文件校驗碼,使用 alder32 算法校驗文件除去 maigc、checksum 外余下的所有文件區(qū)域,用于 檢 查文件錯誤。 signature: 使用 SHA-1 算法 hash 除去 magic、checksum 和 signature 外余下的所有文件區(qū)域, 用于唯一 識別本文件 。 file_size: dex 文件大小 header_size: header 區(qū)域的大小,固定為 0x70 endian_tag: 大小端標簽,dex 文件格式為小端,固定值為 0x12345678 map_off: map_item 的偏移地址,該 item 屬于 data 區(qū)里的內(nèi)容,值要大于等于 data_off 的大小,處于 dex 文件的末端。

其他 xx_off , xx_size 成對出現(xiàn),表示數(shù)據(jù)的偏移與數(shù)據(jù)個數(shù)。

這里以16進制方式來查看magic為例:

這幾個數(shù)值轉換為字符串為dex.035,被稱為文件簽名。dex代表文件格式,035代表版本號。

索引區(qū)

StringIds : 描述了 dex 文件中所有的字符串。記錄的數(shù)據(jù)只有一個偏移量,偏移量指向了 數(shù)據(jù)區(qū)Data中 的一 個字符串

type_ids : 類似數(shù)據(jù)索引,記錄了每個類型的字符串索引

proto_ids : 原型數(shù)據(jù)索引,記錄了方法聲明的字符串,返回類型字符串,參數(shù)列表

field_ids : 字段數(shù)據(jù)索引,記錄了所屬類,類型以及方法名

method_ids :類方法索引,記錄方法所屬類名,方法聲明以及方法名等信息

class_defs :類定義數(shù)據(jù)索引,記錄指定類各類信息,包括接口,超類,類數(shù)據(jù)偏移量

數(shù)據(jù)區(qū)

保存了各個類的真實數(shù)據(jù)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容