增量更新(客户端笔记)
来源:互联网 发布:历史上真实的和珅 知乎 编辑:程序博客网 时间: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
- 增量更新(客户端笔记)
- android 客户端增量更新
- android 增量更新之客户端
- 增量升级(省流量更新)的Android客户端实现
- 增量升级(省流量更新)的Android客户端实现
- Android--增量升级--增量更新客户端的实现方法
- Android--增量升级--增量更新客户端的实现方法
- Android的增量更新,差分更新--服务器端&客户端
- Android增量更新(四)-客户端合并差分包生成新的apk安装包
- 热修复 增量更新 学习笔记
- 增量更新(制作差分包笔记)
- ToLua学习笔记,增量热更新
- Android 增量更新(一)
- Android增量更新(1)
- android差异化更新(增量更新)
- 浅谈Android增量更新客户端的实现方法
- 增量更新---服务端与客户端的处理方案
- 增量更新
- 设计模式-结构性模式:桥接模式 Bridge
- 使用RecyclerView时出现异常IllegalArgumentException的原因
- PHP+AJAX进行分页
- 作用域
- CSS 设置滚动条样式
- 增量更新(客户端笔记)
- 正则表达式30分钟入门教程
- json表单回填(表单反序列化回填值)
- Bootstrap carousel轮转图的使用实例详解
- PHP之等价变换
- iOS 10 本地推送UNUserNotificationCenter
- tomcat 远程调试
- iOS之https请求客户端---AFNetworking
- android studio 添加assets文件夹