At the beginning of the year, tried a hot repair technology, when the choice is Ali's Andfix, the use is very simple, here is not much, if you are interested in Andfix please link: Click to open the link. Although the online will be a lot of hot repair articles, but I still want to say the principle, and then cooperate with the code, I think we understand more deeply.
The principle is actually to use the ClassLoader loading mechanism, covering out the problem method. We know that a classloader can contain multiple Dex files, each dex file is an element, multiple Dex files are arranged into an ordered array dexelements, and when the class is found, the Dex file is traversed sequentially, Then find the class from the currently traversed Dex file, and return if the class is found. So the principle of our hot fix is to replace the problematic Dex with the new Dex, a picture of the QQ team may be more convenient to explain the principle of hot repair.
If you want to do in-depth understanding of ClassLoader students, you can go to see my previous analysis of ClassLoader: Click to open the link
Hot fix (patching) Patch: The service side through the new version of APK and the old version of the APK to generate patches (also become differential packets), the client update only need to download the differential packet to the local, and then remove the old version of the APK from System/app, through the differential package to synthesize the new version of the APK, This process is actually a patch.
Steps to Patch:
| Copy Resources |
Copy the old version apk and the new version apk to SD card. To generate a differential packet later |
| Install old version apk |
Install an older version of APK |
| Generate Patches |
Generates a differential packet. This should actually be done on the server side. |
| Hit patch |
Create a new version of the APK with the differential packet and the old version apk |
| Install new version apk |
Install the new version of the build apk |
| Get the APK installation file for an app |
During the real incremental update process, the old apk should be taken from under/data/app, copied to the SD card, and patched. Of course, you can also use the path without copying it directly. |
For convenience, we put two local locally, in order to facilitate the explanation, we define 4 variables first.
StringSrcdir= Environment.getExternalStorageDirectory ().ToString ()+ "/daemonprocess-1.apk" ;StringDestDir1= Environment.getExternalStorageDirectory ().ToString ()+ "/daemonprocess-2.apk" ;StringDestDir2= Environment.getExternalStorageDirectory ().ToString ()+ "/daemonprocess-3.apk" ;StringPatchdir= Environment.getExternalStorageDirectory ().ToString ()+ "/daemonprocess.patch" ;
Srcdir: Old version apk path. That is, the APK address of the installed legacy app. For demonstration purposes, this side writes the dead path directly. In real development to really get the old version of the APK address, can be obtained by the following code:
String appdir = Getpackagemanager (). Getapplicationinfo (PackageName, 0). SourceDir;
DESTDIR1: The new version of the APK path.
DESTDIR2: The new version of the APK path. A new version of APK is synthesized from the diff pack + old apk.
Patchdir: Differential packet. A differential packet is generated from the old version apk+ new version apk.
This generates the differential packet and the new APK, using JNI, the code is as follows: generating the differential packet native method
public class Diffutils {static diffutils instance;public static Diffutils getinstance () {if (instance = = null) instance = N EW diffutils (); return instance;} static {system.loadlibrary ("apkpatchlibrary");} The/** * Native method compares the differences between the APK and the NewPath apk path to OldPath, and generates a patch package, stored in patchpath */public native int Gendiff (String oldapkpath, String Newapkpath, String patchpath);}
To synthesize a new package native method:
public class Patchutils {static patchutils instance;public static Patchutils getinstance () {if (instance = null) instance = new Patchutils (); return instance;} static {system.loadlibrary ("apkpatchlibrary");} The/** * Native method uses the path for the Oldapkpath apk with the path of the Patchpath patch package, which synthesizes the new apk and is stored in newapkpath */public native int patch (String oldapkpath , string Newapkpath, String patchpath);}
Here is a ndk, if you need to know how to generate a dynamic library file can access the following click to open the link
Hot Patch Repair Step: 1, load Check the sub-package file from the server (we simulate here, put the differential packet under the Assert file)
Private class Copytask extends Asynctask<string, Void, integer> {@Override protected Integer Doinback Ground (String ... params) {for (int i = 0; i < params.length; i + = 2) {try { File File = new file (Params[i]); if (!file.exists ()) fileutils.createfile (file); InputStream is; OutputStream OS = new FileOutputStream (params[i]); is = Getassets (). Open (Params[i + 1]); byte[] buffer = new byte[1024]; int length = is.read (buffer); while (length > 0) {os.write (buffer, 0, length); Length = is.read (buffer); } os.flush (); Is.close (); Os.close (); } catch (Exception e) {handler.obtainmessage (1). Sendtotarget (); return null; }} handler.obtainmessage (0). Sendtotarget (); return null; } @Override protected void OnPostExecute (Integer integer) {super.onpostexecute (integer); Loadding.setvisibility (View.gone); } }2, Synthesis of new apk (JNI will automatically determine whether the composition is successful)
Private class Patchtask extends Asynctask<string, Void, integer> { @Override protected Integer Doinbackground (String ... params) { try { int result = Patchutils.getinstance (). Patch (Srcdir, DestDir2, PATCHDIR); if (result = = 0) { handler.obtainmessage (4). Sendtotarget (); return what_success; } else { handler.obtainmessage (5). Sendtotarget (); return what_fail_patch; } } catch (Exception e) { e.printstacktrace (); } return what_fail_patch; } @Override protected void OnPostExecute (Integer integer) { super.onpostexecute (integer); Loadding.setvisibility (View.gone); } }
3. Install the new apk
private void Install (string dir) { string command = "chmod 777" + dir; Runtime runtime = Runtime.getruntime (); try { runtime.exec (command);//executable permission } catch (IOException e) { e.printstacktrace (); } Intent Intent = new Intent (intent.action_view); Intent.addflags (intent.flag_activity_new_task); Intent.setdataandtype (Uri.parse ("file://" + dir), "application/vnd.android.package-archive"); StartActivity (intent); }
Service-side tools and source code are located in the server directory. Currently only in the Linux64 bit of the system compiled, other systems can be compiled by themselves. The VC can be compiled directly under Linux under direct modification makefile,windows.
Diff Tool: Generating differential packets
<!--command oldapk N ewapk patch--> ./linux-x86_64/diff daemonprocess-1.apk daemonprocess-2.apk Dp.patch
Patch Tool: Merging
<!--command oldapk newapk patch-->./linux-x86_64/patch daemonprocess-1.apk daemonprocess-3.apk Dp.patch
Code address: Click to open the link
Android incremental updates and upgrades