阅读此文之前请先阅读  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:差分比文件存放路径public native int applyPatchToOldApk(String oldapk_filepath, String newapk_savepath , String patchpath);

3、编写Android.mk配置文件,并把需要的bzlib2源代码文件()拷贝到目录下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)# This is the target being built.
LOCAL_MODULE:= libBsdiff# All of the source files that we will compile.
# 具体到底需要哪些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 \# No static libraries.
LOCAL_STATIC_LIBRARIES := \libbz# Also need the JNI headers.
LOCAL_C_INCLUDES += \$(JNI_H_INCLUDE) external/bzip2# No special compiler flags.
LOCAL_CFLAGS +=include $(BUILD_SHARED_LIBRARY)

4、实现本地方法

#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>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 applypatch(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   X16  8   Y24  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 bytesfrom oldfile to x bytes from the diff block; copy y bytes from theextra 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;
}// old 升级之前apk包路径
// new 升级之后apk包路径
// patch文件,可以用bsdiff工具生成
// 具体原理可以参看http://blog.csdn.net/hmg25/article/details/8100896
JNIEXPORT jint JNICALL Java_tu_bingbing_bsdiff_BsdiffBusiness_applyPatchToOldApk(JNIEnv *env,jobject obj, jstring old, jstring new , jstring patch){int argc=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));int ret=applypatch(argc, argv);(*env)->ReleaseStringUTFChars(env,old,argv[1]);(*env)->ReleaseStringUTFChars(env,new,argv[2]);(*env)->ReleaseStringUTFChars(env,patch,argv[3]);return ret;
}

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

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

Android应用增量升级相关推荐

  1. Android 探索增量升级

    一.介绍 Android 的增量升级,不同热修复和热更新,它只是通过和老的 apk 对比,识别出与新 apk 之间的二进制差异,从而生成的补丁包(差量包): 这样的好处在于,不用全部下载所有的文件,比 ...

  2. Android APP增量升级的实现方式

    实现原理 增量更新的原理非常简单,就是将本地apk与服务器端最新版本比对,并得到差异包,用户更新App时只需要下载差异包.例如,当前安装新浪微博V3.5,12.8 MB,新浪微博最新版V4.0,15. ...

  3. Android apk增量升级

    前言 别看本文看上去很简单,实际在实验过程中遇到了很多问题,比如andorid studio下ndk编译报错,而本文呈现给大家的都是最终可行的方法. 所需资源 bzip2 bsdiff ndk 两个不 ...

  4. 浅析android应用增量升级

    2019独角兽企业重金招聘Python工程师标准>>> http://blog.csdn.net/hmg25/article/details/8100896 bsdiff http: ...

  5. Android增量升级

           Android的增量升级原理就是做apk版本之间的差分数据包,得到这个补丁包以后,在客户端合并旧的apk和补丁包,得到一个新的apk,最终通过新的apk实现升级. Android的增量升 ...

  6. 增量升级(省流量更新)的Android客户端实现

    By sgwhp (http://blog.csdn.net/sgwhp)转载请注明出处 用过类似360手机助手应该对省流量更新都很熟悉了.详细资料可以参考以下两个博客: 浅析android应用增量升 ...

  7. 手把手实现andriod应用增量升级

    转载地址:http://blog.csdn.net/mockingbirds/article/details/47701635?utm_source=tuicool 最近研究了android应用增量升 ...

  8. android ota升级服务,android 标准OTA升级流程

    标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户.推送的信息常常会包含OTA更新包的下载地址和一些版本信息. 2.Update程序会将 ...

  9. 增量升级(省流量更新)的Java服务端实现

    用过类似360手机助手应该对省流量更新都很熟悉了.详细资料可以参考以下两个帖子: 浅析android应用增量升级 Android应用增量升级 本文需要详细说的是服务端的实现.即服务端如何用JAVA实现 ...

最新文章

  1. 个人计算机与微型计算机的区别与联系,微处理器、微型计算机和微型计算机系统之间有何联系与区别?...
  2. 2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)
  3. java uuid 效率_java uuid第一次性能
  4. Java LinkedList双向链表源码分析
  5. 区块链中的密码学,使用ABE结合区块链
  6. 最长递增子序列和网易去除最少使从左向右递增又递减问题
  7. Windows10安装ubuntu 20双系统
  8. int 与Integer的用法与区别
  9. 在GridView列中动态创建几个CheckBox
  10. RuntimeError: failed to execute [‘dot‘, ‘-Tpdf‘, ‘-O‘, ‘test‘], make sure the Graphviz executables
  11. Web 项目中,MySQL 最新驱动下载、及配置
  12. OpenDrive格式的高精度地图
  13. iostream和stdafx.h
  14. java语言程序设计郎波_Java语言程序设计(第3版) 郎波 清华大学出版社
  15. 伦敦时间现在几点_英国伦敦时间现在几点钟(英国时差和中国差几个小时)
  16. -atime、-ctime、mtime、-newer
  17. 中国驾照在美国各州开车的规定
  18. 图像配置分类及名词解释
  19. 【技能教学】如何通过FFMPEG编码推RTSP视频直播流到EasyDarwin开源平台时叠加时间水印?
  20. 【NLP自然语言处理】文本特征提取

热门文章

  1. 【游戏开发实战】教你在Unity中实现模型消融化为灰烬飘散的效果(ShaderGraph | 消融 | 粒子系统 | 特效)
  2. for...in与for...of区别
  3. Arduino单片机智能土壤灌溉浇水系统根据土壤湿度温度光照智能浇水
  4. java中的 s_「javas」Java中 s = s+1 与 s +=1 的区别 - seo实验室
  5. 网上买充电宝怎么选?网上选充电宝的技巧
  6. HCIP 证书过期后要怎么重新认证?需要注意什么?
  7. 穿越火线河北一区服务器位置,cf北方大区属于哪个区(穿越火线合区列表)
  8. 转录组+代谢组联合分析
  9. 泡MM的android小程序
  10. python画一朵玫瑰花,制作成可执行文件