扯淡
最近閑來(lái)無(wú)事搀继,學(xué)習(xí)了一下增量更新窘面。
增量更新的概念就不扯了,有興趣的看一下鴻洋大神的文章Android 增量更新完全解析 是增量不是熱修復(fù)叽躯。
測(cè)試設(shè)備(Android 5.0系統(tǒng))
Talk is cheap财边!廢話不多說(shuō),接下來(lái)開始踩坑之路点骑。
準(zhǔn)備工具
-
bsdiff/bzip 密碼: qdrb
- 下載 bzip 后解壓把里面的 .c 和 .h 文件復(fù)制到項(xiàng)目 app/src/main/jni/ 下面
- bsdiff 文件中的 bsdiff.c 和 bspatch.c 文件復(fù)制到項(xiàng)目 app/src/main/jni/ 下面
Android Studio 配置 NDK 環(huán)境 Android NDK 開發(fā)從 0 到 1
生成增量文件
- 寫一個(gè)工具類 DiffUtil.java
static {
System.loadLibrary("bsdiff");
}
/**
* native 方法 比較路徑為 oldPath 的 apk 與 newPath 的 apk 之間差異酣难,并生成 patch 包,存儲(chǔ)于 patchPath
*/
public static native int genDiff(String oldApkPath, String newApkPath, String patchPath);
- 生成頭文件
在 Terminal 中進(jìn)入到項(xiàng)目 ..app\src\main\java> 下輸入 javah -d ../jni 包名.方法名
如: javah -d ../jni sj.updateplus_utils.DiffUtil
- 復(fù)制頭文件中代碼到 bsdiff.c 中黑滴,之后再添加如下代碼
JNIEXPORT jint JNICALL Java_sj_updateplus_utils_DiffUtil_genDiff
(JNIEnv *env, jclass cls, jstring old, jstring new, jstring patch) {
int argc = 4;
char * argv[argc];
argv[0] = "bsdiff";
argv[1] = (char*) ((*env)->GetStringUTFChars(env, old, 0));
argv[2] = (char*) ((*env)->GetStringUTFChars(env, new, 0));
argv[3] = (char*) ((*env)->GetStringUTFChars(env, patch, 0));
printf("old apk = %s \n", argv[1]);
printf("new apk = %s \n", argv[2]);
printf("patch = %s \n", argv[3]);
int ret = diffMain(argc, argv);
printf("genDiff result = %d ", ret);
(*env)->ReleaseStringUTFChars(env, old, argv[1]);
(*env)->ReleaseStringUTFChars(env, new, argv[2]);
(*env)->ReleaseStringUTFChars(env, patch, argv[3]);
return ret;
}
- bsdiff.c 中還需要修改的地方
//原代碼:
int main(int argc, char *argv[]) {
...
}
//修改為:
int diffMain(int argc, char *argv[]) {
...
}
//原代碼
#include <bzlib.h>
//修改為,可自定義
#include "bzip2/bzlib.h"
最后再進(jìn)行編譯運(yùn)行憨募,這期間可能遇到各種報(bào)錯(cuò),哈哈袁辈,沒(méi)關(guān)系菜谣,反正我也不知道怎么解決。(???開玩笑,后面有踩坑經(jīng)歷)
增量文件和 oldApk 的合并
這個(gè)和增量文件的生成類似
- 寫一個(gè)工具類 PatchUtil.java
static {
System.loadLibrary("bsdiff");
}
/**
* native 方法 合并舊 apk 和補(bǔ)丁 patch尾膊,生成新的 apk
* @param oldApkPath 舊apk文件路徑
* @param newApkPath 合并生成的新 apk 保存路徑
* @param patchPath 增量文件路徑
* @return 合并結(jié)果: 0-成功 -其他失敗
*/
public static native int mypatch(String oldApkPath, String newApkPath, String patchPath);`
- 生成頭文件
同增量文件的生成里面一樣
在 Terminal 中進(jìn)入到項(xiàng)目 ..app\src\main\java> 下輸入 javah -d ../jni 包名.方法名
如:javah -d ../jni sj.updateplus_utils.PatchUtil
- 復(fù)制頭文件中代碼到 bspatch.c 里添加以下代碼
JNIEXPORT jint JNICALL Java_sj_updateplus_utils_PatchUtil_mypatch
(JNIEnv *env, jclass cls,
jstring old, jstring new, jstring patch) {
int argc = 4;
char *argv[argc];
argv[0] = "bspatch";
argv[1] = (char *) ((*env)->GetStringUTFChars(env, old, 0));
argv[2] = (char *) ((*env)->GetStringUTFChars(env, new, 0));
argv[3] = (char *) ((*env)->GetStringUTFChars(env, patch, 0));
int ret = patchMain(argc, argv);
(*env)->ReleaseStringUTFChars(env, old, argv[1]);
(*env)->ReleaseStringUTFChars(env, new, argv[2]);
(*env)->ReleaseStringUTFChars(env, patch, argv[3]);
return ret;
}
- bspatch.c 中還需要修改的地方
//原代碼
int main(int argc, char *argv[]) {
...
}
//修改為,可自定義
int patchMain(int argc, char *argv[]) {
...
}
//原代碼:
#include <bzlib.h>
//修改為:
#include "bzip2/bzlib.h"
踩過(guò)的坑
- 編譯缺少 xxx 文件
CMakeLists.txt 文件中添加以下代碼
add_library( # Sets the name of the library.
bsdiff
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/jni/bzip2/blocksort.c
src/main/jni/bzip2/bzip2.c
src/main/jni/bzip2/bzip2recover.c
src/main/jni/bzip2/bzlib.c
src/main/jni/bzip2/compress.c
src/main/jni/bzip2/crctable.c
src/main/jni/bzip2/decompress.c
src/main/jni/bzip2/dlltest.c
src/main/jni/bzip2/huffman.c
src/main/jni/bzip2/mk251.c
src/main/jni/bzip2/randtable.c
src/main/jni/bzip2/spewG.c
src/main/jni/bzip2/unzcrash.c
src/main/jni/bsdiff.c
src/main/jni/bspatch.c )
CMakeLists.txt 中這兩處地方要一致媳危,可自定義
add_library( # Sets the name of the library.
bsdiff
... )
target_link_libraries( # Specifies the target library.
bsdiff
...)
- 可能需要添加
gradle.properties 文件
android.useDeprecatedNdk=true
進(jìn)行 MD5 驗(yàn)證
這個(gè)步驟是為了檢驗(yàn)合并生成的 apk 文件和我們要升級(jí)更新的 apk 文件是否一樣
在 apk 文件目錄下打開 cmd
輸入命令行
//***.apk 為需要驗(yàn)證的 apk 文件名
certutil -hashfile ***.apk MD5
寫在最后
到這邊增量更新操作基本就完成了。還有一些考慮不足之處冈敛。
當(dāng)然這只是進(jìn)行了增量文件的生成和新 apk 的合并待笑,而且也只是在本地進(jìn)行。其實(shí)呢莺债,增量文件的生成最好在服務(wù)端進(jìn)行滋觉,而且需要生成多個(gè)版本與最新版本的增量文件,才能保證各個(gè)版本的用戶可以正常更新;更新完后還要安裝等齐邦。
筆者這里是對(duì)其他 apk 的增量更新椎侠,如果是對(duì)本身 apk 的更新的話,還需要提取自身 apk 之類的措拇,其他步驟可參照以上所寫我纪。
第一次寫文章,還望各位指點(diǎn)