我们原来在应用市场上看到有些应用在升级的时候,一个几十兆的apk,只需要下载一个几兆的增量包便可以完成升级。
主要应用了开源项目bsdiff进行制作。
1、 在服务器上生成一个patch。
2、 下载patch到手机中。
3、 通过补丁获取一个已安装应用的新的安装apk。
4、 安装应用的新版本并删掉旧的版本和patch。
本片文章主要讲如何制作差分包
bsdiff地址 :http://www.daemonology.net/bsdiff/
bsdiff github地址:https://github.com/mendsley/bsdiff
·
1、下载上面的项目源码, 把.c和.cpp还有.h导入到vs中,并解决相应的错误
在vs命令行配置如下 -D _CRT_SECURE_NO_WARNINGS -D _CRT_NONSTDC_NO_DEPRECATE
2 我们主要应用bsdiff.cpp 这个文件中的main方法进行拆分
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);
/* Allocate newsize+1 bytes instead of newsize bytes to ensure
that we never try to malloc(0) and get a NULL pointer */
//org:
//if(((fd=open(argv[2],O_RDONLY,0))<0) ||
// ((newsize=lseek(fd,0,SEEK_END))==-1) ||
// ((_new=malloc(newsize+1))==NULL) ||
// (lseek(fd,0,SEEK_SET)!=0) ||
// (read(fd,_new,newsize)!=newsize) ||
// (close(fd)==-1)) err(1,"%s",argv[2]);
//new:
//Read in chunks, don't rely on read always returns full data!
if(((fd=open(argv[2],O_RDONLY|O_BINARY|O_NOINHERIT,0))<0) ||
((newsize=lseek(fd,0,SEEK_END))==-1) ||
((_new=(u_char*)malloc(newsize+1))==NULL) ||
(lseek(fd,0,SEEK_SET)!=0))
err(1,"%s",argv[2]);
r=newsize;
while (r>0 && (i=read(fd,_new+newsize-r,r))>0) r-=i;
if (r>0 || close(fd)==-1) err(1,"%s",argv[1]);
if(((db=(u_char*)malloc(newsize+1))==NULL) ||
((eb=(u_char*)malloc(newsize+1))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
/* Create the patch file */
//org:
//if ((pf = fopen(argv[3], "w")) == NULL)
//new:
//if((fd=open(argv[3],O_CREAT|O_TRUNC|O_WRONLY|O_BINARY|O_NOINHERIT,0666))<0)
if ((pf = fopen(argv[3], "wb")) == NULL)
err(1,"%s",argv[3]);
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
offtout(0, header + 8);
offtout(0, header + 16);
offtout(newsize, header + 24);
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", argv[3]);
/* Compute the differences, writing ctrl as we go */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan0;
for(scsc=scan+=len;scan0,oldsize,&pos);
for(;scscif((scsc+lastoffsetif(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffsetif((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+iif(old[lastpos+i]==_new[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==_new[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;iif(_new[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(_new[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;ifor(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=_new[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((scan-lenb)-(lastscan+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((pos-lenb)-(lastpos+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed ctrl data */
if ((len = ftell(pf)) == -1)
err(1, "ftello");
offtout(len-32, header + 8);
/* Write compressed diff data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, db, dblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed diff data */
if ((newsize = ftell(pf)) == -1)
err(1, "ftello");
offtout(newsize - len, header + 16);
/* Write compressed extra data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, eb, eblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Seek to the beginning, write the header, and close the file */
if (fseek(pf, 0, SEEK_SET))
err(1, "fseeko");
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", argv[3]);
if (fclose(pf))
err(1, "fclose");
/* Free the memory we used */
free(db);
free(eb);
free(I);
free(old);
free(_new);
return 0;
}
如上代码可知需要必须为argc=4
argv[0] = “bsdiff”;//无效参数
argv[1] = oldfile;//旧版本地址
argv[2] = newfile;//新版本地址
argv[3] = patchfile;//差分包的位置
由此可知我们jni需要传递的参数有oldfile,newfile,patchfile三个参数
我们新建一个javaweb项目,并在src目录下创建一个java 类如下:
Bsdiff.java
/**
* 制作差分包
* @param oldifle 旧路径
* @param patchfile 差分包路径
*
*/
public native static void bsdiff(String oldifle,String pacrhfile,String newfile);
进入对应的目录执行命令:javah com.saber.update.BsDiff ,并且刷新工程获取到.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_saber_update_BsDiff */
#ifndef _Included_com_saber_update_BsDiff
#define _Included_com_saber_update_BsDiff
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_saber_update_BsDiff
* Method: bsdiff
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_saber_update_BsDiff_bsdiff
(JNIEnv *, jclass, jstring, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
并且把文件考入到vs中,并在bsdiff.cpp中引入com_saber_update_BsDiff.h,jni.h,jni_md.h
并在bsdiff.cpp中写下调用jni方法
//JNI 调用
JNIEXPORT void JNICALL Java_com_saber_update_BsDiff_bsdiff
(JNIEnv *env, jclass jcls, jstring oldifle_jstr, jstring pacrhfile_jstr, jstring newfile_jstr){
int argc = 4;
char* oldfile = (char*)env->GetStringUTFChars(oldifle_jstr, NULL);
char* newfile = (char*)env->GetStringUTFChars(newfile_jstr, NULL);
char* patchfile = (char*)env->GetStringUTFChars(pacrhfile_jstr, NULL);
char *argv[4];
argv[0] = "bsdiff";
argv[1] = oldfile;
argv[2] = newfile;
argv[3] = patchfile;
bsdiff_main(argc,argv);
//回收
env->ReleaseStringUTFChars(oldifle_jstr, oldfile);
env->ReleaseStringUTFChars(newfile_jstr, newfile);
env->ReleaseStringUTFChars(pacrhfile_jstr, patchfile);
}
生成.dll动态库放入web 工程中,并在BsDiff.java中加入如下代码
static {
System.loadLibrary("SaberBsdiff");
}
建立一个java文件进行测试
“`
public class TestBsDiff {
private static String newpath="E:/apk/SaBerBsDiff_new.apk";
private static String oldpath="E:/apk/SaBerBsDiff_old.apk";
private static String path="E:/apk/apk.patch";
public static void main(String args[])
{
BsDiff.bsdiff(oldpath, path, newpath);
}
}
结果如下:
群号:454430053,欢迎入群