热更新
虽然有插件开发,但热更新少不了。
当我们需要更新插件的时候使用的是插件开发,当我们需要更新宿主程序就需要使用热更新
热更新使用框架bsdiff和bzip2
我们需要在服务端使用新版apk和旧版apk生成差分包,由于服务端在windows下,所以生成动态文件(dll)
通过寻找bsdiff的入口函数在bsdiff.cpp中在,因为截止到现在我主要了解了一点c,所以把bsdiff.cpp改成了bsdiff.c
int main(int argc,char *argv[])
{
int fd;
u_char *old,*_new;
off_t oldsize,newsize;
off_t *I,*V;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t dblen,eblen;
u_char *db,*eb;
u_char buf[8];
u_char header[32];
FILE * pf;
BZFILE * pfbz2;
int bz2err;
if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
/* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
that we never try to malloc(0) and get a NULL pointer */
//org:
//if(((fd=open(argv[1],O_RDONLY,0))<0) ||
// ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
// ((old=malloc(oldsize+1))==NULL) ||
// (lseek(fd,0,SEEK_SET)!=0) ||
// (read(fd,old,oldsize)!=oldsize) ||
// (close(fd)==-1)) err(1,"%s",argv[1]);
//new:
//Read in chunks, don't rely on read always returns full data!
if(((fd=open(argv[1],O_RDONLY|O_BINARY|O_NOINHERIT,0))<0) ||
((oldsize=lseek(fd,0,SEEK_END))==-1) ||
((old=(u_char*)malloc(oldsize+1))==NULL) ||
(lseek(fd,0,SEEK_SET)!=0))
err(1,"%s",argv[1]);
int r=oldsize;
while (r>0 && (i=read(fd,old+oldsize-r,r))>0) r-=i;
if (r>0 || close(fd)==-1) err(1,"%s",argv[1]);
if(((I=(off_t*)malloc((oldsize+1)*sizeof(off_t)))==NULL) ||
((V=(off_t*)malloc((oldsize+1)*sizeof(off_t)))==NULL)) err(1,NULL);
qsufsort(I,V,old,oldsize);
free(V);
这里贴上前几行代码,只要调用这个函数就能得到差分包(.patch),
而从if(argc!=4) errx(1,”usage: %s oldfile newfile patchfile\n”,argv[0]);这行代码可以知道,argc这个参数必须等于4才可以正常执行,argv数组的第一个参数没有要求,从后面代码得到第二个参数为旧版apk的路径,第三个参数为新版apk的路径,第四个参数为生成的差分包的位置。
当我们差分的时候只要调用这个main函数并传递相应参数就可以得到差分包了,所以我们修改入口函数的名字,目的是当我们调用的时候采取执行。我们只需要在bsdiff这个文件下实现我们声明的native方法并调用入口函数。然后生成动态库文件放入服务端项目下用来辅助生成差分包
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_dongnaoedu_bsdiff_BsDiff */
#ifndef _Included_com_dongnaoedu_bsdiff_BsDiff
#define _Included_com_dongnaoedu_bsdiff_BsDiff
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_dongnaoedu_bsdiff_BsDiff
* Method: diff
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_dongnaoedu_bsdiff_BsDiff_diff
(JNIEnv *, jclass, jstring, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
public class BsDiff {
/**
* 差分
*
* @param oldfile
* @param newfile
* @param patchfile
*/
public native static void diff(String oldfile, String newfile, String patchfile);
static{
System.loadLibrary("bsdiff");
}
}
这里只贴出了部分代码。这样我们就可以得到差分包,在服务器就可以获取这个差分包,然后我们需要从客户端下载这个差分包并与旧版apk进行合并生成新版apk,这样就可以省去部分流量。
合并的入口函数在bspatch文件中,下面为bspatch文件中native方法的实现,bspatch_main就是改了名字之后的入口函数
//合并
JNIEXPORT void JNICALL Java_com_dongnaoedu_appupdate_utils_BsPatch_patch
(JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr, jstring patchfile_jstr){
int argc = 4;
char* oldfile = (char*)(*env)->GetStringUTFChars(env,oldfile_jstr, NULL);
char* newfile = (char*)(*env)->GetStringUTFChars(env,newfile_jstr, NULL);
char* patchfile = (char*)(*env)->GetStringUTFChars(env,patchfile_jstr, NULL);
//参数(第一个参数无效)
char *argv[4];
argv[0] = "bspatch";
argv[1] = oldfile;
argv[2] = newfile;
argv[3] = patchfile;
bspatch_main(argc,argv);
(*env)->ReleaseStringUTFChars(env,oldfile_jstr, oldfile);
(*env)->ReleaseStringUTFChars(env,newfile_jstr, newfile);
(*env)->ReleaseStringUTFChars(env,patchfile_jstr, patchfile);
}
和差分类似,数组的第三个参数为生成的新版本apk路径
查分和合并使用bsdiff主要依赖于bzip2这个框架
然后我们就生成动态库文件(.so),因为安卓运行在linux平台所以生成的动态库文件和前面不同。自此我们生成了两个动态库文件,分别运行在服务端进行差分和运行在客户端进行合并。
System.getProperty(“os.name”)能输出系统名字,能用于判断运行的操作系统
System.load(“路径”)加载指定文件下的库文件
差分算法:比较新旧文件,标识出翔通部分,压缩不同部分和额外部分(主要以来bzip2)生成patch文件
合并算法:生成的patch文件和旧文件合成新文件
当然这些算法内部实现非常复杂
还没有评论,来说两句吧...