- 浏览: 487349 次
文章分类
最新评论
Android应用增量升级
阅读此文之前请先阅读 http://blog.csdn.net/hmg25/article/details/8100896
何为增量升级,简单说下,当应用版本要更新时通常的做法是重新下载新的版本去覆盖旧版本,但这样有个比较明显缺点,太浪费流量了,尤其是在GPRS模式下。我们能不能只更新新版本增加的内容呢,bsdiff/bzlib2可以帮助我们实现这点。下面介绍下具体的做法
第一、生成旧版和新版的差分比patch文件,可以借助bsdiff开源库windows版本
- bsdiff.exe../iReader1.6.2.0(v35).apk../iReader1.8.0.1(v40).apk../ireader.patch
第二、有了patch文件,我们就可以在Android平台上利用JNI调用bzlib2就可以实现增量升级了。
1、首先要有ndk编译环境,具体怎么搭建详见:http://blog.csdn.net/tibib/article/details/8504680
2、编写本地方法
- //oldapk_filepath:旧版本存储路径newapk_savepath:生成的新版本要存放的路径patchpath:差分比文件存放路径
- publicnativeintapplyPatchToOldApk(Stringoldapk_filepath,Stringnewapk_savepath,Stringpatchpath);
- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- #Thisisthetargetbeingbuilt.
- LOCAL_MODULE:=libBsdiff
- #Allofthesourcefilesthatwewillcompile.
- #具体到底需要哪些c代码,没有仔细研究过
- LOCAL_SRC_FILES:=tu_bingbing_bsdiff_BsdiffBusiness.c\
- bzlib.c\
- blocksort.c\
- compress.c\
- crctable.c\
- decompress.c\
- huffman.c\
- randtable.c\
- bzip2.c\
- #Nostaticlibraries.
- LOCAL_STATIC_LIBRARIES:=\
- libbz
- #AlsoneedtheJNIheaders.
- LOCAL_C_INCLUDES+=\
- $(JNI_H_INCLUDE)external/bzip2
- #Nospecialcompilerflags.
- LOCAL_CFLAGS+=
- include$(BUILD_SHARED_LIBRARY)
- #include<stdio.h>
- #include"tu_bingbing_bsdiff_BsdiffBusiness.h"
- #include"bzlib_private.h"
- #include<stdlib.h>
- #include<stdio.h>
- #include<string.h>
- #include<err.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<android/log.h>
- staticoff_tofftin(u_char*buf)
- {
- off_ty;
- 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;
- returny;
- }
- intapplypatch(intargc,char*argv[])
- {
- FILE*f,*cpf,*dpf,*epf;
- BZFILE*cpfbz2,*dpfbz2,*epfbz2;
- intcbz2err,dbz2err,ebz2err;
- intfd;
- ssize_toldsize,newsize;
- ssize_tbzctrllen,bzdatalen;
- u_charheader[32],buf[8];
- u_char*old,*new;
- off_toldpos,newpos;
- off_tctrl[3];
- off_tlenread;
- off_ti;
- if(argc!=4)errx(1,"usage:%soldfilenewfilepatchfile\n",argv[0]);
- /*Openpatchfile*/
- if((f=fopen(argv[3],"r"))==NULL)
- err(1,"fopen(%s)",argv[3]);
- /*
- Fileformat:
- 08"BSDIFF40"
- 88X
- 168Y
- 248sizeof(newfile)
- 32Xbzip2(controlblock)
- 32+XYbzip2(diffblock)
- 32+X+Y???bzip2(extrablock)
- withcontrolblockasetoftriples(x,y,z)meaning"addxbytes
- fromoldfiletoxbytesfromthediffblock;copyybytesfromthe
- extrablock;seekforwardsinoldfilebyzbytes".
- */
- /*Readheader*/
- if(fread(header,1,32,f)<32){
- if(feof(f))
- errx(1,"Corruptpatch\n");
- err(1,"fread(%s)",argv[3]);
- }
- /*Checkforappropriatemagic*/
- if(memcmp(header,"BSDIFF40",8)!=0)
- errx(1,"Corruptpatch\n");
- /*Readlengthsfromheader*/
- bzctrllen=offtin(header+8);
- bzdatalen=offtin(header+16);
- newsize=offtin(header+24);
- if((bzctrllen<0)||(bzdatalen<0)||(newsize<0))
- errx(1,"Corruptpatch\n");
- /*Closepatchfileandre-openitvialibbzip2attherightplaces*/
- 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],
- (longlong)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],
- (longlong)(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],
- (longlong)(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){
- /*Readcontroldata*/
- 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,"Corruptpatch\n");
- ctrl[i]=offtin(buf);
- };
- /*Sanity-check*/
- if(newpos+ctrl[0]>newsize)
- errx(1,"Corruptpatch\n");
- /*Readdiffstring*/
- lenread=BZ2_bzRead(&dbz2err,dpfbz2,new+newpos,ctrl[0]);
- if((lenread<ctrl[0])||
- ((dbz2err!=BZ_OK)&&(dbz2err!=BZ_STREAM_END)))
- errx(1,"Corruptpatch\n");
- /*Addolddatatodiffstring*/
- for(i=0;i<ctrl[0];i++)
- if((oldpos+i>=0)&&(oldpos+i<oldsize))
- new[newpos+i]+=old[oldpos+i];
- /*Adjustpointers*/
- newpos+=ctrl[0];
- oldpos+=ctrl[0];
- /*Sanity-check*/
- if(newpos+ctrl[1]>newsize)
- errx(1,"Corruptpatch\n");
- /*Readextrastring*/
- lenread=BZ2_bzRead(&ebz2err,epfbz2,new+newpos,ctrl[1]);
- if((lenread<ctrl[1])||
- ((ebz2err!=BZ_OK)&&(ebz2err!=BZ_STREAM_END)))
- errx(1,"Corruptpatch\n");
- /*Adjustpointers*/
- newpos+=ctrl[1];
- oldpos+=ctrl[2];
- };
- /*Cleanupthebzip2reads*/
- 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]);
- /*Writethenewfile*/
- 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);
- return0;
- }
- //old升级之前apk包路径
- //new升级之后apk包路径
- //patch文件,可以用bsdiff工具生成
- //具体原理可以参看http://blog.csdn.net/hmg25/article/details/8100896
- JNIEXPORTjintJNICALLJava_tu_bingbing_bsdiff_BsdiffBusiness_applyPatchToOldApk(JNIEnv*env,
- jobjectobj,jstringold,jstringnew,jstringpatch){
- intargc=4;
- char*argv[argc];
- argv[0]="bspatch";
- argv[1]=(char*)((*env)->GetStringUTFChars(env,old,0));
- argv[2]=(char*)((*env)->GetStringUTFChars(env,new,0));
- argv[3]=(char*)((*env)->GetStringUTFChars(env,patch,0));
- intret=applypatch(argc,argv);
- (*env)->ReleaseStringUTFChars(env,old,argv[1]);
- (*env)->ReleaseStringUTFChars(env,new,argv[2]);
- (*env)->ReleaseStringUTFChars(env,patch,argv[3]);
- returnret;
- }
最后 ndk编译,在Android中调用native方法,你会发现在你传入路径下生成了新版本的apk。
DEMO:http://download.csdn.net/detail/tibib/5581905
阅读此文之前请先阅读 http://blog.csdn.net/hmg25/article/details/8100896
何为增量升级,简单说下,当应用版本要更新时通常的做法是重新下载新的版本去覆盖旧版本,但这样有个比较明显缺点,太浪费流量了,尤其是在GPRS模式下。我们能不能只更新新版本增加的内容呢,bsdiff/bzlib2可以帮助我们实现这点。下面介绍下具体的做法
第一、生成旧版和新版的差分比patch文件,可以借助bsdiff开源库windows版本
- bsdiff.exe../iReader1.6.2.0(v35).apk../iReader1.8.0.1(v40).apk../ireader.patch
第二、有了patch文件,我们就可以在Android平台上利用JNI调用bzlib2就可以实现增量升级了。
1、首先要有ndk编译环境,具体怎么搭建详见:http://blog.csdn.net/tibib/article/details/8504680
2、编写本地方法
- //oldapk_filepath:旧版本存储路径newapk_savepath:生成的新版本要存放的路径patchpath:差分比文件存放路径
- publicnativeintapplyPatchToOldApk(Stringoldapk_filepath,Stringnewapk_savepath,Stringpatchpath);
- LOCAL_PATH:=$(callmy-dir)
- include$(CLEAR_VARS)
- #Thisisthetargetbeingbuilt.
- LOCAL_MODULE:=libBsdiff
- #Allofthesourcefilesthatwewillcompile.
- #具体到底需要哪些c代码,没有仔细研究过
- LOCAL_SRC_FILES:=tu_bingbing_bsdiff_BsdiffBusiness.c\
- bzlib.c\
- blocksort.c\
- compress.c\
- crctable.c\
- decompress.c\
- huffman.c\
- randtable.c\
- bzip2.c\
- #Nostaticlibraries.
- LOCAL_STATIC_LIBRARIES:=\
- libbz
- #AlsoneedtheJNIheaders.
- LOCAL_C_INCLUDES+=\
- $(JNI_H_INCLUDE)external/bzip2
- #Nospecialcompilerflags.
- LOCAL_CFLAGS+=
- include$(BUILD_SHARED_LIBRARY)
- #include<stdio.h>
- #include"tu_bingbing_bsdiff_BsdiffBusiness.h"
- #include"bzlib_private.h"
- #include<stdlib.h>
- #include<stdio.h>
- #include<string.h>
- #include<err.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<android/log.h>
- staticoff_tofftin(u_char*buf)
- {
- off_ty;
- 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;
- returny;
- }
- intapplypatch(intargc,char*argv[])
- {
- FILE*f,*cpf,*dpf,*epf;
- BZFILE*cpfbz2,*dpfbz2,*epfbz2;
- intcbz2err,dbz2err,ebz2err;
- intfd;
- ssize_toldsize,newsize;
- ssize_tbzctrllen,bzdatalen;
- u_charheader[32],buf[8];
- u_char*old,*new;
- off_toldpos,newpos;
- off_tctrl[3];
- off_tlenread;
- off_ti;
- if(argc!=4)errx(1,"usage:%soldfilenewfilepatchfile\n",argv[0]);
- /*Openpatchfile*/
- if((f=fopen(argv[3],"r"))==NULL)
- err(1,"fopen(%s)",argv[3]);
- /*
- Fileformat:
- 08"BSDIFF40"
- 88X
- 168Y
- 248sizeof(newfile)
- 32Xbzip2(controlblock)
- 32+XYbzip2(diffblock)
- 32+X+Y???bzip2(extrablock)
- withcontrolblockasetoftriples(x,y,z)meaning"addxbytes
- fromoldfiletoxbytesfromthediffblock;copyybytesfromthe
- extrablock;seekforwardsinoldfilebyzbytes".
- */
- /*Readheader*/
- if(fread(header,1,32,f)<32){
- if(feof(f))
- errx(1,"Corruptpatch\n");
- err(1,"fread(%s)",argv[3]);
- }
- /*Checkforappropriatemagic*/
- if(memcmp(header,"BSDIFF40",8)!=0)
- errx(1,"Corruptpatch\n");
- /*Readlengthsfromheader*/
- bzctrllen=offtin(header+8);
- bzdatalen=offtin(header+16);
- newsize=offtin(header+24);
- if((bzctrllen<0)||(bzdatalen<0)||(newsize<0))
- errx(1,"Corruptpatch\n");
- /*Closepatchfileandre-openitvialibbzip2attherightplaces*/
- 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],
- (longlong)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],
- (longlong)(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],
- (longlong)(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){
- /*Readcontroldata*/
- 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,"Corruptpatch\n");
- ctrl[i]=offtin(buf);
- };
- /*Sanity-check*/
- if(newpos+ctrl[0]>newsize)
- errx(1,"Corruptpatch\n");
- /*Readdiffstring*/
- lenread=BZ2_bzRead(&dbz2err,dpfbz2,new+newpos,ctrl[0]);
- if((lenread<ctrl[0])||
- ((dbz2err!=BZ_OK)&&(dbz2err!=BZ_STREAM_END)))
- errx(1,"Corruptpatch\n");
- /*Addolddatatodiffstring*/
- for(i=0;i<ctrl[0];i++)
- if((oldpos+i>=0)&&(oldpos+i<oldsize))
- new[newpos+i]+=old[oldpos+i];
- /*Adjustpointers*/
- newpos+=ctrl[0];
- oldpos+=ctrl[0];
- /*Sanity-check*/
- if(newpos+ctrl[1]>newsize)
- errx(1,"Corruptpatch\n");
- /*Readextrastring*/
- lenread=BZ2_bzRead(&ebz2err,epfbz2,new+newpos,ctrl[1]);
- if((lenread<ctrl[1])||
- ((ebz2err!=BZ_OK)&&(ebz2err!=BZ_STREAM_END)))
- errx(1,"Corruptpatch\n");
- /*Adjustpointers*/
- newpos+=ctrl[1];
- oldpos+=ctrl[2];
- };
- /*Cleanupthebzip2reads*/
- 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]);
- /*Writethenewfile*/
- 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);
- return0;
- }
- //old升级之前apk包路径
- //new升级之后apk包路径
- //patch文件,可以用bsdiff工具生成
- //具体原理可以参看http://blog.csdn.net/hmg25/article/details/8100896
- JNIEXPORTjintJNICALLJava_tu_bingbing_bsdiff_BsdiffBusiness_applyPatchToOldApk(JNIEnv*env,
- jobjectobj,jstringold,jstringnew,jstringpatch){
- intargc=4;
- char*argv[argc];
- argv[0]="bspatch";
- argv[1]=(char*)((*env)->GetStringUTFChars(env,old,0));
- argv[2]=(char*)((*env)->GetStringUTFChars(env,new,0));
- argv[3]=(char*)((*env)->GetStringUTFChars(env,patch,0));
- intret=applypatch(argc,argv);
- (*env)->ReleaseStringUTFChars(env,old,argv[1]);
- (*env)->ReleaseStringUTFChars(env,new,argv[2]);
- (*env)->ReleaseStringUTFChars(env,patch,argv[3]);
- returnret;
- }
最后 ndk编译,在Android中调用native方法,你会发现在你传入路径下生成了新版本的apk。
DEMO:http://download.csdn.net/detail/tibib/5581905
相关推荐
android增量测试所用到的test工具及相关的源码,详情请前往我的博客:
ReadMe:需要有生成差分patch的文件,与旧apk进行合并。生成差分包的patch方法可以如下列出的"参考文档"。Install bsdiff for Ubuntu:... 下载地址: ... 参考文档: ...
Android应用增量更新,是一个用于Android应用程序增量更新的库,包括客户端、服务端两部分代码。
andorid 增量升级的demo,其实就是通过二进制的差分和合成来做的。简单的demo详细的介绍在我博客里面有
Android 实现应用的增量更新和升级
对应博文链接:http://blog.csdn.net/yyh352091626/article/details/50579859 Android底下实现类似小米应用商店的增量更新工程。主要进行补丁的生成,和新的APK的合并
用于安卓应用增量升级,可以做新旧版本应用的差异包,客户端做旧包和差异包合成新的安装包
Android应用源码安卓增量更新(差分升级)项目
Android系统手机软件增量升级.pdf
Android应用源码安卓增量更新(差分升级)项目.zip
你所看到的,是一个用于Android应用程序增量更新的开源库。 包括客户端、服务端两部分代码。 原理 自从 Android 4.1 开始,Google引入了应用程序的增量更新。 Link: ...
今天我们就来实现类似的应用的增量升级。其实增量升级的原理很简单,即首先将应用的旧版本Apk与新版本Apk做差分,得到更新的部分的补丁,例如旧版本的APK有5M,新版的有8M,更新的部分则可能只有3M左右(这里需要说明...
[ :check_mark: ] Android增量升级 [ :check_mark: ] IOS根据appid跳至Appstore升级 [ :check_mark: ] IOS根据appid获取Appstore的当前在线版本 入门 1.使用插件: 将此代码添加到pubspec.yaml dependencies : r_...
作者smuyyh,源码IncrementallyUpdate,Android实现应用的增量更新和升级。通过旧版APK+新版APK生成差分包,再用差分包与旧版APK合成新版APK并安装。 详细说明:http://android.662p.com/thread-6727-1-1.html
Android应用增量更新 - Smart App Updates 介绍 你所看到的,是一个用于Android应用程序增量更新的库。 包括客户端、服务端两部分代码。 原理 自从 Android 4.1 开始, Google Play 引入了应用程序的增量更新功能,...
尽管现在网络环境有了很大的提升,但一个不争的事实就是应用越做越大,因此,增量更新在目前的仍然是一种解决APP更新包过大的有效方案。今天,我们就来聊聊增量更新。增量更新的关键在于如何理解增量一词。来想想...
:应用场景:服务器发布新版本v1.1,客服端当前版本为v1.0,使用bsdiff生成差分包patch_v1.0_v1.1,然后客户端下载patch包到本地然后与本地的v1.0.apk合并生成v1.1.apk,然后执行安装,升级完成增量升级可以优化升级...
此增量包只能用在-掌讯3518-V005-190117官方版本固件,卡刷此增量包后 可增加root权限。桌面会自动增加magisk应用。 注意只能用在3518-V005上并且必须是190117版本基础上刷。 刷入方法:将root-ZL-3518-V005-...
此增量包只能用在-掌讯3518-V006-190404官方版本固件,卡刷此增量包后 可增加root权限。桌面会自动增加magisk应用。 注意只能用在3518-V006上并且必须是190404版本基础上刷。 刷入方法:将root-ZL-3518-V006-...
一键式移动自述文件 使用 MIT 许可的一键将 Html5 Web 应用程序打包到本机 Android/IOS 应用程序中 One Click Mobile Packer 是一种将 ...使用 Xamarin 工具从 Html5 应用程序页面增量升级到本机应用程序屏幕 Window