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

一、概述

我们原来在应用市场上看到有些应用在升级的时候,一个几十兆的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 __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,欢迎入群

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值