Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

learnr27/IncrementallyUpdate

Repository files navigation

IncrementallyUpdate

Android 实现应用的增量更新和升级

原理

服务端通过新版本APK和旧版本APK生成patch补丁(也成为差分包),客户端更新的时候只需要下载差分包到本地,然后从system/app取出旧版本APK,通过差分包来合成新版本的APK,这个过程实际上就是打补丁。

步骤 内容
拷贝资源 拷贝旧版本APK以及新版本APK到SD卡。为了后面进行生成差分包
安装旧版本APK 安装旧版本的APK
生成补丁 生成差分包。这个实际上应该是在服务端完成
打补丁 通过差分包及旧版本APK生成新版本APK
安装新版本APK 安装生成的新版本APK
获取某个应用的APK安装文件 在真正的增量更新过程中,旧版本Apk应该从/data/app底下获取,拷贝到SD卡,进行打补丁。当然,也可以不拷贝,直接使用该路径。
String srcDir = Environment.getExternalStorageDirectory().toString() + "/DaemonProcess-1.apk";
String destDir1 = Environment.getExternalStorageDirectory().toString() + "/DaemonProcess-2.apk";
String destDir2 = Environment.getExternalStorageDirectory().toString() + "/DaemonProcess-3.apk";
String patchDir = Environment.getExternalStorageDirectory().toString() + "/DaemonProcess.patch";

首先来看看这四个文件的作用

srcDir:旧版本apk路径。也就是已安装的旧版应用的APK地址。为了便于演示,这边直接写死路径。若想真正获取旧版apk地址,可通过下面代码实现:

String appDir = getPackageManager().getApplicationInfo(packageName, 0).sourceDir;

destDir1:新版本的apk路径。

destDir2:新版本的apk路径。通过差分包+旧版本APK合成新版本APK。

patchDir:差分包。通过旧版本APK+新版本APK生成差分包。

NDK配置

若需自己编译jni代码,则下载NDK,并在local.properties下配置自己ndk路径

ndk.dir=/Users/yuyuhang/Documents/Android/android-ndk-r10c

build.gradle加入以下内容:

android {
 defaultConfig {
 ndk{
 moduleName "ApkPatchLibrary"
 abiFilters "armeabi", "armeabi-v7a", "x86"
 }
 }
 sourceSets {
 main {
 jni.srcDirs = ['src/main/jni', 'src/main/jni/']
 }
 }
}

若不想编译jni资源,也可直接使用项目提供的so库。在build.gradle配置so库路径,去掉jni编译相关脚本,sync now...

sourceSets {
 main {
 // jni.srcDirs = ['src/main/jni', 'src/main/jni/']
 jniLibs.srcDirs = ['libs'] // 若不想编译jni代码,可直接引用so库,ndk编译相关脚本注释掉
 }
 }

使用

调用生成差分包及合成APK的native方法。

package com.yyh.lib.bsdiff;
public class DiffUtils {
	static DiffUtils instance;
	public static DiffUtils getInstance() {
		if (instance == null)
			instance = new DiffUtils();
		return instance;
	}
	static {
		System.loadLibrary("ApkPatchLibrary");
	}
	/**
	 * 比较oldapk与newapk之间差异,并生成patch包,存储于patchPath
	 * 
	 * @param oldApkPath 示例:/sdcard/old.apk
	 * @param newApkPath 示例:/sdcard/new.apk
	 * @param patchPath 示例:/sdcard/xx.patch
	 * @return 0:成功 非0:失败
	 */
	public native int genDiff(String oldApkPath, String newApkPath, String patchPath);
}
package com.yyh.lib.bsdiff;
public class PatchUtils {
	static PatchUtils instance;
	public static PatchUtils getInstance() {
		if (instance == null)
			instance = new PatchUtils();
		return instance;
	}
	static {
		System.loadLibrary("ApkPatchLibrary");
	}
	/**
	 * 使用oldApk与patch补丁包,合成新的apk,存储于newApkPath
	 * 
	 * @param oldApkPath 示例:/sdcard/old.apk
	 * @param newApkPath 示例:/sdcard/new.apk
	 * @param patchPath 示例:/sdcard/xx.patch
	 * @return 0:成功 非0:失败
	 */
	public native int patch(String oldApkPath, String newApkPath, String patchPath);
}

服务端

服务端工具以及源码位于Server目录下。目前只在Linux64位的系统下编译,其他系统大家可自行编译。Linux下的可直接修改makefile,windows下可用VC编译。

Diff工具:生成差分包
<!--命令 oldApk newApk patch-->
./linux-x86_64/Diff DaemonProcess-1.apk DaemonProcess-2.apk dp.patch
Patch工具:合并
<!--命令 oldApk newApk patch-->
./linux-x86_64/Patch DaemonProcess-1.apk DaemonProcess-3.apk dp.patch

项目截图

About

Android 应用增量更新

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 94.8%
  • Java 5.0%
  • Makefile 0.2%

AltStyle によって変換されたページ (->オリジナル) /