增量更新(制作差分包笔记)

来源:互联网 发布:剑网三咩太捏脸数据 编辑:程序博客网 时间:2024/05/22 09:41

一、概述

我们原来在应用市场上看到有些应用在升级的时候,一个几十兆的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(scan<newsize) {        oldscore=0;        for(scsc=scan+=len;scan<newsize;scan++) {            len=search(I,old,oldsize,_new+scan,newsize-scan,                    0,oldsize,&pos);            for(;scsc<scan+len;scsc++)            if((scsc+lastoffset<oldsize) &&                (old[scsc+lastoffset] == _new[scsc]))                oldscore++;            if(((len==oldscore) && (len!=0)) ||                 (len>oldscore+8)) break;            if((scan+lastoffset<oldsize) &&                (old[scan+lastoffset] == _new[scan]))                oldscore--;        };        if((len!=oldscore) || (scan==newsize)) {            s=0;Sf=0;lenf=0;            for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {                if(old[lastpos+i]==_new[lastscan+i]) s++;                i++;                if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };            };            lenb=0;            if(scan<newsize) {                s=0;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;i<overlap;i++) {                    if(_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;i<lenf;i++)                db[dblen+i]=_new[lastscan+i]-old[lastpos+i];            for(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 <jni.h>/* Header for class com_saber_update_BsDiff */#ifndef _Included_com_saber_update_BsDiff#define _Included_com_saber_update_BsDiff#ifdef __cplusplusextern "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,欢迎入群

1 0