增量更新(客户端笔记)

来源:互联网 发布:历史上真实的和珅 知乎 编辑:程序博客网 时间:2024/06/05 02:20

一、概述

在上一篇文章我们了解了如何在服务端生成差分包,这篇文章我们主要来讲解客户端如何使用差分包进行合并

二、差分包的合并

1、首先创建jni目录并导入bspatch.c,并分析所需参数

#if 0__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");#endif#include <stdlib.h>#include <stdio.h>#include <string.h>#include <err.h>#include <unistd.h>#include <fcntl.h>static off_t offtin(u_char *buf){    off_t y;    y=buf[7]&0x7F;    y=y*256;y+=buf[6];    y=y*256;y+=buf[5];    y=y*256;y+=buf[4];    y=y*256;y+=buf[3];    y=y*256;y+=buf[2];    y=y*256;y+=buf[1];    y=y*256;y+=buf[0];    if(buf[7]&0x80) y=-y;    return y;}int main(int argc,char * argv[]){    FILE * f, * cpf, * dpf, * epf;    BZFILE * cpfbz2, * dpfbz2, * epfbz2;    int cbz2err, dbz2err, ebz2err;    int fd;    ssize_t oldsize,newsize;    ssize_t bzctrllen,bzdatalen;    u_char header[32],buf[8];    u_char *old, *new;    off_t oldpos,newpos;    off_t ctrl[3];    off_t lenread;    off_t i;    if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);    /* Open patch file */    if ((f = fopen(argv[3], "r")) == NULL)        err(1, "fopen(%s)", argv[3]);    /*    File format:        0   8   "BSDIFF40"        8   8   X        16  8   Y        24  8   sizeof(newfile)        32  X   bzip2(control block)        32+X    Y   bzip2(diff block)        32+X+Y  ??? bzip2(extra block)    with control block a set of triples (x,y,z) meaning "add x bytes    from oldfile to x bytes from the diff block; copy y bytes from the    extra block; seek forwards in oldfile by z bytes".    */    /* Read header */    if (fread(header, 1, 32, f) < 32) {        if (feof(f))            errx(1, "Corrupt patch\n");        err(1, "fread(%s)", argv[3]);    }    /* Check for appropriate magic */    if (memcmp(header, "BSDIFF40", 8) != 0)        errx(1, "Corrupt patch\n");    /* Read lengths from header */    bzctrllen=offtin(header+8);    bzdatalen=offtin(header+16);    newsize=offtin(header+24);    if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))        errx(1,"Corrupt patch\n");    /* Close patch file and re-open it via libbzip2 at the right places */    if (fclose(f))        err(1, "fclose(%s)", argv[3]);    if ((cpf = fopen(argv[3], "r")) == NULL)        err(1, "fopen(%s)", argv[3]);    if (fseeko(cpf, 32, SEEK_SET))        err(1, "fseeko(%s, %lld)", argv[3],            (long long)32);    if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)        errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);    if ((dpf = fopen(argv[3], "r")) == NULL)        err(1, "fopen(%s)", argv[3]);    if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))        err(1, "fseeko(%s, %lld)", argv[3],            (long long)(32 + bzctrllen));    if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)        errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);    if ((epf = fopen(argv[3], "r")) == NULL)        err(1, "fopen(%s)", argv[3]);    if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))        err(1, "fseeko(%s, %lld)", argv[3],            (long long)(32 + bzctrllen + bzdatalen));    if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)        errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);    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]);    if((new=malloc(newsize+1))==NULL) err(1,NULL);    oldpos=0;newpos=0;    while(newpos<newsize) {        /* Read control data */        for(i=0;i<=2;i++) {            lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);            if ((lenread < 8) || ((cbz2err != BZ_OK) &&                (cbz2err != BZ_STREAM_END)))                errx(1, "Corrupt patch\n");            ctrl[i]=offtin(buf);        };        /* Sanity-check */        if(newpos+ctrl[0]>newsize)            errx(1,"Corrupt patch\n");        /* Read diff string */        lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);        if ((lenread < ctrl[0]) ||            ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))            errx(1, "Corrupt patch\n");        /* Add old data to diff string */        for(i=0;i<ctrl[0];i++)            if((oldpos+i>=0) && (oldpos+i<oldsize))                new[newpos+i]+=old[oldpos+i];        /* Adjust pointers */        newpos+=ctrl[0];        oldpos+=ctrl[0];        /* Sanity-check */        if(newpos+ctrl[1]>newsize)            errx(1,"Corrupt patch\n");        /* Read extra string */        lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);        if ((lenread < ctrl[1]) ||            ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))            errx(1, "Corrupt patch\n");        /* Adjust pointers */        newpos+=ctrl[1];        oldpos+=ctrl[2];    };    /* Clean up the bzip2 reads */    BZ2_bzReadClose(&cbz2err, cpfbz2);    BZ2_bzReadClose(&dbz2err, dpfbz2);    BZ2_bzReadClose(&ebz2err, epfbz2);    if (fclose(cpf) || fclose(dpf) || fclose(epf))        err(1, "fclose(%s)", argv[3]);    /* Write the new file */    if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||        (write(fd,new,newsize)!=newsize) || (close(fd)==-1))        err(1,"%s",argv[2]);    free(new);    free(old);    return 0;}

我们发现所需参数和生成差分包所需参数基本一致,并且我们需要导入bzip2,并在上述代码中进行引用

#include "bzip2/bzlib.c"#include "bzip2/crctable.c"#include "bzip2/compress.c"#include "bzip2/decompress.c"#include "bzip2/randtable.c"#include "bzip2/blocksort.c"#include "bzip2/huffman.c"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <err.h>#include <unistd.h>#include <fcntl.h>

新建一个bsPatch.java如下,并生成头文件

public class BsPatch {    /**     *      * @param oldfile旧文件路径     * @param newfile新文件路径     * @param patchfile差分包     */    public native static void bsPatch(String oldfile, String newfile,            String patchfile);}

拷贝头文件到jni目录中,并在bspatch.c中引用,并调用其中的方法,如下

//合并JNIEXPORT void JNICALL Java_com_saber_1bsdiff_BsPatch_bsPatch  (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;    bspathch_main(argc,argv);    (*env)->ReleaseStringUTFChars(env,oldfile_jstr, oldfile);    (*env)->ReleaseStringUTFChars(env,newfile_jstr, newfile);    (*env)->ReleaseStringUTFChars(env,patchfile_jstr, patchfile);}

然后builde project形成.so文件

在MainActivity中执行如下代码

class ApkUpdateTask extends AsyncTask<Void, Void, Boolean>{        @Override        protected Boolean doInBackground(Void... params) {            try {                //1.下载差分包                File patchFile = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD);                //获取当前应用的apk文件/data/app/app                String oldfile = ApkUtils.getSourceApkPath(MainActivity.this, getPackageName());                //2.合并得到最新版本的APK文件                String newfile = Constants.NEW_APK_PATH;                String patchfile = patchFile.getAbsolutePath();                BsPatch.bsPatch(oldfile, newfile, patchfile);            } catch (Exception e) {                e.printStackTrace();                return false;            }            return true;        }        @Override        protected void onPostExecute(Boolean result) {            super.onPostExecute(result);            //3.安装            if(result){                ApkUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);            }        }    }

群号:454430053,欢迎入群

0 0
原创粉丝点击