当前位置:操作系统 > 安卓/Android >>

浅析android应用增量升级

很久没有更新博客了,真是堕落啊,几次想提起笔,却总是被各种琐事耽搁,以后会多写文章记录点滴。
背景
        随着android应用体积的不断增大,以及应用版本发布的不断更迭,用户的升级成了一个问题,google也意识到不断更新应用对用户流量的损耗,在Google I/O 上提及的 Smart App update,即应用增量升级,或者叫做差分升级的做法,并在新版本的Google Play中得到支持,某天在和群友聊天是扯到这方面的话题,好奇就稍微研究了一下。
增量升级的原理
        今天我们就来实现类似的应用的增量升级。其实增量升级的原理很简单,即首先将应用的旧版本Apk与新版本Apk做差分,得到更新的部分的补丁,例如旧版本的APK有5M,新版的有8M,更新的部分则可能只有3M左右(这里需要说明的是,得到的差分包大小并不是简单的相减,因为其实需要包含一些上下文相关的东西),使用差分升级的好处显而易见,那么你不需要下载完整的8M文件,只需要下载更新部分就可以,而更新部分可能只有3、4M,可以很大程度上减少流量的损失。


         在用户下载了差分包之后,需要在手机端将他们组合起来。可以参考的做法是先将手机端的旧版本软件(多半在/data/下),复制到SD卡或者cache中,将它们和之前的差分patch进行组合,得到一个新版本的apk应用,如果不出意外的话,这个生成的apk和你之前做差分的apk是一致的。
增量升级的操作
       在了解基本的原理之后,我们来逐步解决其中的各个难点。首先是差分包patch的生成。如果做过android手机OTA升级的同学应该注意到,在update.zip中的patch文件夹中有需要与系统文件同名但是以xxx.p 为后缀的文件,他们就是生成的差分patch文件。我们可以借鉴OTA系统升级的差分生成工具来生成我们单个应用apk的差分patch文件。
OTA系统差分包的制作,使用命令:
 [java]
./build/tools/releasetools/ota_from_target_files -n -i <旧包> <新包> <差分包名> 

  ./build/tools/releasetools/ota_from_target_files -n -i <旧包> <新包> <差分包名>

小实验
       多说无益,实践才是王道。下面就来简单实践一下,检测之前理论的正确性。下载实验包 (http://download.csdn.net/detail/by317966834/5260384),解压后文件如下
[html]
├── bsdiff-4.3        //bsdiff的源码路径,官网获取 
│   ├── bsdiff.1 
│   ├── bsdiff.c 
│   ├── bspatch.1 
│   ├── bspatch.c 
│   └── Makefile 
├── bsdiff-4.3.tar.gz     
├── bsdiff4.3-win32     //windows PC端的测试工具 
│   ├── Binary diff.txt 
│   ├── bsdiff.exe 
│   ├── bspatch.exe 
│   └── LICENSE 
├── bspatch             //手机端的测试工具 
├── iReader1.6.2.0(v35).apk      // 旧版本的apk 
└── iReader1.8.0.1(v40).apk    //新版本的apk 

       以附带的iReader来做测试,在shell进入test\bsdiff4.3-win32文件夹,并下运行命令:
[html]
bsdiff.exe   ../iReader1.6.2.0(v35).apk   ../iReader1.8.0.1(v40).apk   ../ireader.patch 
       原来的apk(2.94M),新版本的(3.24M),得到的patch文件为1.77M,用户需要下载的就只是1.77M,流量节省了很多。
     下面先在电脑端将他们合并。
     [html] view plaincopybspatch.exe  ../iReader1.6.2.0(v35).apk   ../new.apk    ../ireader.patch 
     执行后得到名为new.apk 的合成版本应用,我在ubuntu下进行校验可以看出他们是一样的。

  
    下面我们在手机端合成看看,将根目录下的bspatch(此为手机端运行的)、iReader1.6.2.0(v35).apk 和ireader.patch ,通过adb push到你有权限操作的目录,最好是在/sdcard/下,然后设置bspatch的执行权限,重复操作上述命令,可以合成新版本的apk,稍后安装查看验证版本即可,不详述。
扩展阅读
      使用bsdiff 进行差分升级,还并不是最优的方式,google在它的Chromium项目中,对这个差分算法进行了优化,优化后的版本叫做小胡瓜Courgette,据说性能优化了很多不是一个数量级了,官方的一个例子:
Full update       10,385,920
bsdiff update     704,512
Courgette update      78,848
       大牛们可以去研究下。
      最近有些小忙,稍后有时间会对增量升级进行封装下,将合成的代码弄成一个lib库,供java调用。有兴趣的童鞋可以自己操作一下~~~
          

 


补充:
很多人不知道怎么进行封装为lib,其实这个和一般的android的C库是一样的,不明白的看看jni相关的知识,原来的测试工程已经找不到了,下边我给出个简单的例子,抛砖引玉,给大家参考下。


  [java]
#include <stdio.h> 
#include "com_hmg25_newstart_BSpatch.h" 
 
#include <bzlib.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   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

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,