Android APP 增量更新demo
隨著現(xiàn)在手機(jī)硬件不斷的提升,分辨率提高手機(jī)的安裝包也是越來越大了。當(dāng)年NOKIA,MOTO時(shí)代,一個(gè)手機(jī)APP如果有1MB那都是算大的,2MB已經(jīng)不得了了。雖然網(wǎng)絡(luò)、存儲(chǔ)都已經(jīng)大大提升,但是流量還不至于廉價(jià)到APP改了一個(gè)標(biāo)題要去下載一個(gè)幾兆的程序安裝包。今天就介紹安卓增量下載的實(shí)現(xiàn)。有耐心的先看原理,后面實(shí)踐!
增量升級(jí)的原理
今天我們就來實(shí)現(xiàn)類似的應(yīng)用的增量升級(jí)。其實(shí)增量升級(jí)的原理很簡(jiǎn)單,即首先將應(yīng)用的舊版本Apk與新版本Apk做差分,得到更新的部分的補(bǔ)丁,例如舊版本的APK有5M,新版的有8M,更新的部分則可能只有3M左右(這里需要說明的是,得到的差分包大小并不是簡(jiǎn)單的相減,因?yàn)槠鋵?shí)需要包含一些上下文相關(guān)的東西),使用差分升級(jí)的好處顯而易見,那么你不需要下載完整的8M文件,只需要下載更新部分就可以,而更新部分可能只有3、4M,可以很大程度上減少流量的損失。
在用戶下載了差分包之后,需要在手機(jī)端將他們組合起來??梢詤⒖嫉淖龇ㄊ窍葘⑹謾C(jī)端的舊版本軟件(多半在/data/下),復(fù)制到SD卡或者cache中,將它們和之前的差分patch進(jìn)行組合,得到一個(gè)新版本的apk應(yīng)用,如果不出意外的話,這個(gè)生成的apk和你之前做差分的apk是一致的。
增量升級(jí)的操作
在了解基本的原理之后,我們來逐步解決其中的各個(gè)難點(diǎn)。首先是差分包patch的生成。如果做過android手機(jī)OTA升級(jí)的同學(xué)應(yīng)該注意到,在update.zip中的patch文件夾中有需要與系統(tǒng)文件同名但是以xxx.p 為后綴的文件,他們就是生成的差分patch文件。我們可以借鑒OTA系統(tǒng)升級(jí)的差分生成工具來生成我們單個(gè)應(yīng)用apk的差分patch文件。OTA系統(tǒng)差分包的制作,使用命令:
./ota_from_target_files -n -i
diff_program = DIFF_PROGRAM_BY_EXT.get(ext, “bsdiff”)
至此我們就看到了android中提供我們用來制作差分增量升級(jí)包的工具,”bsdiff”,這是一個(gè)很牛X開源的二進(jìn)制差分工具.相關(guān)的介紹傳送門 相關(guān)的代碼地址 或者在android的代碼目錄下 externalbsdiff bsdiff是二進(jìn)制差分工具,其對(duì)應(yīng)的bspatch是相應(yīng)的補(bǔ)丁合成工具 需要注意的是增量升級(jí)的補(bǔ)丁包,是需要在服務(wù)器端,即PC端完成,大致流程如,制作補(bǔ)丁時(shí)調(diào)用bsdiff函數(shù),根據(jù)兩個(gè)不同版本的二進(jìn)制文件,生成補(bǔ)丁文件。
命令:bsdiff oldfile newfile patchfile
例如: bsdiff xx_v1.0.apk xx_v2.0.apk xx.patch
將生成的補(bǔ)丁包 xx.patch放置在升級(jí)服務(wù)器上,供用戶下載升級(jí),對(duì)應(yīng)多版本需要對(duì)不同的版本進(jìn)行差分,對(duì)于版本跨度較大的,建議整包升級(jí)。 用戶在下載了 xx.patch補(bǔ)丁包后,需要用到補(bǔ)丁所對(duì)應(yīng)的apk,即原來系統(tǒng)安裝的舊版本apk和補(bǔ)丁合成的bspatch工具。系統(tǒng)舊版本的apk可以通過copy系統(tǒng)data/app目錄下的apk文件獲取,而補(bǔ)丁合成的bspatch可以通過將bspatch源碼稍作修改,封裝成一個(gè)so庫,供手機(jī)端調(diào)用。
bspatch的命令格式為:
bspatch oldfile newfile patchfile
和差分時(shí)的參數(shù)一樣。合成新的apk便可以用于安裝。 以上只是簡(jiǎn)單的操作原理,增量升級(jí)還涉及很多其他方面,例如,升級(jí)補(bǔ)丁校驗(yàn)等問題,可以參考android源碼中bootablerecoveryapplypatch的相關(guān)操作,本文只是淺析,在此不表。 不足 增量升級(jí)并非完美無缺的升級(jí)方式,至少存在以下兩點(diǎn)不足: 1.增量升級(jí)是以兩個(gè)應(yīng)用版本之間的差異來生成補(bǔ)丁的,你無法保證用戶每次的及時(shí)升級(jí)到最新,所以你必須對(duì)你所發(fā)布的每一個(gè)版本都和最新的版本作差分,以便使所有版本的用戶都可以差分升級(jí),這樣操作相對(duì)于原來的整包升級(jí)較為繁瑣,不過可以通過自動(dòng)化的腳本批量生成。 2.增量升級(jí)成功的前提是,用戶手機(jī)端必須有能夠讓你拷貝出來且與你服務(wù)器用于差分的版本一致的apk,這樣就存在,例如,系統(tǒng)內(nèi)置的apk無法獲取到,無法進(jìn)行增量升級(jí);對(duì)于某些與你差分版本一致,但是內(nèi)容有過修改的(比如破解版apk),這樣也是無法進(jìn)行增量升級(jí)的,為了防止合成補(bǔ)丁錯(cuò)誤,最好在補(bǔ)丁合成前對(duì)舊版本的apk進(jìn)行sha1sum校驗(yàn),保證基礎(chǔ)包的一致性。 小實(shí)驗(yàn) 多說無益,實(shí)踐才是王道。下面就來簡(jiǎn)單實(shí)踐一下,檢測(cè)之前理論的正確性。
├── bsdiff-4.3 //bsdiff的源碼路徑,官網(wǎng)獲取
│ ├── bsdiff.1
│ ├── bsdiff.c
│ ├── bspatch.1
│ ├── bspatch.c
│ └── Makefile
├── bsdiff-4.3.tar.gz
├── bsdiff4.3-win32 //windows PC端的測(cè)試工具
│ ├── Binary diff.txt
│ ├── bsdiff.exe
│ ├── bspatch.exe
│ └── LICENSE
├── bspatch //手機(jī)端的測(cè)試工具
├── oldAPK1.6.2.apk // 舊版本的apk
└── newAPK1.8.0.apk //新版本的apk
APK來做測(cè)試,在shell進(jìn)入testbsdiff4.3-win32文件夾,并下運(yùn)行命令:
1bsdiff.exe
oldAPK1.6.2.apk newAPK1.8.0.apk apk.patch
原來的apk(2.94M),新版本的(3.24M),得到的patch文件為1.77M,用戶需要下載的就只是1.77M,流量節(jié)省了很多。 下面先在電腦端將他們合并。
bspatch.exe oldAPK1.6.2.apk new.apk apk.patch
執(zhí)行后得到名為new.apk 的合成版本應(yīng)用。這個(gè)和我們newAPK1.8.0.apk其實(shí)是一樣的。
現(xiàn)在寫一個(gè)安卓小DEMO出來,測(cè)試一下這個(gè)工具。直接在創(chuàng)建安卓工程的時(shí)候添加native支持,在CPP文件中添加以下代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205#include
"com_droidupdate_jni_PatchUtil.h"
#include
"bzlib_private.h"
#include
"bzlib.h"
#include
#include
#include
#include
#include
#include
#include
static
off_t
offtin(u_char *buf) {
off_t
y;
y
= buf[
7
]
&
0x7F
;
y
= y *
256
;
y
+= buf[
6
];
y
= y *
256
;
<code class="java plain" style="border:0px!important; padding:0px!important; bottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; margin:0px!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:base