背景


我们知道,现在市面上有很多应用助手,比如豌豆荚,360手机助手,应用宝等,这些应用基本上都具有省流量下载功能。 由于现在的安卓应用多而大,并且更新频率快,即使现在随处都有wifi覆盖,但总有时候会使用数据流量,这时如果相更新应用就比较老火啦。 而省流量升级的出现正好可以解决这个问题。


省流量升级介绍

  • 介绍

省流量升级又名增量升级,官方称为Smart App Update 自从 Android 4.1 开始,Google引入了应用程序的增量更新


  • 官方说明

Smart app updates is a new feature of Google Play that introduces a better way of delivering app updates to devices. When developers publish an update, Google Play now delivers only the bits that have changed to devices, rather than the entire APK. This makes the updates much lighter-weight in most cases, so they are faster to download, save the device’s battery, and conserve bandwidth usage on users’ mobile data plan. On average,a smart app update is about 1/3 the sizeof a full APK update.


  • 来看应用宝增量升级

应用 动态更新manifest_应用 动态更新manifest


原理

以下以应用宝为例来分析

  • 增量升级与手机OTA升级有相似之处,先来简单说下OTA升级吧,对OTA升级比较了解的略过

OTA差分包主要两个版本(两个版本中间包)之间做差异,生成差分包,使用OTA客户端来应用差分包完成升级 可以看看X_HIKe差分包:\\10.120.10.100\ckt_cd_share\SmartPhone\projects\HIKe\Version\X-HIKe\OTA版本 解压差分包update.zip,里面有大量的*.p文件,这些文件就是生成的差分patch文件,在升级时会将原始文件和差分文件生成新的文件,完成OTA升级 android中提供我们用来制作差分增量升级包的工具-->bsdiff,相关介绍:传送卷,源码路径:external/bsdiff,其中bsdiff.c是二进制文件比对的代码;bspatch.c是二进制文件合成的代码

应用 动态更新manifest_Android_02


  • 来看应用包增量升级原理

1.得到差分包,这步操作是在应用宝服务器上完成 假设,你的apk已经发布了3个版,1.0,2.0,3.0,这时候你要在后台发布4.0,在你上传时,就应该生成 1.0——>4.0的差异包; 2.0——>4.0的差异包; 3.0——>4.0的差异包; 如果版本相差太大就不建议使用增量升级,类似OTA相差3个以上版本使用OTA Full包升级 2.用户下载差分patch文件到手机 3.获取手机原始版本,并与patch合成新的apk,此时apk与新版本一致 看看图=>

应用 动态更新manifest_差分_03


实现

原理知道了,但这是如何实现的呢?我们可以来做下测试
下载测试包 [\\10.120.10.100\ckt_cd_share\SmartPhone\team\Framework\UED\yong.zou\Doc\Install_App\smart_app_update.zip]

应用 动态更新manifest_Android_04

  • 差分patch如何生成的呢?

生成旧版和新版的差分比patch文件,可以借助bsdiff开源库windows版本,源码在external/bsdiff/bsdiff.c 进入到工具包目录bsdiff4.3-win32下,按照如下图所示执行命令,得到*.patch文件

应用 动态更新manifest_应用 动态更新manifest_05


  • 如何合成新版本apk呢?

使用工具包下的bspatch.exe工具来合成,按照如下图所示来执行命令,得到新包,该包就可以正常安装

应用 动态更新manifest_应用 动态更新manifest_06


  • 合成的包和原始的新包一致,可以通过下图看出来

应用 动态更新manifest_应用 动态更新manifest_07


  • 问题来了,测试都使用bsdiff和bspatch的windows工具包,与我们实际需求不符合啊!!

既然源码里有bsdiff和bspatch,那么一定有可以做成linux版本的bsdiff给应用服务器生成patch用, 而合成patch是由应用宝来完成的,那么可以把bspatch稍加修改封装成so库,给应用包调用即可。可参考Android应用增量升级实现方法


  • 生成patch和合成新包都能实现了,那么还有一个问题需要解决,应用包是如何拿到旧版本的安装包的呢?

我们潜意识里,对于user版本来说,三方app是没办法访问/data/app或/mnt/asec的,但实际上三方应用是可以把/data/app下的app拿出来的。方法如下:


public void backupApp(String packageName, Context mContext) throws IOException
    {
        // 存放位置
        String newFile = Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator;
        String oldFile = null;
        try {
            // 原始位置
            oldFile = mContext.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;
            Log.i("zy", "oldFile:" + oldFile);
        } catch (NameNotFoundException e) {
            Log.e("zy", "Error:" + e.toString());
            e.printStackTrace();
        }
        System.out.println(newFile);
        System.out.println(oldFile);
 
        File in = new File(oldFile);
        File out = new File(newFile + packageName + ".apk");
        if (!out.exists()) {
            out.createNewFile();
            Toast.makeText(mContext, "文件备份成功!" + "存放于" + newFile + "目录下", 1)
                    .show();
        } else {
            Toast.makeText(mContext, "文件已经存在!" + "查看" + newFile + "目录下", 1).show();
        }
 
        FileInputStream fis = new FileInputStream(in);
        FileOutputStream fos = new FileOutputStream(out);
 
        int count;
        // 文件太大的话,我觉得需要修改
        byte[] buffer = new byte[256 * 1024];
        while ((count = fis.read(buffer)) > 0)
        {
            fos.write(buffer, 0, count);
        }
 
        fis.close();
        fos.flush();
        fos.close();
    }
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>



  • 想知道为啥我们不能访问/data/app目录,却能把里面的apk拿出来呢,看了下面的图就明白了。

应用 动态更新manifest_差分_08

/data/app目录访问不了,但是里面的文件有可读权限啊,哈哈~ 通过以上方法的思路可以看出,手机无需root,三方应用一样可以把app给拿出来。


OK,通过以上方法和思路是可以来做app的增量升级的,应用宝最终是不是这个思路就不得而知,但总的说来,这也不失为一个方法。