上一節(jié)我們學(xué)習(xí)了NDK來(lái)處理文件的拆分和合并操作虱黄,那時(shí)候我們純手工來(lái)敲C語(yǔ)言的代碼,今天我們來(lái)用C語(yǔ)言代碼搞搞NDK的增量更新差分包吮成,
那什么是增量更新呢橱乱?再說(shuō)這個(gè)之前我們有必要說(shuō)一下熱修復(fù),什么又是熱修復(fù)呢粱甫?
對(duì)于熱修復(fù)就是打補(bǔ)丁泳叠,當(dāng)有重大的bug的時(shí)候需要使用熱修復(fù)的功能,這樣避免了重新打包并發(fā)布所帶來(lái)的成本高茶宵、效率低危纫,熱修復(fù)會(huì)使用到PathClassLoader和DexClassLoader類(lèi)。
增量更新顧名思義就是用來(lái)apk的版本更新乌庶,增量則通過(guò)生成兩個(gè)apk的增量文件patch种蝶,然后將舊版本的apk進(jìn)行合并達(dá)到更新的目的。
做增量更新需要注意:
- 新版本和舊版本的apk簽名要一致
- 新版本的大小要增加
- 最好要生成幾個(gè)版本的增量文件瞒大,每個(gè)版本去下載對(duì)應(yīng)的文件去做增量更新
正文
我們從兩方面來(lái)進(jìn)行講解:根據(jù)舊版本和新版本的apk生成增量文件螃征、根據(jù)增量文件客戶(hù)端做相應(yīng)的增量更新
生成增量更新
生成增量更新的操作都是放到后臺(tái)來(lái)進(jìn)行,首先我們先去配置好Tomcat和NDK環(huán)境
接下來(lái)要生成增量文件就需要使用第三方的bsdiff庫(kù)
http://www.daemonology.net/bsdiff/
在這里面不僅有差分文件還有合并的文件透敌,因?yàn)閎sdiff和bspatch都使用到了bzip2,所以我們還需要去下載bzip2庫(kù)
http://www.bzip.org/
這樣我們就可以正式開(kāi)發(fā)服務(wù)端生成增量更新的功能了会傲。
-
導(dǎo)入bsdiff.c和bzip2里的文件
在編譯的時(shí)候會(huì)遇到一些坑锅棕,這里列舉一下:
- 會(huì)提示_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE沒(méi)有使用,這里因?yàn)樯婕拔募容^多淌山,我們?cè)诿钚兄羞M(jìn)行添加
- 不能將參數(shù) 1 從 CHAR [1024] 轉(zhuǎn)換為 LPWSTR裸燎,解決:在項(xiàng)目屬性->常規(guī)中,把Uicode改成多字符段
- 編譯的時(shí)候會(huì)報(bào)字段過(guò)時(shí)泼疑,解決關(guān)閉dsl檢查
-
在bsdiff.cpp里面有main方法德绿,那怎么來(lái)加入到NDK里面來(lái)呢?這時(shí)會(huì)想到將main改成普通方法退渗,使用native方法調(diào)用即可
JNIEXPORT void JNICALL Java_com_lypop_BsDiff_diff(JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr, jstring patchfile_jstr){ int argc = 4; char* oldfile = (char*)(env)->GetStringUTFChars( oldfile_jstr, NULL); char* newfile = (char*)(env)->GetStringUTFChars(newfile_jstr, NULL); char* patchfile = (char*)(env)->GetStringUTFChars(patchfile_jstr, NULL); char *argv[4]; argv[0] = "bspatch"; argv[1] = oldfile; argv[2] = newfile; argv[3] = patchfile; bsdiff_main(argc,argv); //釋放資源 env->ReleaseStringUTFChars(oldfile_jstr, oldfile); env->ReleaseStringUTFChars(newfile_jstr, newfile); env->ReleaseStringUTFChars(patchfile_jstr, patchfile); };
在寫(xiě)這個(gè)方法之前需要先看一下main方法
int bsdiff_main(int argc,char *argv[])
{
if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
......
}
由源碼可以看出第一個(gè)參數(shù)可有可無(wú)移稳,重點(diǎn)是最后的那三個(gè)參數(shù),分別代表的是oldfile会油、newfile个粱、patchfile,然后根據(jù)要傳入的參數(shù)寫(xiě)相應(yīng)的native方法并生成.h文件,最后生成相應(yīng)的dll動(dòng)態(tài)庫(kù)讓后臺(tái)進(jìn)行調(diào)用生成相應(yīng)的增量patch文件
進(jìn)行增量更新
在Android這邊我們開(kāi)啟了一個(gè)異步任務(wù)用來(lái)請(qǐng)求服務(wù)器的patch文件翻翩,將patch文件合并到apk中進(jìn)行增量更新
class ApkUpdateTask extends AsyncTask<Void, Void, Boolean>{
@Override
protected Boolean doInBackground(Void... params) {
try {
//1.下載差分包
File patchFile = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD);
//獲取當(dāng)前應(yīng)用的apk文件
String oldfile = ApkUtils.getSourceApkPath(MainActivity.this, getPackageName());
//2.合并得到最新版本的APK文件
String newfile = Constants.NEW_APK_PATH;
String patchfile = patchFile.getAbsolutePath();
BsPatch.patch(oldfile, newfile, patchfile);
合并的native方法
/**
* 合并
* @param oldfile
* @param newfile
* @param patchfile
*/
public native static void patch(String oldfile,String newfile,String patchfile);
static{
System.loadLibrary("bspatch");
}