First, the use of the scene
APK upgrade to save server and user traffic
Second, the principle
Since Android 4.1, Google Play has introduced an incremental update to the app that uses this upgrade method to save about 2/3 of your traffic.
Now the domestic mainstream application market also supports the incremental update of the application, the most common app Bao province traffic update.
The principle of incremental update is that the installed APK on the phone and the server side of the latest apk binary comparison, to get the difference packet (that is, two versions of the difference file), the user updates the program, only need to download the differential packet, and local use of the difference package and installed APK, the new version of the APK.
For example, the current phone has installed Weibo V1, size 12.8MB, now Weibo released the latest version of V2, size 15.4MB, we have two versions of the APK file difference ratio, we found that the difference is only 3M (may be smaller, because the differential file will also use internal compression), Then the user just need to download a 3M differential packet, using the old version of the APK and this differential packet, the synthesis of a new version of the APK, to remind users to install, do not need to download the entire package 15.4M Weibo version V2 apk.
Third, the process
This process requires both the server and client writing to complete
server: Get the latest version of Apk,called new.apk, the old version of Apk,called old.apk, through the incremental update technology to get the differential file, called Patch.patch.
client: through the network operation to the server to download the prepared differential file Patch.patch, find the current version of the data directory old.apk, through the incremental new technology to merge these two files, get new.apk.
Iv. Explanation of examples
The above procedure needs to use the server to get the differential file, but embarrassed, I will not, so I use the opportunistic way, a new project through the NDK to get the differential file, and then through another project through the NDK to merge, Of course, both the server and the simulation we ultimately need to know how the process is specifically implemented.
4.1 Preparatory work
1.NDK development technology, not yet, or would be welcome to view my NDK related article: Click to enter
2. We need to prepare two apk, a old.apk, a new.apk, used to simulate the server differential, old.apk only used TextView display the current 1.0 of the old version, old.apk in the new.apk on the basis of the current directory res/ A number of images were added to the DRAWABLE-HDPI directory to simulate capacity expansion, and the version number was changed to 2,textview Display as 2.0 new version, thus simply getting 2 new and old versions. Of course, this operation is very simple, so we provide the resources to download: old.apk and new.apk download.
3. For differential new.apk and old.apk as well as merging old.apk and Patch.patch Bsdiff files, and because Bsdiff relies on bzip2, we also need to use bzip2
In Bsdiff, BSDIFF.C is used to generate a differential packet, BSPATCH.C used to synthesize the file. These files are written in C, so you need to use NDK technology: Download locally
4.2 Analog Server Get differential file Patch.patch
Note the following development environments are eclipse.
1. Create a new Android project, then the new source folder is named Jni and do the NDK configuration for this project, which is not explained here,
2. Then copy the Bsdiff.c,bsdiff.h,bzip2 folder from the Bsdiff download to the JNI directory,
3. New class, the class name is of course arbitrary, used to load the dynamic library and generate the native method, as follows:
package com.example.serverpatch;public class PatchAPK { public native static int patchAPK(String oldFile,String newFile,String patchFile); static{ System.loadLibrary("server_patch"); }}
Of course, the server_patch here must match the so library name in the Android.mk file later. And the patchapk method requires 3 parameters, the path of the old apk, the path of the new APK, the path of the differential file.
4. Using CMD to navigate to the SRC directory of this project, enter the class package name created in the Javah +3 step, for example:
com.example.serverpatch.PatchAPK
Then refresh the project and you can see:
Copy it to the JNI directory as well
5. Copy the methods needed to implement in Com.example.serverpatch.patchapk.h to BSDIFF.C:
Of course, there is a need to give these jnienv, variables named long needless to say.
Then we'll see how it's implemented:
Jniexport jint jnicall java_com_example_serverpatch_patchapk_patchapk (jnienv *env, Jclass cls, jstring oldFile, jstring NewFile, jstring patchfile) {int argc=4; Char *ARGV[ARGC]; argv[0] ="Bsdiff"; argv[1] =(char*)(*env)->getstringutfchars (env, OldFile,0));ARGV[2] =(char*)(*env)->getstringutfchars (env, NewFile,0));ARGV[3] =(char*)(*env)->getstringutfchars (env, Patchfile,0));Printf("Old apk =%s \ n", argv[1]);Printf("New apk =%s \ n", argv[2]); printf ( "patch =%s \ n", Argv[3]); int ret = diff_main printf ( "diff_main result =%d", ret); 1]); Span class= "hljs-function" > (*env)->releasestringutfchars (env, NewFile, Argv[2]); (*env)->releasestringutfchars (env, PatchFile, argv[< Span class= "Hljs-number" >3]); return ret;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
To generate a differential file we need to use the main method in the BSDIFF.C, because I modify it to Diff_main, so you do not have to be depressed where the diff_main () function, the main function requires two parameters, the first fixed to 4, the second is the char* data, But we're passing in a string in Java, so we'll first turn it into char* through the getstringutfchars in the NDK, because there's a GC in Java, but the C language has to release itself through Releasestringutfchars.
6. Modify the BSDIFF.C < bzlib.h >
to read as follows:
#include "bzip2/bzlib.c"#include "bzip2/crctable.c"#include "bzip2/compress.c"#include "bzip2/decompress.c"#include "bzip2/randtable.c"#include "bzip2/blocksort.c"#include "bzip2/huffman.c"
Because the bzlib at this time are local, double quotes are used.
6. Write Android.mk and Application.mk. Not posted here. Just remember that the generated. So and loaded. So names are the same.
The final project style is as follows:
First in mainactivity not to do anything, run a project through the simulator, I was through the simulator. The real machine can not run, because I just want to put old.apk and new.apk in the root directory of the simulator, not to get its root directory ah, after the completion of the run will be ready to old.apk, and new.apk put into the SDcard directory, such as my simulator:
You can see that new.apk has a 5m,old.apk of 1 m, and if you don't use incremental updates, now we need to use 5M of traffic updates.
OK, now call the Navtive method in the Patchapk class in mainactivity:
Package com.example.serverpatch;Import Java.io.File;Import android.app.Activity;Import Android.os.Bundle;Import android.os.Environment;PublicClassmainactivity extends Activity { @Override protected void oncreate (Bundle savedinstancestate) {super.oncreate (savedInstanceState) ; Setcontentview (R.layout.activity_main); GETPATCHAPK (); } private void getPatchAPK () {if (environment.getexternalstoragestate ()! = null) {File sdFile= Environment.getexternalstoragedirectory (); String Sdstring=sdfile.getabsolutepath (); patchapk.patchapk (Sdstring+ "/old.apk", Sdstring+ "/new.apk", Sdstring+ "/patch.patch"); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 24
- 25
- 26
We found the directory of new.apk and old.apk just placed in the SD root directory, and added the differential file directory, of course call
patchapk.patchapk (sdstring+ "/old.apk", sdstring+ "/new.apk", sdstring+ "/patch.patch");
Need to be in a sub-thread, there is no demonstration here, the main understanding principle. Run the project last.
You can see a patch.patch file in the root directory of the SD:
Can see only 3M multipoint, here we simulate the server to get the differential file has been completed.
4.3 Client-side co-differential file
It's very close to success, so we can't be discouraged!
1. Create a new client project, followed by the next operation and the simulation server to create a differential file is almost identical, so we do not have to worry about the amount of code, can be copied, after all, this is the programmer's necessary skills. Unlike the analog server, it is:
- Put the BSPATCH.C,BSPATCH.H in the JNI directory instead of the Bsdiff series, of course bzip2 file
Clip is still retained
- New class hebingapk, of course, I do not name the standard here, do not mind, the key to see the principle:
package com.example.patch;public class hebingAPK { public native static int hbAPK(String oldFile,String newFile,String patchFile); static{ System.loadLibrary("client_patch"); }}
The header file is generated through the Javah command, and a concrete merge is implemented in the BSPATCH.C
Jniexport jint jnicall java_com_example_patch_hebingapk_hbapk (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,New0));ARGV[3] =(char*)((*env)->getstringutfchars (env, Patch,0));Printf("Old apk =%s \ n", argv[1]);Printf("Patch =%s \ n", argv[3]);printf ( "new apk =%s \ n", Argv[2]); int ret = hb_main printf ( "patch result =%d", ret); 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
- 19
- 20
- 21st
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
You can see that the code for merging and differencing is almost identical to the NDK code, except that the main function used here is main in bspatch.c, modifies it to the Hb_main function, and, of course, it needs to include < bzlib.h >
Modify the guide package in BSDIFF.C.
Final project directory style:
Finally, call the native code in Mainactivity:
PublicClassmainactivity extends Activity{ @Override protected void oncreate (Bundle savedinstancestate) {super.oncreate (savedInstanceState) ; Setcontentview (r.layout.main_layout); GETPATCHAPK (); } private void getPatchAPK () {if (environment.getexternalstoragestate ()! = null) {File sdFile= Environment.getexternalstoragedirectory (); String Sdstring=sdfile.getabsolutepath (); hebingapk.hbapk (Sdstring+ "/old.apk", Sdstring+ "/new2.apk", Sdstring+ "/patch.patch"); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
Of course, here the merge and the difference also need to be carried out in the sub-thread, here also does not demonstrate, just look at the principle.
We will need to see if the generated new2.apk can be installed and whether the size is the same as new.apk, if it is necessary to verify that the newly synthesized apk MD5 or SHA1 is correct, as correct, then guide the user to install, of course, we do not show this here.
Last run, the emulator root directory is as follows:
We can see that the new2.apk has been successfully generated, good to this our difference and merge all complete, think can point a good, thank you.
4.3 Installing new2.apk
Of course, this one is the simplest, to be installed through the ADB command.
First pull the new2.apk to the computer, open cmd, navigate to the new2.apk directory, and install it via the ADB install new2.apk:
You can see that the installation is successful and the emulator is also available, indicating that the differential and merge of this set is successful.
Incremental update to Android development