`
473687880
  • 浏览: 487349 次
文章分类
社区版块
存档分类
最新评论

Android应用增量升级

 
阅读更多


阅读此文之前请先阅读 http://blog.csdn.net/hmg25/article/details/8100896


何为增量升级,简单说下,当应用版本要更新时通常的做法是重新下载新的版本去覆盖旧版本,但这样有个比较明显缺点,太浪费流量了,尤其是在GPRS模式下。我们能不能只更新新版本增加的内容呢,bsdiff/bzlib2可以帮助我们实现这点。下面介绍下具体的做法


第一、生成旧版和新版的差分比patch文件,可以借助bsdiff开源库windows版本

  1. 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、编写本地方法

  1. //oldapk_filepath:旧版本存储路径newapk_savepath:生成的新版本要存放的路径patchpath:差分比文件存放路径
  2. publicnativeintapplyPatchToOldApk(Stringoldapk_filepath,Stringnewapk_savepath,Stringpatchpath);
3、编写Android.mk配置文件,并把需要的bzlib2源代码文件()拷贝到目录下

  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. #Thisisthetargetbeingbuilt.
  4. LOCAL_MODULE:=libBsdiff
  5. #Allofthesourcefilesthatwewillcompile.
  6. #具体到底需要哪些c代码,没有仔细研究过
  7. LOCAL_SRC_FILES:=tu_bingbing_bsdiff_BsdiffBusiness.c\
  8. bzlib.c\
  9. blocksort.c\
  10. compress.c\
  11. crctable.c\
  12. decompress.c\
  13. huffman.c\
  14. randtable.c\
  15. bzip2.c\
  16. #Nostaticlibraries.
  17. LOCAL_STATIC_LIBRARIES:=\
  18. libbz
  19. #AlsoneedtheJNIheaders.
  20. LOCAL_C_INCLUDES+=\
  21. $(JNI_H_INCLUDE)external/bzip2
  22. #Nospecialcompilerflags.
  23. LOCAL_CFLAGS+=
  24. include$(BUILD_SHARED_LIBRARY)
4、实现本地方法

  1. #include<stdio.h>
  2. #include"tu_bingbing_bsdiff_BsdiffBusiness.h"
  3. #include"bzlib_private.h"
  4. #include<stdlib.h>
  5. #include<stdio.h>
  6. #include<string.h>
  7. #include<err.h>
  8. #include<unistd.h>
  9. #include<fcntl.h>
  10. #include<android/log.h>
  11. staticoff_tofftin(u_char*buf)
  12. {
  13. off_ty;
  14. y=buf[7]&0x7F;
  15. y=y*256;y+=buf[6];
  16. y=y*256;y+=buf[5];
  17. y=y*256;y+=buf[4];
  18. y=y*256;y+=buf[3];
  19. y=y*256;y+=buf[2];
  20. y=y*256;y+=buf[1];
  21. y=y*256;y+=buf[0];
  22. if(buf[7]&0x80)y=-y;
  23. returny;
  24. }
  25. intapplypatch(intargc,char*argv[])
  26. {
  27. FILE*f,*cpf,*dpf,*epf;
  28. BZFILE*cpfbz2,*dpfbz2,*epfbz2;
  29. intcbz2err,dbz2err,ebz2err;
  30. intfd;
  31. ssize_toldsize,newsize;
  32. ssize_tbzctrllen,bzdatalen;
  33. u_charheader[32],buf[8];
  34. u_char*old,*new;
  35. off_toldpos,newpos;
  36. off_tctrl[3];
  37. off_tlenread;
  38. off_ti;
  39. if(argc!=4)errx(1,"usage:%soldfilenewfilepatchfile\n",argv[0]);
  40. /*Openpatchfile*/
  41. if((f=fopen(argv[3],"r"))==NULL)
  42. err(1,"fopen(%s)",argv[3]);
  43. /*
  44. Fileformat:
  45. 08"BSDIFF40"
  46. 88X
  47. 168Y
  48. 248sizeof(newfile)
  49. 32Xbzip2(controlblock)
  50. 32+XYbzip2(diffblock)
  51. 32+X+Y???bzip2(extrablock)
  52. withcontrolblockasetoftriples(x,y,z)meaning"addxbytes
  53. fromoldfiletoxbytesfromthediffblock;copyybytesfromthe
  54. extrablock;seekforwardsinoldfilebyzbytes".
  55. */
  56. /*Readheader*/
  57. if(fread(header,1,32,f)<32){
  58. if(feof(f))
  59. errx(1,"Corruptpatch\n");
  60. err(1,"fread(%s)",argv[3]);
  61. }
  62. /*Checkforappropriatemagic*/
  63. if(memcmp(header,"BSDIFF40",8)!=0)
  64. errx(1,"Corruptpatch\n");
  65. /*Readlengthsfromheader*/
  66. bzctrllen=offtin(header+8);
  67. bzdatalen=offtin(header+16);
  68. newsize=offtin(header+24);
  69. if((bzctrllen<0)||(bzdatalen<0)||(newsize<0))
  70. errx(1,"Corruptpatch\n");
  71. /*Closepatchfileandre-openitvialibbzip2attherightplaces*/
  72. if(fclose(f))
  73. err(1,"fclose(%s)",argv[3]);
  74. if((cpf=fopen(argv[3],"r"))==NULL)
  75. err(1,"fopen(%s)",argv[3]);
  76. if(fseeko(cpf,32,SEEK_SET))
  77. err(1,"fseeko(%s,%lld)",argv[3],
  78. (longlong)32);
  79. if((cpfbz2=BZ2_bzReadOpen(&cbz2err,cpf,0,0,NULL,0))==NULL)
  80. errx(1,"BZ2_bzReadOpen,bz2err=%d",cbz2err);
  81. if((dpf=fopen(argv[3],"r"))==NULL)
  82. err(1,"fopen(%s)",argv[3]);
  83. if(fseeko(dpf,32+bzctrllen,SEEK_SET))
  84. err(1,"fseeko(%s,%lld)",argv[3],
  85. (longlong)(32+bzctrllen));
  86. if((dpfbz2=BZ2_bzReadOpen(&dbz2err,dpf,0,0,NULL,0))==NULL)
  87. errx(1,"BZ2_bzReadOpen,bz2err=%d",dbz2err);
  88. if((epf=fopen(argv[3],"r"))==NULL)
  89. err(1,"fopen(%s)",argv[3]);
  90. if(fseeko(epf,32+bzctrllen+bzdatalen,SEEK_SET))
  91. err(1,"fseeko(%s,%lld)",argv[3],
  92. (longlong)(32+bzctrllen+bzdatalen));
  93. if((epfbz2=BZ2_bzReadOpen(&ebz2err,epf,0,0,NULL,0))==NULL)
  94. errx(1,"BZ2_bzReadOpen,bz2err=%d",ebz2err);
  95. if(((fd=open(argv[1],O_RDONLY,0))<0)||
  96. ((oldsize=lseek(fd,0,SEEK_END))==-1)||
  97. ((old=malloc(oldsize+1))==NULL)||
  98. (lseek(fd,0,SEEK_SET)!=0)||
  99. (read(fd,old,oldsize)!=oldsize)||
  100. (close(fd)==-1))err(1,"%s",argv[1]);
  101. if((new=malloc(newsize+1))==NULL)err(1,NULL);
  102. oldpos=0;newpos=0;
  103. while(newpos<newsize){
  104. /*Readcontroldata*/
  105. for(i=0;i<=2;i++){
  106. lenread=BZ2_bzRead(&cbz2err,cpfbz2,buf,8);
  107. if((lenread<8)||((cbz2err!=BZ_OK)&&
  108. (cbz2err!=BZ_STREAM_END)))
  109. errx(1,"Corruptpatch\n");
  110. ctrl[i]=offtin(buf);
  111. };
  112. /*Sanity-check*/
  113. if(newpos+ctrl[0]>newsize)
  114. errx(1,"Corruptpatch\n");
  115. /*Readdiffstring*/
  116. lenread=BZ2_bzRead(&dbz2err,dpfbz2,new+newpos,ctrl[0]);
  117. if((lenread<ctrl[0])||
  118. ((dbz2err!=BZ_OK)&&(dbz2err!=BZ_STREAM_END)))
  119. errx(1,"Corruptpatch\n");
  120. /*Addolddatatodiffstring*/
  121. for(i=0;i<ctrl[0];i++)
  122. if((oldpos+i>=0)&&(oldpos+i<oldsize))
  123. new[newpos+i]+=old[oldpos+i];
  124. /*Adjustpointers*/
  125. newpos+=ctrl[0];
  126. oldpos+=ctrl[0];
  127. /*Sanity-check*/
  128. if(newpos+ctrl[1]>newsize)
  129. errx(1,"Corruptpatch\n");
  130. /*Readextrastring*/
  131. lenread=BZ2_bzRead(&ebz2err,epfbz2,new+newpos,ctrl[1]);
  132. if((lenread<ctrl[1])||
  133. ((ebz2err!=BZ_OK)&&(ebz2err!=BZ_STREAM_END)))
  134. errx(1,"Corruptpatch\n");
  135. /*Adjustpointers*/
  136. newpos+=ctrl[1];
  137. oldpos+=ctrl[2];
  138. };
  139. /*Cleanupthebzip2reads*/
  140. BZ2_bzReadClose(&cbz2err,cpfbz2);
  141. BZ2_bzReadClose(&dbz2err,dpfbz2);
  142. BZ2_bzReadClose(&ebz2err,epfbz2);
  143. if(fclose(cpf)||fclose(dpf)||fclose(epf))
  144. err(1,"fclose(%s)",argv[3]);
  145. /*Writethenewfile*/
  146. if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0)||
  147. (write(fd,new,newsize)!=newsize)||(close(fd)==-1))
  148. err(1,"%s",argv[2]);
  149. free(new);
  150. free(old);
  151. return0;
  152. }
  153. //old升级之前apk包路径
  154. //new升级之后apk包路径
  155. //patch文件,可以用bsdiff工具生成
  156. //具体原理可以参看http://blog.csdn.net/hmg25/article/details/8100896
  157. JNIEXPORTjintJNICALLJava_tu_bingbing_bsdiff_BsdiffBusiness_applyPatchToOldApk(JNIEnv*env,
  158. jobjectobj,jstringold,jstringnew,jstringpatch){
  159. intargc=4;
  160. char*argv[argc];
  161. argv[0]="bspatch";
  162. argv[1]=(char*)((*env)->GetStringUTFChars(env,old,0));
  163. argv[2]=(char*)((*env)->GetStringUTFChars(env,new,0));
  164. argv[3]=(char*)((*env)->GetStringUTFChars(env,patch,0));
  165. intret=applypatch(argc,argv);
  166. (*env)->ReleaseStringUTFChars(env,old,argv[1]);
  167. (*env)->ReleaseStringUTFChars(env,new,argv[2]);
  168. (*env)->ReleaseStringUTFChars(env,patch,argv[3]);
  169. returnret;
  170. }

最后 ndk编译,在Android中调用native方法,你会发现在你传入路径下生成了新版本的apk。


DEMO:http://download.csdn.net/detail/tibib/5581905


Android应用增量升级

阅读此文之前请先阅读 http://blog.csdn.net/hmg25/article/details/8100896


何为增量升级,简单说下,当应用版本要更新时通常的做法是重新下载新的版本去覆盖旧版本,但这样有个比较明显缺点,太浪费流量了,尤其是在GPRS模式下。我们能不能只更新新版本增加的内容呢,bsdiff/bzlib2可以帮助我们实现这点。下面介绍下具体的做法


第一、生成旧版和新版的差分比patch文件,可以借助bsdiff开源库windows版本

  1. 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、编写本地方法

  1. //oldapk_filepath:旧版本存储路径newapk_savepath:生成的新版本要存放的路径patchpath:差分比文件存放路径
  2. publicnativeintapplyPatchToOldApk(Stringoldapk_filepath,Stringnewapk_savepath,Stringpatchpath);
3、编写Android.mk配置文件,并把需要的bzlib2源代码文件()拷贝到目录下

  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. #Thisisthetargetbeingbuilt.
  4. LOCAL_MODULE:=libBsdiff
  5. #Allofthesourcefilesthatwewillcompile.
  6. #具体到底需要哪些c代码,没有仔细研究过
  7. LOCAL_SRC_FILES:=tu_bingbing_bsdiff_BsdiffBusiness.c\
  8. bzlib.c\
  9. blocksort.c\
  10. compress.c\
  11. crctable.c\
  12. decompress.c\
  13. huffman.c\
  14. randtable.c\
  15. bzip2.c\
  16. #Nostaticlibraries.
  17. LOCAL_STATIC_LIBRARIES:=\
  18. libbz
  19. #AlsoneedtheJNIheaders.
  20. LOCAL_C_INCLUDES+=\
  21. $(JNI_H_INCLUDE)external/bzip2
  22. #Nospecialcompilerflags.
  23. LOCAL_CFLAGS+=
  24. include$(BUILD_SHARED_LIBRARY)
4、实现本地方法

  1. #include<stdio.h>
  2. #include"tu_bingbing_bsdiff_BsdiffBusiness.h"
  3. #include"bzlib_private.h"
  4. #include<stdlib.h>
  5. #include<stdio.h>
  6. #include<string.h>
  7. #include<err.h>
  8. #include<unistd.h>
  9. #include<fcntl.h>
  10. #include<android/log.h>
  11. staticoff_tofftin(u_char*buf)
  12. {
  13. off_ty;
  14. y=buf[7]&0x7F;
  15. y=y*256;y+=buf[6];
  16. y=y*256;y+=buf[5];
  17. y=y*256;y+=buf[4];
  18. y=y*256;y+=buf[3];
  19. y=y*256;y+=buf[2];
  20. y=y*256;y+=buf[1];
  21. y=y*256;y+=buf[0];
  22. if(buf[7]&0x80)y=-y;
  23. returny;
  24. }
  25. intapplypatch(intargc,char*argv[])
  26. {
  27. FILE*f,*cpf,*dpf,*epf;
  28. BZFILE*cpfbz2,*dpfbz2,*epfbz2;
  29. intcbz2err,dbz2err,ebz2err;
  30. intfd;
  31. ssize_toldsize,newsize;
  32. ssize_tbzctrllen,bzdatalen;
  33. u_charheader[32],buf[8];
  34. u_char*old,*new;
  35. off_toldpos,newpos;
  36. off_tctrl[3];
  37. off_tlenread;
  38. off_ti;
  39. if(argc!=4)errx(1,"usage:%soldfilenewfilepatchfile\n",argv[0]);
  40. /*Openpatchfile*/
  41. if((f=fopen(argv[3],"r"))==NULL)
  42. err(1,"fopen(%s)",argv[3]);
  43. /*
  44. Fileformat:
  45. 08"BSDIFF40"
  46. 88X
  47. 168Y
  48. 248sizeof(newfile)
  49. 32Xbzip2(controlblock)
  50. 32+XYbzip2(diffblock)
  51. 32+X+Y???bzip2(extrablock)
  52. withcontrolblockasetoftriples(x,y,z)meaning"addxbytes
  53. fromoldfiletoxbytesfromthediffblock;copyybytesfromthe
  54. extrablock;seekforwardsinoldfilebyzbytes".
  55. */
  56. /*Readheader*/
  57. if(fread(header,1,32,f)<32){
  58. if(feof(f))
  59. errx(1,"Corruptpatch\n");
  60. err(1,"fread(%s)",argv[3]);
  61. }
  62. /*Checkforappropriatemagic*/
  63. if(memcmp(header,"BSDIFF40",8)!=0)
  64. errx(1,"Corruptpatch\n");
  65. /*Readlengthsfromheader*/
  66. bzctrllen=offtin(header+8);
  67. bzdatalen=offtin(header+16);
  68. newsize=offtin(header+24);
  69. if((bzctrllen<0)||(bzdatalen<0)||(newsize<0))
  70. errx(1,"Corruptpatch\n");
  71. /*Closepatchfileandre-openitvialibbzip2attherightplaces*/
  72. if(fclose(f))
  73. err(1,"fclose(%s)",argv[3]);
  74. if((cpf=fopen(argv[3],"r"))==NULL)
  75. err(1,"fopen(%s)",argv[3]);
  76. if(fseeko(cpf,32,SEEK_SET))
  77. err(1,"fseeko(%s,%lld)",argv[3],
  78. (longlong)32);
  79. if((cpfbz2=BZ2_bzReadOpen(&cbz2err,cpf,0,0,NULL,0))==NULL)
  80. errx(1,"BZ2_bzReadOpen,bz2err=%d",cbz2err);
  81. if((dpf=fopen(argv[3],"r"))==NULL)
  82. err(1,"fopen(%s)",argv[3]);
  83. if(fseeko(dpf,32+bzctrllen,SEEK_SET))
  84. err(1,"fseeko(%s,%lld)",argv[3],
  85. (longlong)(32+bzctrllen));
  86. if((dpfbz2=BZ2_bzReadOpen(&dbz2err,dpf,0,0,NULL,0))==NULL)
  87. errx(1,"BZ2_bzReadOpen,bz2err=%d",dbz2err);
  88. if((epf=fopen(argv[3],"r"))==NULL)
  89. err(1,"fopen(%s)",argv[3]);
  90. if(fseeko(epf,32+bzctrllen+bzdatalen,SEEK_SET))
  91. err(1,"fseeko(%s,%lld)",argv[3],
  92. (longlong)(32+bzctrllen+bzdatalen));
  93. if((epfbz2=BZ2_bzReadOpen(&ebz2err,epf,0,0,NULL,0))==NULL)
  94. errx(1,"BZ2_bzReadOpen,bz2err=%d",ebz2err);
  95. if(((fd=open(argv[1],O_RDONLY,0))<0)||
  96. ((oldsize=lseek(fd,0,SEEK_END))==-1)||
  97. ((old=malloc(oldsize+1))==NULL)||
  98. (lseek(fd,0,SEEK_SET)!=0)||
  99. (read(fd,old,oldsize)!=oldsize)||
  100. (close(fd)==-1))err(1,"%s",argv[1]);
  101. if((new=malloc(newsize+1))==NULL)err(1,NULL);
  102. oldpos=0;newpos=0;
  103. while(newpos<newsize){
  104. /*Readcontroldata*/
  105. for(i=0;i<=2;i++){
  106. lenread=BZ2_bzRead(&cbz2err,cpfbz2,buf,8);
  107. if((lenread<8)||((cbz2err!=BZ_OK)&&
  108. (cbz2err!=BZ_STREAM_END)))
  109. errx(1,"Corruptpatch\n");
  110. ctrl[i]=offtin(buf);
  111. };
  112. /*Sanity-check*/
  113. if(newpos+ctrl[0]>newsize)
  114. errx(1,"Corruptpatch\n");
  115. /*Readdiffstring*/
  116. lenread=BZ2_bzRead(&dbz2err,dpfbz2,new+newpos,ctrl[0]);
  117. if((lenread<ctrl[0])||
  118. ((dbz2err!=BZ_OK)&&(dbz2err!=BZ_STREAM_END)))
  119. errx(1,"Corruptpatch\n");
  120. /*Addolddatatodiffstring*/
  121. for(i=0;i<ctrl[0];i++)
  122. if((oldpos+i>=0)&&(oldpos+i<oldsize))
  123. new[newpos+i]+=old[oldpos+i];
  124. /*Adjustpointers*/
  125. newpos+=ctrl[0];
  126. oldpos+=ctrl[0];
  127. /*Sanity-check*/
  128. if(newpos+ctrl[1]>newsize)
  129. errx(1,"Corruptpatch\n");
  130. /*Readextrastring*/
  131. lenread=BZ2_bzRead(&ebz2err,epfbz2,new+newpos,ctrl[1]);
  132. if((lenread<ctrl[1])||
  133. ((ebz2err!=BZ_OK)&&(ebz2err!=BZ_STREAM_END)))
  134. errx(1,"Corruptpatch\n");
  135. /*Adjustpointers*/
  136. newpos+=ctrl[1];
  137. oldpos+=ctrl[2];
  138. };
  139. /*Cleanupthebzip2reads*/
  140. BZ2_bzReadClose(&cbz2err,cpfbz2);
  141. BZ2_bzReadClose(&dbz2err,dpfbz2);
  142. BZ2_bzReadClose(&ebz2err,epfbz2);
  143. if(fclose(cpf)||fclose(dpf)||fclose(epf))
  144. err(1,"fclose(%s)",argv[3]);
  145. /*Writethenewfile*/
  146. if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0)||
  147. (write(fd,new,newsize)!=newsize)||(close(fd)==-1))
  148. err(1,"%s",argv[2]);
  149. free(new);
  150. free(old);
  151. return0;
  152. }
  153. //old升级之前apk包路径
  154. //new升级之后apk包路径
  155. //patch文件,可以用bsdiff工具生成
  156. //具体原理可以参看http://blog.csdn.net/hmg25/article/details/8100896
  157. JNIEXPORTjintJNICALLJava_tu_bingbing_bsdiff_BsdiffBusiness_applyPatchToOldApk(JNIEnv*env,
  158. jobjectobj,jstringold,jstringnew,jstringpatch){
  159. intargc=4;
  160. char*argv[argc];
  161. argv[0]="bspatch";
  162. argv[1]=(char*)((*env)->GetStringUTFChars(env,old,0));
  163. argv[2]=(char*)((*env)->GetStringUTFChars(env,new,0));
  164. argv[3]=(char*)((*env)->GetStringUTFChars(env,patch,0));
  165. intret=applypatch(argc,argv);
  166. (*env)->ReleaseStringUTFChars(env,old,argv[1]);
  167. (*env)->ReleaseStringUTFChars(env,new,argv[2]);
  168. (*env)->ReleaseStringUTFChars(env,patch,argv[3]);
  169. returnret;
  170. }

最后 ndk编译,在Android中调用native方法,你会发现在你传入路径下生成了新版本的apk。


DEMO:http://download.csdn.net/detail/tibib/5581905


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics