Android热修复原理和例子

概述:

热修复其实很简单,通俗理解就找到有bug的apk和无bug的apk的差异生成一个.apatch(按照AndFix使用)结尾的文件,通过预先固定的通道从网上下载无bug的代码替换有bug的代码,从而实现bug的修复,最关键的是用户体验好,如果按照正常的流程操作的话需要开发人员修复完bug后打包经过测试人员测试后,上传到多个应用市场;通过热修复的方法就省去了很大的人力物力成本。

1  热修复的原理

Android的类加载器有两种:PathClassLoader和DexClassLoader,两者的父类是BaseDexClassLoader,BaseDexClassLoader的父类是ClassLoader

其中PathDexLoader用来加载系统类和应用类;

DexClassLoader用来加载一些jar、apk、dex文件,其实jar和apk文件实际上加载的都是dex文件

热修复原理:ClassLoader会遍历一个由dex文件组成的数组,然后加载其中的dex文件,我们会把正确的dex(修复过的类所在的dex)文件插入数组的前面,当加载器加载到好 的类文件时候就不会加载有bug的类了,就实现了热修复

2 热修复例子

  本案例使用的是阿里的开源热修复框架AndFix

  1 首先建立一个App类继承自Application

public class App extends Application {
    private static final String TAG = "App";
    //生成的apatch文件名
    public static final String APATCH_PATCH = "jiang.apatch";
    private PatchManager mPatchManager;
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化
        mPatchManager = new PatchManager(this);
        String appversion=null;
        try {
            //这个地方要是用此方法获取versionName
            appversion= getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
            Log.i("aaa",""+appversion);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        mPatchManager.init(appversion);
        //加载apatch
        mPatchManager.loadPatch();
        //apatch文件的目录
        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, "补丁文件存在");
            try {
                mPatchManager.addPatch(patchFileString);
            } catch (IOException e) {
                Log.i(TAG, "打补丁出错了");
                e.printStackTrace();
            }
        }else {
            Log.i(TAG, "补丁文件不存在");
        }

    }
}
这里只是模拟,其实真正的是会通过固定的网络通道下载.apatch文件,然后进行更新

2 下面是模拟修复前和修复后的代码

修复前:

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();
            }
        });
    }
}
修复后:

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();
            }
        });
    }
}

分别打包成apk文件:bug.apk和nobug.apk(注意要对apk文件签名)

3 然后需要使用到一个生成补丁的工具apkapatch

文件目录如下

需要将签名文件放到当前文件中,使用命令

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

其中参数的意义是

-f代表修复好的apk   -t代表有问题的apk   -k代表签名文件   -p代表签名文件的密码   -a代表别名   -e代表别名密码

使用cmd命令打开后运行就会生成一个jiang的文件夹 里面就会有一个.apatch文件生成

我们利用反编译可以看看里面的内容

可以看到类名用_CF结尾,方法名用@MethodReplace注释,通过这种方式就可以找到需要替换的类和方法

4 最后看看结果吧

运行bug.apk的界面

当把jiang.apatch文件放入指定的SD目录后,重新打开app就会发现神奇一幕

以上就是热修复的简单案例,欢迎指正


  

 

猜你喜欢

转载自blog.csdn.net/oman001/article/details/76142454