Android hot repair principle and example

Overview:

The hot fix is ​​actually very simple. It is easy to understand the difference between a bug-free apk and a bug-free apk. Generate a file ending with .apatch (used according to AndFix), and download the bug-free code from the Internet through a pre-fixed channel to replace the buggy one. The most important thing is to have a good user experience. If you follow the normal process, you need to fix the bug, package it, test it by the tester, and upload it to multiple application markets; Saves a lot of manpower and material costs.

1 The principle of hot repair

There are two types of Android class loaders: PathClassLoader and DexClassLoader, the parent class of both is BaseDexClassLoader, and the parent class of BaseDexClassLoader is ClassLoader

Among them, PathDexLoader is used to load system classes and application classes;

DexClassLoader is used to load some jar, apk, and dex files. In fact, jar and apk files actually load dex files

Hot repair principle: ClassLoader will traverse an array composed of dex files, and then load the dex files in it, we will insert the correct dex (dex where the repaired class is located) file in front of the array, when the loader loads the good dex file When the class file is loaded, the buggy class will not be loaded, and the hot repair will be implemented.

2 Examples of hot fixes

  This case uses Alibaba's open source hot repair framework AndFix

  1 First create an App class that inherits from Application

public class App extends Application {
    private static final String TAG = "App";
    // Generated apatch file name
    public static final String APATCH_PATCH = "jiang.apatch";
    private PatchManager mPatchManager;
    @Override
    public void onCreate() {
        super.onCreate();
        //initialization
        mPatchManager = new PatchManager(this);
        String appversion=null;
        try {
            //If this place uses this method to get versionName
            appversion= getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
            Log.i("aaa",""+appversion);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace ();
        }
        mPatchManager.init(appversion);
        //load apatch
        mPatchManager.loadPatch();
        //directory of apatch file
        String patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+APATCH_PATCH;
        Log.i("aaa","App:"+patchFileString);
        File apatchPatch = new File(patchFileString);
        if (apatchPatch.exists()){
            Log.i(TAG, "Patch file exists");
            try {
                mPatchManager.addPatch(patchFileString);
            } catch (IOException e) {
                Log.i(TAG, "Error patching");
                e.printStackTrace ();
            }
        }else {
            Log.i(TAG, "Patch file does not exist");
        }

    }
}
This is just a simulation. In fact, the real thing is to download the .apatch file through a fixed network channel and then update it.

2 Below is the code before and after the simulation repair

Before repair:

public class MainActivity extends AppCompatActivity {

    public Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtn  = (Button) findViewById(btn);
        String patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+APATCH_PATCH;
        Log.i("aaa",""+"MainActivity"+patchFileString);
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "出现bug了", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
After fix:

public class MainActivity extends AppCompatActivity {

    public Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtn  = (Button) findViewById(btn);
        String patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+APATCH_PATCH;
        Log.i("aaa",""+"MainActivity"+patchFileString);
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "修复bug了", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

Packaged into apk files: bug.apk and nobug.apk (note that the apk file must be signed)

3 Then you need to use a tool for generating patches, apkapatch

The file directory is as follows

You need to put the signature file in the current file, use the command

apkpatch.bat -f nobug.apk -t bug.apk -o jiang -k mzbanner.jks -p 123456 -a w -e 123456

The meaning of the parameters is

-f represents the repaired apk -t represents the problematic apk -k represents the signature file -p represents the password of the signature file -a represents the alias -e represents the alias password

After opening it with the cmd command, it will generate a jiang folder and there will be a .apatch file generated in it

We can use decompilation to see what's inside

You can see that the class name ends with _CF, and the method name is annotated with @MethodReplace. In this way, you can find the classes and methods that need to be replaced.

4 Finally, look at the results

Interface to run bug.apk

When you put the jiang.apatch file into the specified SD directory, you will find a magical scene when you reopen the app

The above is a simple case of hot repair, welcome to correct


  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325723054&siteId=291194637