Transferred from: http://blog.csdn.net/lmj623565791/article/details/52761658
This article starts with my public number: Yang (hongyangandroid).
Reprint please indicate the source:
http://blog.csdn.net/lmj623565791/article/details/52761658;
This article is from: "Zhang Hongyang's Blog"
I. Overview
Recently focused on hot fix things, occasionally chatting about incremental updates, of course two is not a thing at all. Take this to find some information, collect and tidy up, originally did not want to write blog, because the main is the realization of the tool, but last night in the collation of information, suddenly found that I was about to forget this thing, but also from the beginning to find a circle of tools.
So, right when a record, also convenient later to find themselves.
The first thing to be clear is, what is an incremental update:
I'm sure you've all seen it. In the app market, a hundreds of m software may only need to download a 20M incremental package to complete the update. So how does it work?
Is the topic of this blog.
Incremental update process is: The user's phone installed an application, download the incremental package, the APK and the incremental package on the phone to form a new package, and then install again (note that the process is to reinstall, of course, some of the application market has root authority you may not perceive).
OK, then the entire process is refined into several key points:
- The APK for the currently installed app is extracted on the user's phone
- How to generate delta files using old.apk and new.apk
- Add files with 1. old.apk in the merge, and then install
Solve the above 3 problems, OK.
The following begins to solve, first we look at the incremental file generation and merger, this link can be said to be the core of the process, but also the technical difficulties, it is worth happy that the technical difficulties have been the tool for us to achieve.
Two, incremental file generation and merging
This is actually a diff and patch that uses the tool to do binary binary.
Url:
- http://www.daemonology.net/bsdiff/
:
- Http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz
By the way, the environment for Mac, the other system if the obstruction, slowly search solution can be.
Download OK, unzip, cut to the corresponding directory, and then execute make:
aaa:bsdiff-4.3 zhy$ makeMakefile:13: *** missing separator. Stop.
Well, you have not read wrong, error, this mistake is better solved.
Unzip the file there is a file: Makefile, opened as text, will install: The following if,endif add an indentation.
The modification is done this way:
CFLAGS+=-o3 -lbz2prefix ?=/usr/localinstall_program ?= ${install} -c -s -m 555INSTALL_MAN ?= ${install} -c -m 444all:bsdiff bspatchbsdiff:bsdiff.cbspatch : Bspatch.cinstall: ${install_program} bsdiff bspatch ${prefix}/bin .ifndef Without_man ${install_man} bsdiff.1 Bspatch .1 ${prefix}/man/man1 .endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
Then, re-execute make:
aaa:bsdiff -4.3 zhy$ makecc -O3 -lbz2 bsdiff.c -o bsdiffcc -o3 -lbz2 bspatch.c -o bspatchbspatch.c: 39: 21:error:unknown type name ' U_char ‘; Did you mean ' char ' ?static off_t offtin (U_char *buf) ^~~~~~ char
This time is better than the last time, this time generated a bsdiff, but in the generation of Bspatch error, fortunately, we only need to use Bsdiff, why say so?
Because generating delta files is definitely done on the server, or on our local PC, using the Bsdiff tool;
Another bspatch, merging old.apk and Delta files is definitely done inside our app.
Of course this problem can be solved, search, a lot of solutions, we will not continue to waste space on this.
I offer here A:
https://github.com/hymanAndroid/tools/tree/master/bsdiff-4.3
Download complete, direct Make,bsdiff and Bspatch will be generated (in Mac environment).
============= Magical Split-line ==============
OK, assuming here, no matter what method you use, we already have Bsdiff and BSPACTH, the following shows the use of this tool:
First we prepare two apk,old.apk and new.apk, you can write your own project, first run to get the APK as old.apk, and then modify some code, or add some features, and then run a build new.apk;
old.apk new.apk old-to-new.patch
This generates a delta file Old-to-new.patch
- Incremental files and OLD.APK merged into the new APK
old.apk new2.apk old-to-new.patch
This generates a new2.apk
So how do we prove that the generated new2.apk is exactly the same as our new.apk?
We can look at the value of the next MD5, if the two files md5 the same value, then almost sure two files are exactly the same (don't tell me what collision can produce the same MD5 value ~ ~).
aaa:bsdiff-4.3 zhy$ md5 new.apk MD5 (new.apk) = 0900d0d65f49a0cc3b472e14da11bde7aaa:bsdiff-4.3 zhy$ md5 new2.apk MD5 (new2.apk) = 0900d0d65f49a0cc3b472e14da11bde7
You can see the MD5 of two files exactly the same ~ ~
Well, suppose you're not a Mac, how do you get a file for MD5? (Write your own code, download tools, do not encounter such problems, also pop windows I, I will be deducted pay ...) )
So here we know how to generate delta files and merge patches with old files into new files. Then we comb the whole process again:
- The server has already done the incremental file (this section completes)
- Client Download Delta file + extract apk for the app, merge with Bspatch
- Generated by the new APK, invoke the installer
Still pretty clear, then the main is 2nd, 2nd there are two things, one is the application of the APK, one is to use bspatch merge, then this merger is definitely need to native method and so file to do, that is, we have to make a so out;
III. client Behavior (1) Extract app apk file
In fact, extracting the current app apk is very simple, the following code:
public class ApkExtract { public static String extract(Context context) { context = context.getApplicationContext(); ApplicationInfo applicationInfo = context.getApplicationInfo(); String apkPath = applicationInfo.sourceDir; Log.d("hongyang", apkPath); return apkPath; }}
(2) Making Bspatch so
First declare a class, write a native method, as follows:
public class BsPatch { static { System.loadLibrary("bsdiff"); } public static native int bspatch(String oldApk, String newApk, String patch);}
Three parameters are already clear;
Also, don't forget to build.gradle the module:
{ ndk { moduleName = ‘bsdiff‘ }}
Note that this step requires you to configure the NDK environment (download NDK, set Ndk.dir) ~
OK, the next step is to complete the C code to write;
First, create a new folder in the App/main directory JNI, the previously downloaded bsdiff in the bspatch.c copy in;
Then follow the JNI rules and create a new method inside:
Jniexport jint jnicall java_com_zhy_utils_bspatch_bspatch (jnienv *env, Jclass cls, jstring old, jstringNew, jstring patch) {int argc =4; char * ARGV[ARGC]; argv[0] ="Bspatch"; argv[1] =(char*)(*env)->getstringutfchars (env, old,0));ARGV[2] =(char*)(*env)->getstringutfchars (env,new, 0)); argv[3] = (char*) ((*env)->getstringutfchars (env, Patch, 0)); int ret = patchmethod(argc, argv); (*env)->releasestringutfchars (env, old, argv[1]); (*env)->releasestringutfchars (env, New, argv[2]); (*env)->releasestringutfchars (env, Patch, argv[3]); return ret;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
The method name is regular, the law does not have to mention it ~ ~
Note that there is no Patchmethod method in Bsdiff.c, this method is actually the main method, directly modified to Patchmethod can, feel complex does not matter, the text at the end of the source.
OK, at this point you can try to run, you will be prompted to rely on bzlib, in fact, from the top of the file include can also be seen.
Since it depends, let's import it:
Download First:
- Http://www.bzip.org/downloads.html
- Http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
After the download is complete, unzip:
Extract the. h and. c files, and then select the folder copy to our module's app/main/jni, the result is as follows:
Remember to modify the include in Bsdiff:
#include "bzip2/bzlib.h"
Run again;
Then you will find a bunch of errors similar to the following:
`main‘
It is suggested that the main method is repeatedly defined, and in the error message, which classes contain the main method, you can choose to directly delete the Main method in those classes.
After the deletion, it's OK ~ ~
So here, we finished the JNI writing, of course, the file is Bsdiff to provide C source code.
Iv. Installation after incremental update
When the above operation is complete, the last step is simple, first prepare two apk:
old.apk new.apk
Then make a patch, Patch.patch in the code below;
Install the old.apk and place the new.apk and Patch.patch on the memory card;
Finally, the call is triggered in the activity:
private Span class= "Hljs-keyword" >void dobspatch () {final File destApk = new File (Environment.getexternalstoragedirectory (), final file patch = new file ( Environment.getexternalstoragedirectory (), "Patch.patch"); //be sure to check that the file exists Bspatch.bspatch (apkextract.extract (this), Destapk.getabsolutepath (), Patch.getabsolutepath ()); if (destapk.exists ()) Apkextract.install (this, Destapk.getabsolutepath ()); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Remember to turn on read and write SDcard permissions, remember that in the code to test the required files are present.
The install is actually installed through intent:
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); }
Here 7.0 may have a problem, exposing the path to other apps, should need to fileprovider to implement (no experiment, speculation may be possible).
Roughly the following:
V. Summary
If you just want to use this function, large can directly copy the resulting so file into, directly LoadLibrary use.
Second, in the incremental update, patch is definitely based on your current version number and the latest (or target) version of the APK, compared to the issued diff file, at the same time should also be the target apk MD5 issued, and then after the merger, do not forget to check the MD5;
Blog end, although very simple, the main use of tools to achieve, but it is recommended to implement one-time, want to run through or take a few hours, may also find some pits in the process, but also to improve their own degree of JNI proficiency.
Source:
- Https://github.com/hongyangAndroid/BsDiff_And_Patch
You can also choose to use so directly
- Https://github.com/hongyangAndroid/BsDiff_And_Patch/tree/master/so-dist
Welcome to follow my Weibo:
http://weibo.com/u/3165018720
Android incremental update full resolution is delta not hot fix (RPM)