Android增量更新
来源:互联网 发布:phpexcel导出大量数据 编辑:程序博客网 时间:2024/06/05 10:20
一、增量更新
1.概述
增量更新,是指通过分析出新apk与旧apk之间的增量文件,然后提取老版的app安装文件,并与增量文件合成新的安装包,之后重新安装即可。
增量更新可以让我们不必加载整个安装包,即可实现app的更新,节省了不少流量,提供更佳的用户体验。有些应用市场,就是通过此方式实现流量的节省。
2.实现步骤
1)利用新apk与旧apk生成增量文件;
2)提取手机上的旧apk;
3)合成旧apk与增量文件,安装合成的新apk。
接下来一步步来实现上述的步骤。
二、实现
1.生成增量文件
这个我们使用工具bsdiff.exe即可生成差异文件,这个,我已经忘了之前从哪里找到的windows上的exe文件,直接提供下载地址:windows下bsdiff与bspatch下载地址
当然也有linux版本的,需要自己下载,make,下载地址:http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz。
使用方法也很简单:
在所在目录中,cmd命令生成增量文件:bsdiff old.apk new.apk new.patch
2.提取手机上的旧apk
上面的都是在pc上完成,下面的提取与合成都放在app上完成。
提取旧apk,直接提供一个工具方法:
/** * 提取本应用的apk路径 */public static String extract(Context context) { context = context.getApplicationContext(); ApplicationInfo applicationInfo = context.getApplicationInfo(); return applicationInfo.sourceDir;}
3.合成与安装
合成需要使用到Native方法,因此要打包一个so库文件,也方便以后使用,这里也涉及到ndk与jni的使用。下面我一步步实现。
1)下载与配置NDK
首先,要下载NDK,一般在AS中打开SDKManager在SDKTools中下载。但是这里不要这么做,在实践中,发现sdk中更新的sdk如果过高,在打出的so库中使用的一些方法会找不到,因为有些手机使用的库较早。我在刚刚接触这个功能时,sdk是r14,但是打包出的so库在荣耀7和魅族上都会抛出找不到指定方法的异常。抠脚一天,才在网上找到可能是NDK版本过高的原因,因此这里我实验通过的版本是r10e,下载地址:http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe。下载之后,安装到sdk目录中。
首先在gradle.properties中配置
然后是local.properties
好了,配置就差不多了。可能大家在用的时候还是会遇到一些配置问题,请自行百度NDK配置,我就配了这俩地方。
2)实现合成nativie方法与打包
a)合成的native方法如下:
package com.example.davidchen.patchdemo.util;/** * 增量更新,合成 * Created by DavidChen on 2017/1/4. */public class BsPatch { static { System.loadLibrary("bsdiff"); } public static native int bspatch(String oldApk, String newApk, String patch);}b)先make project,之后在指定的目录...\app\build\intermediates\classes\debug\com\example\davidchen\patchdemo\util下找到编译出来的class文件,再用javah -jni com.example.davidchen.patchdemo.util.BsPatch命令生成对应的头文件。文件位置在...\app\build\intermediates\classes\debug目录下。
接下来就是c实现部分
c)首先建立jni目录:
d)将之前的头文件剪切到该目录中,再建立c实现文件(这里是Patch.c)。当然还有核心的实现方法。这里还有个依赖的bzip,要从网上下载,网址:http://www.bzip.org/downloads.html。当然这个库里还有些要去掉的多余的文件与方法。这里提供一个精简过的包以及上面的c实现:native方法c实现。但是不要直接用我上面生成的文件,因为native方法的命名是由要求的,直接使用会出问题,但是代码可以拷过去,注意改一下方法名和include即可。
e)配置ndk生成对应不同cpu的abi架构的so
说一下,一般我们为了缩减apk大小,会选择最少的so,怎样去适配不同手机的cpu架构呢,一般的机子,大部分都是支持armeabi或armeabi-v7a,而且x86的机子也会支持armeabi的类库。因此我们一般只需要armeabi的so。
之后可以在...\app\build\intermediates\ndk\debug\lib目录中找到生成的so,拷贝到项目...\app\libs\目录下(当然也可以不拷贝,因为有c实现的时候可以打包后直接就加载到c的方法,但是如果不要c实现就要这些so了,下面会介绍)。
3)实现合成并调用方法安装
这里写了个在activity中运行的合成例子:
...protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); String path = Environment.getExternalStorageDirectory().getPath(); doBsPatch(this, path + "/new.apk", path + "/new.patch");}/** * 合成 * * @param latestPath 要生成的新apk位置 * @param patchPatch 增量文件位置 */public static void doBsPatch(final Context context, String latestPath, String patchPatch) { final File latestApk = new File(latestPath); final File patch = new File(patchPatch); //一定要检查文件都存在 if (!patch.exists()) { Toast.makeText(context, "合成失败", Toast.LENGTH_SHORT).show(); } new Thread(new Runnable() { @Override public void run() { // 使用native方法,是因为c的算法比java的算法要快100倍 BsPatch.bspatch(ApkExtract.extract(context), latestApk.getAbsolutePath(), patch.getAbsolutePath()); if (latestApk.exists()) { ApkExtract.install(context, latestApk.getAbsolutePath()); } } }).start();}...上面的install方法实现:
/** * 安装apk * * @param apkPath apk所在目录 */public static void install(Context context, String apkPath) { Intent i = new Intent(Intent.ACTION_VIEW); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(Uri.fromFile(new File(apkPath)), "application/vnd.android.package-archive"); context.startActivity(i); android.os.Process.killProcess(android.os.Process.myPid());}
注意声明读写权限。OK,测试图就不上了。
注意:so文件可以直接用来放到libs中对应的abi架构目录中使用,这样以后就不用再麻烦的用那么多的c文件和生成步骤了,只要在build.gradle中的android内添加:
sourceSets { main { jniLibs.srcDirs = ['libs'] }}指定jni加载的so库位置,便可以直接通过java的native方法进行使用。
三、应用
增量更新的应用还有些要注意的。
一般步骤是:
pc:生成新版本的apk-->与旧版本的apk生成增量文件。
app:检测到更新-->下载差异文件-->提取旧apk,合成-->校验文件MD5-->安装。
这里校验是有必要的,防止生成的apk无法安装,给出一个app上获取文件MD5的方法:
/** * 获取单个文件的MD5值 * * @param file 文件 * @return 文件MD5值 */ public static String getFileMD5(File file) { if (!file.isFile()) { return null; } MessageDigest digest; FileInputStream in; byte buffer[] = new byte[1024]; int len; try { digest = MessageDigest.getInstance("MD5"); in = new FileInputStream(file); while ((len = in.read(buffer, 0, 1024)) != -1) { digest.update(buffer, 0, len); } in.close(); } catch (Exception e) { e.printStackTrace(); return null; } BigInteger bigInt = new BigInteger(1, digest.digest()); return bigInt.toString(16);}
声明:参考了Hongyang大神的博客:http://blog.csdn.net/lmj623565791/article/details/52761658,同时补充自己一些实际操作。
- android 增量更新应用
- Android 增量更新实例
- android 增量更新
- android增量更新demo
- android实现增量更新
- android 增量更新
- Android 增量更新实例
- Android增量更新
- Android 增量更新APK
- Android APP增量更新
- Android之增量更新
- android增量更新
- Android增量更新
- android增量更新
- Android增量更新
- Android 增量更新
- Android UpdateApk 增量更新
- android 补丁包增量更新
- Watch The Movie
- 深度好文《武侠小说写作指南》 作者为起点副总编ZENK(上)
- DOM节点层次图
- jdk-CyclicBarrier(一)
- 23种设计模式全解析--设计模式看这一篇就够了
- Android增量更新
- GetSchema
- 深度好文《武侠小说写作指南》(下)
- ArrayList取值
- 作业1:提交ORACLE连接配置的实验报告
- 欢迎使用CSDN-markdown编辑器
- 希尔排序相关
- tomcat的优化(内存,缓存,线程数(并发),IO,)
- js小知识