當(dāng)我們要更新一個(gè)應(yīng)用的時(shí)候,以前很多更新的做法是下載一個(gè)新版本去覆蓋一個(gè)舊版本。隨著現(xiàn)在應(yīng)用越來(lái)越大,我們就不得不考慮流量的問(wèn)題。
Google也意識(shí)到不斷更新應(yīng)用對(duì)用戶流量的損耗,于是在Google?I/O上提及了增量升級(jí),或者叫差分升級(jí)的方法,并在新版本的Google?Play中得到支持。
簡(jiǎn)單的來(lái)說(shuō),增量更新是指在進(jìn)行更新操作時(shí),只更新需要改變的地方,不需要更新或者已經(jīng)更新過(guò)的地方則不會(huì)重復(fù)更新,增量更新與完全更新相對(duì)。
增量升級(jí)的原理其實(shí)不難,我們首先使用舊版本的apk與新版本的apk做差分,就能得到更新部分的補(bǔ)丁,也叫差分包。這個(gè)差分包雖然不是新舊版本的簡(jiǎn)單相減,但顯而易見(jiàn)的是,用戶不需要全部下載新版本apk了,我們只要下載更小的那個(gè)補(bǔ)丁包(差分包)。
在用戶下載完差分包后,需要在手機(jī)端將它們組合起來(lái)。一般手機(jī)的應(yīng)用安裝在data/app下,我們可以復(fù)制出就版本apk至SD卡中,與下載好的差分包進(jìn)行組合。最后得到一個(gè)新版本的apk后與服務(wù)器上的新版本進(jìn)行校驗(yàn),正確后就可以安裝了。
NDK(native?develop?kits),是一個(gè)交叉編譯的工具鏈。交叉編譯是指:在一個(gè)平臺(tái)下(CPU,操作系統(tǒng))可以編譯出在另外一個(gè)平臺(tái)可以運(yùn)行的代碼,例如我們正要做的:windows?AMD?intel?x86架構(gòu)->手機(jī)android?arm處理器。
下載地址:http://www.android-doc.com/tools/sdk/ndk/index.html
Cygwin是一個(gè)可以在windows下模擬出linux環(huán)境的一個(gè)工具,NDK必須在linux環(huán)境下進(jìn)行編譯等工作。
安裝過(guò)程略。需要注意的是在Selectpackages安裝界面中把Default改為Install,直接點(diǎn)擊Default即可。
完成安裝后,我們啟動(dòng)Cygwin,輸入make??-v命令,出現(xiàn)如下信息說(shuō)明安裝成功了。

我們cd到NDK的目錄,執(zhí)行./ndk-build命令,出現(xiàn)如下信息則說(shuō)明大功告成。

2.3.在Eclipse中或MyEclipse中安裝CDT插件(可選)
將下載好的安裝包解壓,把features、plugins目錄下的文件對(duì)應(yīng)的復(fù)制到Eclipse(MyEclipse)中即可,重啟軟件。
首先要生成舊版本和新版本的差分比patch文件,我們可以借助bsdiff開源庫(kù)的windows版本。我們先下載bsdiff壓縮包,解壓后有以下兩種工具。

Bsdiff.exe就是一個(gè)二進(jìn)制差分工具,bspatch.exe就是相應(yīng)的補(bǔ)丁合成工具了。我們的增量升級(jí)的差分包,是要在服務(wù)端完成的,也就是pc端去完成。我們打開命令行,轉(zhuǎn)到bsdiff所在目錄下,將新舊版本的apk也放到該目錄下,執(zhí)行命令:
bsdiff.exeoldName.apknewName.apkpatch.patch
Patch文件的名字可自己定義。如測(cè)試程序中的兩個(gè)版本的apk。

將生成的差分包xx.patch放置到升級(jí)服務(wù)器上,供用戶下載升級(jí)。如果多版本,則必須對(duì)不同版本都進(jìn)行差分。如果版本跨度太大,可以選擇整包升級(jí)。
測(cè)試中將上一步生成的Update.patch包放在發(fā)布服務(wù)器Tomcat上。
我們建一個(gè)Android工程,命名為UpdateDemo,用來(lái)實(shí)現(xiàn)應(yīng)用增量更新功能。在工程中建一個(gè)包,編寫本地方法。

我們首先用NDK編譯出一個(gè)*.so文件。這個(gè)文件網(wǎng)上有編譯好的,可以直接下載使用。附錄中詳述了如何去編譯.so文件。
將下載好的.so文件放置于3.3.1新建的工程目錄libs\armeabi文件夾下。

我們現(xiàn)在就可以調(diào)用patch方法來(lái)合成新apk了。在主程序MainAcitivity類中加入以下代碼,該代碼就是調(diào)用我們所需的so庫(kù)文件。

這里得注意,我們的so文件前l(fā)ib是系統(tǒng)生成加上去的,所以在調(diào)用中我們只需將名字去掉lib的名字作為參數(shù)。
無(wú)論在下載還是合成刪除中,我們都必須獲取手機(jī)SD卡的讀寫權(quán)限,我們?cè)赨pdateDemo工程中AndroidManifest.xml加入以下代碼。

我們?cè)赨pdateDemo工程中加上添加一個(gè)更新按鈕,實(shí)現(xiàn)點(diǎn)擊按鈕能夠彈出下載選框,點(diǎn)擊下載就可以下載服務(wù)器上的patch包了。我們?cè)O(shè)定下載的目錄就是SD卡的跟目錄。運(yùn)行該程序,界面如圖。

我們點(diǎn)擊更新按鈕,如下。

在合成過(guò)程中,我們需要舊安裝包。在Android中非系統(tǒng)程序默認(rèn)安裝在data/app文件夾下,在非root情況下,我們可以對(duì)其本身安裝包進(jìn)行讀操作,這樣我們就可以將它復(fù)制到SD根目錄下(和之前下載的patch文件同目錄)。
在下載完成后,下載函數(shù)返回DOWN_OVER,線程接到這個(gè)信號(hào)后,調(diào)用PatchThread()函數(shù)。

我們?cè)赑atchThread()中調(diào)用復(fù)制舊安裝包backupApplication(String?packageName,?String?dest)方法。該方法第一個(gè)參數(shù)為安裝包的ID號(hào),如本例中的com.tutor.update,dest為復(fù)制目標(biāo)路徑。該方法中,主要函數(shù)如下。

該函數(shù)能夠找到data/app下相應(yīng)的安裝包。
測(cè)試中我們下載完patch文件后,立刻復(fù)制舊安裝包。

我們用360助手查看SD中文件。

接下來(lái)就可以調(diào)用本地方法合成新apk了。
同樣在PatchThread()函數(shù)中,當(dāng)復(fù)制成功后,我們就可以調(diào)用如下方法了。

參數(shù)都是舊、新和patch文件的路徑。我們可以用360助手查看,新的apk已經(jīng)合成,我們可以在程序中設(shè)定它的名字。這樣,我們的新apk合成成功。

合成新apk后,我們無(wú)法預(yù)知它的正確性,在下載或在合成過(guò)程中,文件都有可能出錯(cuò),所以緊接著我們需要對(duì)它進(jìn)行MD5校驗(yàn)。
用MD5校驗(yàn)工具對(duì)服務(wù)器上的新apk進(jìn)行校驗(yàn),得到校驗(yàn)碼。然后Android端合成新apk后對(duì)新apk也進(jìn)行校驗(yàn)。我們?cè)赨pdateDemo工程中再建一個(gè)包,編寫MD5類。

我們?cè)贛ainAcitivity類中的PatchThread()函數(shù)中構(gòu)造MD5對(duì)象,調(diào)用check方法即可。
用返回的校驗(yàn)值和服務(wù)器上的校驗(yàn)值對(duì)比,相同則進(jìn)行安裝,不同則提示校驗(yàn)失敗。

校驗(yàn)正確后自動(dòng)安裝即可。緊接著校驗(yàn)函數(shù),我們加入判斷,如果校驗(yàn)正確,則調(diào)用以下方法;如果錯(cuò)誤,我們就跳出提示信息。

安裝完成后打開軟件,已經(jīng)是V2版本了,我們?cè)隽扛鲁晒Α?/p>

最后我們只要把用戶下載的patch文件和舊apk刪除即可,用戶最終可以得到新apk,新apk用戶可以自行處理。
刪除時(shí)我們只要在安裝后或在校驗(yàn)錯(cuò)誤后調(diào)用delete()函數(shù)即可。

用助手查看SD目錄,只有新apk了。

如果校驗(yàn)不通過(guò),所有相關(guān)文件都會(huì)被刪除。這樣,我們就完成了我們的更新操作。
增量更新雖然不用將新apk的內(nèi)容全部下載,但如果版本相差過(guò)大,或者apk本身非常小,還是建議下載整包。以下做了個(gè)小測(cè)試。

我們能夠觀察到,當(dāng)apk不足1M時(shí),差分包大小同樣也有幾百K,所以沒(méi)必要去差分。當(dāng)版本相差過(guò)大,增加內(nèi)容非常多時(shí),我們也建議直接整包更新。差分時(shí)包越大耗時(shí)越長(zhǎng)。
測(cè)試中我們用到網(wǎng)上已有的so庫(kù),直接調(diào)用即可。我們也可以自己在客戶端生成so文件。
我們先下載bzip2-1.0.6.tar.gz。新建一個(gè)Android工程,將可能用到的下列文件復(fù)制到新建的Android工程的jni目錄下(沒(méi)有的新建一個(gè)目錄)。
下載地址:http://www.bzip.org/downloads.html。

在該jni目錄下新建文件,命名Android.mk,配置如下。

打開cmd命令行,轉(zhuǎn)到工程目錄的bin文件夾下,輸入以下命令。

系統(tǒng)會(huì)自動(dòng)生成一個(gè).h文件,我們把它拷貝到j(luò)ni目錄下。

我們?cè)趈ni目錄下新建com_example_jni_MainActivity.c,完成c代碼。

打開Cygwin,轉(zhuǎn)到工程目錄,使用ndk命令編譯成so庫(kù)即可。

我們可以看到libBSdiff.so已經(jīng)編譯成功,在lib/armeabi目錄下。

這樣,我們就可以使用該so文件去合成新apk了。