前言
在我们平常开发app时候,版本1.0迭代到2.0的时候目前还有不少开发得应用是全量更新,也就是重新下载整个2.0的安装包,重新安装到手机,其实是有些浪费资源,用户体验也不是很好,虽然现在是无限流量,一个app老是出现让用户更新全量包,极其影响用户体验,而增量更新可以解决2.0-1.0的差分包的大小,用户只需要在old.apk上更新new.apk的差分包,合成新的apk即可,更新数据包会大大降低,相对上也提高了用户体验,获得手机root全新还可以不知不觉让app更新安装完成,这种体验相对较高,今天就来了解一下如果做到android-apk的增量更新技术。
增量更新流程
增量更新分三部分:1、安装手机当前应用old.apk
2、利用工具bsdiff 去生成 old.apk 和 new.apk 之间的差分包
3、从服务器下载生成的差分包到本地sd卡,和当前手机安装的old.apk进行合并安装即可
正文
实现增量更新,现在有各种合并差分包的开源库,比如:bsdiff、hdiff,我们只需要获得源码直接使用即可。
bsdiff下载地址:
http://www.daemonology.net/bsdiff/
bsdiff依赖bizp2(zip压缩库)
http://nchc.dl.sourcefore.net/project/gnuwin32/bzip2/1.0.5/bzip2-1.0.5-src.zip
翻墙下载,下载解压完是这样的:
最后我会提供提供一下window下的工具(bsdiff-v4.3-win-x64)
把下载好的bspatch.c文件 放置到cpp目录下,放入之后会有很多报错信息,首先将CMakeLists.txt的添加bsdiff
add_library添加
package com.note.zlgx;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.File;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.tv_version);
textView.setText(BuildConfig.VERSION_NAME);
Button button = findViewById(R.id.sample_text);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//1.下载new.apk
new AsyncTask<Void,Void,File>(){
@Override
protected File doInBackground(Void... voids) {
String old = getApplication().getApplicationInfo().sourceDir;
bspatch(old,"/sdcard/patch","/sdcard/bestChoice/new.apk");
return new File("sdcard/bestChoice/new.apk");
}
@Override
protected void onPostExecute(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
// 第二个参数,即第一步中配置的authorities
String packageName = getApplication().getPackageName();
Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.note.zlgx.fileProvider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
// 声明需要的临时权限
}
startActivity(intent);
}
}.execute();
//2.合并安装
}
});
}
/**
*
* @param oldapk 当前运行apk
* @param patch 差分包文件
* @param output 合并之后的新apk输入路径
*/
native void bspatch(String oldapk,String patch,String output);
}
bspatch 定义JNI方法,调用so库方法,进行合并patch喝old.apk查分包
JNI方法区代码
extern "C"
JNIEXPORT void JNICALL
Java_com_note_zlgx_MainActivity_bspatch(JNIEnv *env, jobject instance, jstring oldapk_,
jstring patch_, jstring output_) {
const char *oldapk = env->GetStringUTFChars(oldapk_, 0);
const char *patch = env->GetStringUTFChars(patch_, 0);
const char *output = env->GetStringUTFChars(output_, 0);
char * argv[4] = {"", const_cast<char *>(oldapk), const_cast<char *>(output),
const_cast<char*>(patch)};
main(4,argv);
// TODO
env->ReleaseStringUTFChars(oldapk_, oldapk);
env->ReleaseStringUTFChars(patch_, patch);
env->ReleaseStringUTFChars(output_, output);
}
demo地址:https://download.youkuaiyun.com/download/qq_23213991/10735923