AndFix的使用和主要点

热更新的实现方式

Dex的处理
其实就是把多个dex放进app的classloader之中,从而使得所有dex的类都能被找到,如果第一个类被找到后续的重复类就不会被加载,只要将bug的类打包成一个dex 通过反射查到该dex集合之前就可以替换后续的bug。

指针处理
在native 使用指针替换bug的方法

Bsdiff算法
通过旧的dex 和新的dex 生成一个差异 的dex在客户端通过旧的dex还原成新的dex

AndFix的使用

AndFix 是通过指针处理 ,后续会介绍 。

第一步 依赖

 compile 'com.alipay.euler:andfix:0.3.1@aar'

第二步

记得加权限
public class AliFixApplication extends Application {


    private PatchManager patchManager;

    @Override
    public void onCreate() {
        super.onCreate();
        patchManager = new PatchManager(this);
//        每次appversion变更 会删除所有的补丁,如果appversion 不变,补丁不会删除
        String s = BuildConfig.VERSION_CODE + "";
        Log.e("application", s);
        patchManager.init(s);//current version
        patchManager.loadPatch();
        addPath();
    }

    private void addPath() {
      //寻找自己目录下的补丁文件,具体项目根据网络请求做相应的处理
        String path = Environment.getExternalStorageDirectory().getPath() + "/Alarms/";
        File file1 = new File(path);
        File[] files = file1.listFiles();
        for (File file : files) {
            try {
                patchManager.addPatch(file.getPath());
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("e", e.getMessage());
            }
        }
    }

第三步
将旧的apk 和新的apk 通过 AndFix 提供了一个补丁创建工具 apkpatch. 做后续处理

通过命令行来生成

apkpatch.bat -f bug.apk -t new.apk -o patch -k key.store -p 
123456 -a Hot-fix -e 123456
具体含义 
-f 新版本apk 即修复后的apk 
-t 旧版本apk 即修复前的apk 
-o 差分包即patch 补丁文件存放的文件夹当前为patch 文件夹 
-k keystore 
-p 使用密码当前是123456
-a alias 
-e alias 对应的密码当前是123456

将生成 的文件放到手机对于的目录下加载就可以了
生成的xxx.apatch 是个解压包 里面也有一个dex文件

AndFix的原理

MethodReplace 是个注解,表明了方法名和类,他的目标也是一个方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodReplace {
    String clazz();

    String method();
}
    private void fixClass(Class<?> clazz, ClassLoader classLoader) {
        Method[] methods = clazz.getDeclaredMethods();
        MethodReplace methodReplace;
        String clz;
        String meth;
        for (Method method : methods) {
            methodReplace = method.getAnnotation(MethodReplace.class);
            if (methodReplace == null)
                continue;
     //通过注解获取进行替换,说明他的的工具帮我们自动加上注解
            clz = methodReplace.clazz();
            meth = methodReplace.method();
            if (!isEmpty(clz) && !isEmpty(meth)) {
                replaceMethod(classLoader, clz, meth, method);
            }
        }
    }

//到了 AndFix.initTargetClass(clzz); AndFix.addReplaceMethod(src, method);是ntaive的方法看不了 就跑到被人的github下看下
private void replaceMethod(ClassLoader classLoader, String clz,
            String meth, Method method) {
        try {
            String key = clz + "@" + classLoader.toString();
            Class<?> clazz = mFixedClass.get(key);
            if (clazz == null) {// class not load
                Class<?> clzz = classLoader.loadClass(clz);
                // initialize target class
                clazz = AndFix.initTargetClass(clzz);
            }
            if (clazz != null) {// initialize class OK
                mFixedClass.put(key, clazz);
                Method src = clazz.getDeclaredMethod(meth,
                        method.getParameterTypes());
                AndFix.addReplaceMethod(src, method);
            }
        } catch (Exception e) {
            Log.e(TAG, "replaceMethod", e);
        }
    }

然后跑到https://github.com/alibaba/AndFix/blob/master/jni/art/art_method_replace_6_0.cpp AndFix的github地址



 void replace_6_0(JNIEnv* env, jobject src, jobject dest) {
   。。。。
  // 把原方法的各种属性都改成补丁方法的
    smeth->declaring_class_ = dmeth->declaring_class_;
    smeth->dex_cache_resolved_types_ = dmeth->dex_cache_resolved_types_;
    smeth->access_flags_ = dmeth->access_flags_;
    smeth->dex_cache_resolved_methods_ = dmeth->dex_cache_resolved_methods_;
    smeth->dex_code_item_offset_ = dmeth->dex_code_item_offset_;
    smeth->method_index_ = dmeth->method_index_;
    smeth->dex_method_index_ = dmeth->dex_method_index_;
  // 把原方法的各种属性都改成补丁方法的
    smeth->ptr_sized_fields_.entry_point_from_interpreter_ =
            dmeth->ptr_sized_fields_.entry_point_from_interpreter_;

    smeth->ptr_sized_fields_.entry_point_from_jni_ =
            dmeth->ptr_sized_fields_.entry_point_from_jni_;
    smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_ =
            dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
     。。。。
}
别人的实现大致是这个样子的

个人总结

AndFix支持2.3-6.0
AndFix支持启动应用就可以做更新

缺点

跳过了类初始化,对于静态或者构造函数或者class.forname()的处理可能会有问题
不能实现类替换,资源替换等
对加载过的补丁文件要做名字修改 如果名字重叠 就不会再次加载

参考文章

http://blog.csdn.net/watermusicyes/article/details/50529461
http://blog.csdn.net/xxooyc/article/details/50317455
http://www.open-open.com/lib/view/open1453255144980.html
http://blog.csdn.net/u010299178/article/details/52031505

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值