Android-->热修复,补丁实战

阅读此文之前,可以先阅读: http://blog.csdn.net/lmj623565791/article/details/49883661

在此不阐述原理, 只描述实际过程.

1:首先新建一个Android Studio Android 工程(Project)
新建2个类:

public class BugWrapperClass {//存在Bug的类, 需要被一个父类包含
    public String getBug() {
        return new BugClass().getBug();
    }
}
public class BugClass {
    public String getBug(){
        return "Is In Bug Class";//用于修复的类
    }
}
  ((TextView) findViewById(R.id.text_view)).setText( new BugWrapperClass().getBug());//调用的方法, 很简单,不详述了.

2:这个时候,需要替换BugClass.class, 步骤如下:
需要修改项目 Module 的 build.gradle 如下:

apply plugin: 'com.android.application'

//注意此处
task('insertClass') << {
    String classPath = file('build/intermediates/classes/debug')//项目编译class所在目录
    dodola.patch.PatchClass.process(classPath, project(':InsertLib').buildDir
            .absolutePath + '/intermediates/classes/debug')//第二个参数是hackdex的class所在目录
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        ...
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    //注意此处
    applicationVariants.all { variant ->
        variant.dex.dependsOn << insertClass}
}

dependencies {
    ...
}

//以下方法在,buildSrc(Moudle中),后面有下载地址;主要最用就是去除 CLASS_ISPREVERIFIED 标识

public class PatchClass {
    /** * 植入代码 * @param buildDir 是项目的build class目录,就是我们需要注入的class所在地 * @param lib 这个是hackdex的目录,就是AntilazyLoad类的class文件所在地 */
    public static void process(String buildDir, String lib) {

        println(lib)
        ClassPool classes = ClassPool.getDefault()
        classes.appendClassPath(buildDir)
        classes.appendClassPath(lib)

        println("buildDir:" + buildDir)
        println("lib:" + lib)

        CtClass c1 = classes.getCtClass("com.rsen.BugWrapperClass")//需要去除标识的类
        if (c1.isFrozen()) {
            c1.defrost()
        }
        println("====添加构造方法====")
        def constructor1 = c1.getConstructors()[0];
        constructor1.insertBefore("System.out.println(com.angcyo.insertlib.InsertClass.class);")
        c1.writeFile(buildDir)
    }
}

修改完 build.gradle之后,此时运行项目,调用代码时,会报错;
因为 InsertClass.class类,没有加载;
新建一个 lib moudle,新建一个 InsertClass.class类;如下:

public class InsertClass {
//这个类,声明了就可以
}

编译成jar, 再用dx工具,打包成dex类型的jar:
方法如下:

Make Moudle之后,会在
(Moudle根目录)\build\intermediates\bundles\debug\classes.jar 这个目录下生成jar文件

在 (Android SDK目录)\build-tools\23.0.2\dx.bat 这个目录有dx工具

通过 命令:dx  --dex --output hack_dex.jar hack.jar
可以得到 dex类型的jar

得到dex.jar文件之后,复制到项目assets目录中,通过以下代码,加载InsertClass类

public class RApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        File dexPath = new File(getDir("dex", Context.MODE_PRIVATE), "indertlib_dex.jar");
        HotFix.prepareDex(this.getApplicationContext(), dexPath, "indertlib_dex.jar");
        HotFix.patch(this, dexPath.getAbsolutePath(), "com.angcyo.insertlib.InsertClass");
        try {
            this.getClassLoader().loadClass("com.angcyo.insertlib.InsertClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//注意要在manifest.xml文件中 使用这个application哦;
//这里需要依赖 HotFix 库moudle,后面有下载地址;

此时,项目可以正常运行了;

3:打补丁
新建一个 补丁 lib moudle;创建需要修补的类

public class BugClass {
    public String getBug(){
        return "Is Patch Rsen Class";//此方法已经修改了.
    }
}

通过之前介绍的方法: 使用dx工具,获取dex类型的jar;
将得到的jar,放在项目assets目录;

4:加载补丁

  //准备补丁,从assert里拷贝到dex里
  File dexPath = new File(getDir("dex", Context.MODE_PRIVATE), "patch_dex.jar");
  HotFix.prepareDex(this.getApplicationContext(), dexPath, "patch_dex.jar");
  HotFix.patch(this, dexPath.getAbsolutePath(), "com.rsen.BugClass");//包名要一致

  Snackbar.make(findViewById(R.id.text_view), "打补丁完成", Snackbar.LENGTH_LONG)
          .setAction("Action", null).show();
  //注意,在打补丁之前,先不要调用BugClass类,否则打补丁会失败;

热修复的方法有点复杂,如果有更容易实现的方法,欢迎告之,不胜感激;

文中依赖的2个库项目,和整个项目下载地址:https://github.com/angcyo/HotFixMultiDexDemo

至此: 文章就结束了,如有疑问: QQ群:274306954 欢迎您的加入.

你可能感兴趣的:(android,补丁,热修复)