普通更新与增量更新的区别:
普通更新:客户端在冷启动的时候会将一个版本号和渠道号发送到服务器,如果是最新的,则服务器返回false,如果不是则返回false
增量更新:发送版本号到服务器,服务器收到版本号如果不是最新,则服务会根据版本号找到旧的apk地址跟新apk的地址进行合并,生成一个差分包(apk.aptch),生成完成之后再进行下载,下载完之后,客户端本地进行合并生成新的apk包
当前程序的apk被删除:系统在安装apk的时候,会将apk先拷贝到/data/app目录下(没有删除旧的程序就安装新的程序,会在data/app下的名字后面加数字,root后可删除)
区别:newApkSize-oldApkSize > 差分包的大小,可以节约服务器成本
差分原理(哈夫曼算法):将newapk和oldapk的进制编码进行比较,如果相同则只保留索引到apk.aptch,不同则保存压缩的内容和索引,如图:
插件化,热更新,差分包的使用场景;
热更新:有两个不同的模块,比如:不加载classA,重新加载classB(轻量级)
插件化(pluginManager):根据模块的不同复用插件,可以和热更新重用(比较轻量级)
差分包(增量更新):可以只布属差分class或差分插件
生成差分包(需下载bsdiff-4.3):
1.新建vs工程,在工程目录下新建两个文件夹(include,src),将basdiff下的。h文件拷贝到include文件夹下,将.c和.cpp拷贝到src文件夹下,将文件夹引入到工程
2.生成.exe文件
3.cmd运行,参数:旧apk,新apk,apk.patch
windows服务器自动执行:
1.声明native方法
2.将.exe编辑成dll动态库
2.1 在bsdiff.cpp导入native的.h文件,导入jni.h和jni_md.h文件(java包里的文件是windows平台的,ndk包下的是linux平台的)
2.2 传入1个名字和3个参数,跟.exe传入包名一样,转为字符串数组
2.3 调用bsdiff_main()函数(该函数本身是main函数,如果是生成.exe文件则可以保留函数名,如果生成动态库,则不能使用main做为函数名,所以改成了bsdiff_main),传入数组大小和数组
JNIEXPORT void JNICALL Java_Diff_bsdiff
(JNIEnv *env, jclass clz, jstring old_apk, jstring new_apk, jstring patch) {
int size = 4;
char *path[4];
char *old_path = (char*)env->GetStringUTFChars(old_apk,NULL);
char *new_path = (char*)env->GetStringUTFChars(new_apk, NULL);
char *patch_path = (char*)env->GetStringUTFChars(patch, NULL);
path[0] = "bsdiff";
path[1] = old_path;
path[2] = new_path;
path[3] = patch_path;
bsdiff_main(size, path);
env->ReleaseStringUTFChars(old_apk, old_path);
env->ReleaseStringUTFChars(new_apk, new_path);
env->ReleaseStringUTFChars(patch, patch_path);
free(path);
}
linux服务器自动执行:
1.将diff中的.c和.h拷贝到同一文件夹下,修改可执行权限
2.使用gcc命令(需将main函数改名)
3.执行生成的文件,执行方法和windows .exe执行一样
引入头文件:右键工程-》属性-》C/C++-》附加包含目录-》编辑-》新建-》选择目录(win32平台或x64平台)
引入第三方包可能出现的问题,出现宏定义错误,可以在右键工程-》属性-》C/C++-》命令行输入-D 错误宏
sdl安全检查错误:关闭安全检查 右键工程-》属性-》C/C++-》常规下的安全检查 改为否
android 合并差分包:(不能有main方法,加固后的apk新包与合新旧包并后的apk包的md5值是一致的,所以加固不影响合并)(可以使用 ApplicationInfo context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;获得当前的安装包)
1.导入bspatch下的.c,.cpp,.h文件(可以用file(GLOB name 目录/*.c)导入文件夹下所有的.c文件,能过${name}导入)(glob:全局)
2.编写native方法,与差分方法一致
3.在bspatch文件里导入.h头文件,编写native方法
3.1 将路径转为char*
3.2 定义4个长度的字符串数组
3.3 像差分包一样,分别将名字,旧包,新包,生成路径传入
3.4 调用 bspatch_main函数(该函数名字和差分时的函数名一样),传入数组长度,和字符串数组
4.生成完成后安装
/**
* 获取已安装Apk文件的源Apk文件
* 如:/data/app/my.apk
*
* @param context
* @param packageName
* @return
*/
public static String getSourceApkPath(Context context, String packageName) {
if (TextUtils.isEmpty(packageName))
return null;
try {
ApplicationInfo appInfo = context.getPackageManager()
.getApplicationInfo(packageName, 0);
return appInfo.sourceDir;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
JNIEXPORT void JNICALL Java_jni03_test_com_mybspatch_Patch_bspatch(
JNIEnv *env,
jobject jobj,jstring oldApk,jstring newApk,jstring patch) {
LOGD("%s","jni patch begin");
int size = 4;
char *apk[4];
char *c_old = (char *) (*env)->GetStringUTFChars(env,oldApk, NULL);
char *c_new = (char *) (*env)->GetStringUTFChars(env,newApk, NULL);
char *c_patch = (char *) (*env)->GetStringUTFChars(env,patch, NULL);
apk[0] = "patch";
apk[1] = c_old;
apk[2] = c_new;
apk[3] = c_patch;
bspatch_main(size,apk);
(*env)->ReleaseStringUTFChars(env,oldApk,c_old);
(*env)->ReleaseStringUTFChars(env,newApk,c_new);
(*env)->ReleaseStringUTFChars(env,patch,c_patch);
free(apk);
LOGD("%s","jni patch end");
}