Code Monkey home page Code Monkey logo

incrementallyupdate's Introduction

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

项目截图

incrementallyupdate's People

Contributors

smuyyh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

incrementallyupdate's Issues

运行demo找不到动态库为啥,是动态库没生成吗?

11-08 11:52:31.864 10343-14246/? E/dalvikvm: dlopen("/data/app-lib/com.yuyh.inc.update-1/libApkPatchLibrary.so") failed: dlopen failed: cannot locate symbol "signal" referenced by "libApkPatchLibrary.so"...
11-08 11:52:31.894 10343-14246/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.yuyh.inc.update, PID: 10343
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "signal" referenced by "libApkPatchLibrary.so"...
at java.lang.Runtime.loadLibrary(Runtime.java:364)
at java.lang.System.loadLibrary(System.java:526)
at com.yyh.lib.bsdiff.DiffUtils.(DiffUtils.java:20)
at com.yyh.lib.MainActivity$DiffTask.doInBackground(MainActivity.java:149)
at com.yyh.lib.MainActivity$DiffTask.doInBackground(MainActivity.java:143)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:841) 
11-08 11:52:32.144 2196-2196/? E/octvm: open /sys/class/power_supply/battery/status error, No such file or directory
11-08 11:52:32.149 2196-2196/? E/octvm: open /sys/class/power_supply/battery/status error, No such file or directory

同上问题.不使用您编译好的库,直接编译jni会报错

报错内容如下::

11-14 16:49:49.626 14403-14478/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: com.yuyh.inc.update, PID: 14403
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load libApkPatchLibrary from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.yuyh.inc.update-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.yuyh.inc.update-1, /vendor/lib, /system/lib]]]: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:526)
at com.yyh.lib.bsdiff.DiffUtils.(DiffUtils.java:20)
at com.yyh.lib.MainActivity$DiffTask.doInBackground(MainActivity.java:157)
at com.yyh.lib.MainActivity$DiffTask.doInBackground(MainActivity.java:151)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:841) 
11-14 16:49:49.955 1133-1216/? E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /data/data/theme/com.yulong.android.launcher3/res/drawable-xhdpi/com_yyh_lib_mainactivity.png: open failed: ENOENT (No such file or directory)
11-14 16:49:49.956 1133-1216/? E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /data/data/theme/com.yulong.android.launcher3/res/drawable-xhdpi/com_yyh_lib_mainactivity.png: open failed: ENOENT (No such file or directory)

您知道是因为什么吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.