注意标题 Java层原理和实现###

在说到热修复之前,先简单说下android的apk生成的一个原理,我们都是知道android是Java语言写的,那么.java文件和.class文件大部分人应该都不会陌生,其实从Java文件到apk文件经历了以下的过程

这是java文件到apk文件的四部曲,其实.java .class .apk文件我们都非常熟悉,我们写的代码是java,.java文件经过编译之后变成.class文件,.apk文件android手机可以直接安装,但是 .dex文件是个神马鬼?其实..apk文件是.dex文件编译过来的 ,最通俗的解释。

然后我们就说说热修复:热修复主要是修复一些非常紧急的问题,比如说严重的逻辑错误或是严重的闪退等,或者像当年某宝屏蔽某快递一样,热修复的本质又是啥子了 ??? 用一句非常通俗易懂的话就是:运行时,方法替换

讲多了 。。 都是浮云, 原理知道了之后我们就来撸代码。。。。。 首先我们得明确一点,运行时方法替换这种事情Java是办不了的。。。 ,还有就是,你要使用热修复,那么很显然,你必须未雨绸缪先做好准备,也就是在软件设计的最初级策划阶段就要考虑进去,不可能说我线上版本出现了问题,我之前代码没有集成热修复工具,我现在要热修复,我只能微微一笑,根本不鸟 。。。。

开始撸代码 。。。。

新建项目的时候 C++ 支持,勾上 ,上面说到 runtim的时候替换方法,这个Java解决不了, 只能有 C 来解决了 。。。。。

1 定义native方法

刚刚说了 ,热修复的本质是两个方法在runtime的时刻动态交换, 所以我们需要搞一个类让两个Java方法交换 ,当然这个方法肯定是 native的 。。。

package hebiao.online.hot;import java.lang.reflect.Method;/** * Created by apple on 2018/3/17. */public class MethodUtil {    static {        System.loadLibrary("native-lib");    }    /**     *     * @param m1  原来的方法     * @param m2  新的方法 ,dex 文件中的方法     */    public  static native void changeMethod(Method m1,Method m2);}

既然有 native方法 那么必须有对应的 C++ 的 代码和方法

#include extern "C"{JNIEXPORT void JNICALLJava_hebiao_online_hot_MethodUtil_changeMethod(JNIEnv *env, jclass type, jobject m1, jobject m2) {}}

方法交换我们搞完了 , 注意这里 C++ 的方法我没有实现,我们的主题是 Java层面上的原理和实现,C++ 实现真心蛋疼,毕竟C++ 不是Java程序猿的专长

2 定义被修复的标记

方法交换我们撸好之后,我们需要干的第二个事情就是 ,定义被修复的标记 ,也就是告诉更新包(即.dex)文件更新的位置,以及要替换的部分

package hebiao.online.hot;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)  /// 作用的方法上 @Retention(RetentionPolicy.RUNTIME)  /// 运行时,这个不解释public @interface HotFixInterface {    String clazz();  /// 被修复的类    String method(); /// 被修复的方法}

3 生成补丁文件 .dex

这一步是比较重要的 ,在生成补丁文件之前,我们先来看看要被修复的文件

以上是 ,要被修复的文件中的要被修复的方法 , 我们看下补丁文件 。。。

然后就是生产 .dex 文件了 。。。。 我们上面说到 .dex 是有 .class 文件生产的 也就是说我们首先要将.class文件编译出来 。。。。

我们只需要这个 .class文件 ,可以把其他的 都删掉 。。。 像这样 。。。

然后就是 ,把.class 文件 编译成 .dex 文件了 。。。 这个其实 android studio提供了 一个编译工具 。。。

有一个 叫 dx 的 工具 , AS 自带的 。。 注意版本就行 。。。。 那么怎么使用了????

首先进入到 debug的目录 ,然后执行

appledeiMac:debug apple$ pwd/Users/apple/Desktop/hot/app/build/intermediates/classes/debugappledeiMac:debug apple$ /Development/AS/build-tools/26.0.2/dx --dex --output=./hot.dex hebiao/online/hot/nact/MainActivity.class

/Development/AS/build-tools/26.0.2/dx :根据你自己的环境变量
–output=./hot.dex :输出目录
hebiao/online/hot/nact/MainActivity.class class 的目录

执行完之后 ,会发现多一个文件 。。

这个文件就是 热修复的更新包,也就是更新文件了 。。。。
我们需要读取这个文件的里面的热修复方法,来修复本地存在的问题或在是错误

4 加载补丁文件 .dex

我们在生成 修复包的时候 发现热修复是通过注解来标记要修复的文件,我们可以通过读取.dex文件来找到哪个类中的哪个文件是要我们去修复。。。。我们来画一张图

这就是热修复的 整个的 一张图 。。。。。。

package hebiao.online.hot;

import android.content.Context;

import java.io.File;
import java.lang.reflect.Method;
import java.util.Enumeration;

import dalvik.system.DexFile;

/**
* Created by apple on 2018/3/17.
*/

public class DexFileManager {

private Context context;public DexFileManager(Context c){    this.context = c;}/** * 加载 dex文件 */public void loadDexFile(File file) {    try{        /**         * 加载dex文件 ,三个参数         * 第一个参数 : 文件绝对路径         * 第二个参数: 临时缓存文件         * 第三个参数:默认         */        DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),new File(context.getCacheDir(),"opt").getAbsolutePath(),Context.MODE_PRIVATE);        /**         * 遍历 dex中的类         */        Enumeration entry = dexFile.entries();        while (entry.hasMoreElements()){            String className = entry.nextElement();            System.out.println(" ++$########### " +className);            Class fixClass = dexFile.loadClass(className,context.getClassLoader());            fixMethonAction(fixClass);        }    }catch (Exception e){    }}/** * 撸这个类, * @param fixClass  ,这个类是 dex 文件中的 ;注意!!!!!! */private void fixMethonAction(Class fixClass) throws Exception{    /**     * 找到 dex文件中类的所有方法     */    Method[] methods = fixClass.getDeclaredMethods();    for (Method m: methods) {

// HotFixInterface hf = m.getAnnotation(HotFixInterface.class);

        HotFixInterface hf = m.getAnnotation(HotFixInterface.class);        if (hf == null){            continue;        }        /**         * 若找到 dex文件中类 的注解,则说明这个方法需要被修复或替换         */        String wrongClassName = hf.clazz();        String wrongMethodName = hf.method();        /**         * 获取 旧的, 需要被修复的 方法         */        Class wrongClass = Class.forName(wrongClassName);        Method wrongMethod = wrongClass.getDeclaredMethod(wrongMethodName,m.getParameterTypes());        System.out.println( "   **************   "+wrongClass.getName()+"     wrongMethod ===  "+wrongMethod.getName());       /**         * 方法将 正确的方法和错误的方法交换 。。。         */        System.out.println("-------start---------111");        MethodUtil.changeMethod(wrongMethod,m);    }}

}

5 启动热修复

你想怎么启动都行。 。。。。

 public void load(View v){        DexFileManager dexFileManager = new DexFileManager(this);        String name = getSdCardPath()+"/aaa/hot.dex";        File file = new File(name);        if (file.exists()){            System.out.println("xxxxxxxxxxxxx  文件存在");            dexFileManager.loadDexFile(file);        }else {            System.out.println("瞎了 。。。。 ");        }    }    public static boolean isSdCardExist() {        return Environment.getExternalStorageState().equals(                Environment.MEDIA_MOUNTED);    }    public static String getSdCardPath() {        boolean exist = isSdCardExist();        String sdpath = "";        if (exist) {            sdpath = Environment.getExternalStorageDirectory()                    .getAbsolutePath();        }        return sdpath;    }

以上就是 热修复Java的 原理和实现, 但是 热修复的重点是理解这个流程 , 难点在 C++ 端 。。。。
另外附上代码 : https://github.com/hebiao6446/hotFix

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. NPM 和webpack 的基础使用
  3. Python list sort方法的具体使用
  4. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  5. python list.sort()根据多个关键字排序的方法实现
  6. Android开发中AsyncTask实现异步处理任务的方法
  7. Android应用程序的快速启动
  8. 想抢先体验Android操作系统的魅力吗?那就使用Android(安卓)LiveCD
  9. 一个使用FFmpeg库读取3gp视频的例子-Android中使用FFmpeg媒体库

随机推荐

  1. Android资源文件-Shape
  2. #Android学习#android:src=""的用法
  3. 开发SpringMVC+MyBatis项目001
  4. 用 Eclipse + GDB调试Android中C/C++程序
  5. Android系统文件夹结构的说明
  6. android switch(String)错误:Cannot switch
  7. Android(安卓)UI设计——画廊Gallery与提
  8. Android(安卓)应用性能优化
  9. Compile a native C Android(安卓)applic
  10. Cannot run program "svn" (in directory