实现思路
实现增量更新的步骤:
1. old.apk和new.apk生成差异包patch
2. old.apk和patch合成更新包merge.apk
3. 安装merge.apk
生成差异包patch
1.进入bsdiff官网,下载bsdiff-4.3.tar.gz
2.解压下载好的bsdiff-4.3.tar.gz,然后编辑Makefile如下:
CFLAGS += -O3 -lbz2
PREFIX ?= /usr/local
INSTALL_PROGRAM ?= ${INSTALL} -c -s -m 555
INSTALL_MAN ?= ${INSTALL} -c -m 444
all: bsdiff bspatch
bsdiff: bsdiff.c
bspatch: bspatch.c
install:
${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
.ifndef WITHOUT_MAN
${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
.endif
主要是在.ifndef WITHOUT_MAN和.endif前面加一个tab
3.打开bspatch.c添加:
#include <sys/types.h>
4.在bsdiff-4.3目录下执行下面命令
make
5.生成bsdiff和bspatch
6.进行简单测试
6.1 old.apk new.apk 生成patch
./bsdiff old.apk new.apk patch
6.2 old.apk + patch生成merge.apk
./bspatch old.apk merge.apk patch
6.3 判断new.apk 和 merge.apk是否一致
MD5 new.apk
28c8131df39f1f0a6402fc26298c9a72
MD5 merge.apk
28c8131df39f1f0a6402fc26298c9a72
发现md5一致,说明合成成功。
old.apk和patch合成更新包
配置ndk
1.新建ndk项目
2.拷贝bspatch.c到cpp目录下
3.发现bspatch.c中需要引入bzlib.h,从bzip2下载bzip2-1.0.6.tar.gz
4.解压bzip2-1.0.6.tar.gz,然后保留里面的.c,.h文件,其余删除即可
5.将bzip2拷贝到cpp目录下
6.修改CMakeLists.txt如下
cmake_minimum_required(VERSION 3.4.1)
file(GLOB cpp_path src/main/cpp/bzip2/*.c src/main/cpp/*.c src/main/cpp/*.cpp)
add_library(
native-lib
SHARED
${cpp_path}
)
find_library(
log-lib
log )
target_link_libraries(
native-lib
${log-lib} )
7.在cpp目录下新建bspatch.h文件,添加
int bspatchmain(int argc,char * argv[]);
然后bspatch.c和native-lib.cpp分别引入bspatch.h头文件
修改bspatch.c中的main方法为bspatchmain方法
8.将bzip2下面的所有文件中的main方法添加一个前缀,例如:
bzip2recover.c中的main方法改为bzip2recovermain
至此,bspatch的环境已经搭建完成
编写合并安装代码
1.新建BsPatch.java文件
package com.study.bspatchtest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
/**
* Created by ygdx_lk on 17/11/30.
*/
public class BsPatch {
private static final String TAG = "BsPatch";
public static native int bsPatch(String oldPath, String newPath, String patchPath);
private static String getOldPath(Context context) {
context = context.getApplicationContext();
ApplicationInfo applicationInfo = context.getApplicationInfo();
String apkPath = applicationInfo.sourceDir;
return apkPath;
}
public static void testPath(Context context){
String newPath = Environment.getExternalStorageDirectory() + "/new.apk";
String patchPath = Environment.getExternalStorageDirectory() + "/patch";
mergePatch(context, newPath, patchPath);
}
public static void mergePatch(Context context, String newPath, String patchPath){
String oldPath = getOldPath(context);
if(!TextUtils.isEmpty(oldPath)){
int result = bsPatch(oldPath, newPath, patchPath);
if(result == 0){
Log.i(TAG, "mergePatch: ok");
installApk(context, newPath);
}else {
Log.i(TAG, "mergePatch: error");
}
}
}
private static void installApk(Context context, String newPath) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.fromFile(new File(newPath)),
"application/vnd.android.package-archive");
context.startActivity(i);
}
}
2.native-lib.cpp
#include <jni.h>
#include <string>
extern "C"
#include "bspatch.h"
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_study_bspatchtest_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++ update";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_study_bspatchtest_BsPatch_bsPatch(JNIEnv *env, jclass type, jstring oldPath_,
jstring newPath_, jstring patchPath_) {
char *oldPath = (char *) env->GetStringUTFChars(oldPath_, 0);
char *newPath = (char *) env->GetStringUTFChars(newPath_, 0);
char *patchPath = (char *) env->GetStringUTFChars(patchPath_, 0);
int argc = 4;
char * argv[argc];
argv[0] = "bsPatch";
argv[1] = oldPath;
argv[2] = newPath;
argv[3] = patchPath;
int ret = bspatchmain(argc, argv);
env->ReleaseStringUTFChars(oldPath_, oldPath);
env->ReleaseStringUTFChars(newPath_, newPath);
env->ReleaseStringUTFChars(patchPath_, patchPath);
return ret;
}
3.在MainActivity方法中添加点击事件
BsPatch.testPath(v.getContext());
4.生成old.apk和new.apk及patch
5.安装old.apk,拷贝path到sdk目录
6.点击运行testPath方法
7.安装成功。(失败的话,一定要记得文件的读写权限)