王学岗性能优化(16)——Tinker热修复原理与手写实现


一:热修复背景
1,刚发布的版本出现了严重的Bug,这就需要去解决Bug、测试打包重新发布,这会耗费大量的人力和物力,代价比较大
2,已经更正了此前发布版本的Bug,如果下个版本是大版本,那么两个版本之间间隔时间会很长,这样要等到下个大版本发布再修复Bug,而之前版本的Bug会长期的影响用户
3,版本升级率不高,并且需要长时间来完成版本迭代,前版本的Bug就会一直影响不升级的用户
4,有一些小但是很重要的功能需要在短时间内完成版本迭代,比如节日活动
二:正常开发流程与热修复开发流程对比
在这里插入图片描述
三:热修复框架分类与对比
1,分类
阿里系:AndFix、Dexposed、阿里百川、Sophix
腾讯系:微信的Tinker、QQ空间的超级补丁、手Q的QFix
知名公司:美团的Robust、饿了么的Amigo、美丽说蘑菇街的Aceso
其它:RocooFix、Nuwa、AnoleFix
2,对比
在这里插入图片描述
四:代码修复
1,底层替换方案
在已加载的类中直接替换原有方法,是在原有类的基础上进行修改,无法实现对原有类进行方法和字段的增减,这样会破坏原有类的结构
最大问题是不稳定性,直接修改虚拟机方法实体的具体字段来实现的。Android是开源的,不同的手机厂商开源对代码进行修改,所以像Andfix就会出现在部分机型上的热修复失效的现象
2,类加载方案
APP重新启动后,让ClassLoader去加载新的类。
五:热修复优势
1,无需重新发布新版本,省时省力
2, 用户无感知修复,也无需下载最新应用,代价小
3, 修复成功率高,把损失降到最低
六:插桩原理
在这里插入图片描述

在这里插入图片描述
java文件被编译成字节码文件,然后在android中在进一步被编译成.dex文件。
DexClassLoader可以加载任何地方的dex文件,SD卡上的可以,应用私有目录也可以。出于安全考虑(有同名的危险),我们一般都放在私有目录里面
热修复就是把class打包成dex文件,把修复好的dex文件放到数组的第一位
七:dex分包
在这里插入图片描述
可以在multidex.keep中配置分包文件,哪些文件是主文件可以在这里定义
在这里插入图片描述
在gradle中设置

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.dn.lsn16_demo"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        // 开启分包
        multiDexEnabled true
        // 设置分包配置文件
        multiDexKeepFile file('multidex.keep')
    }
    dexOptions {
        javaMaxHeapSize "4g"
        preDexLibraries = false
        additionalParameters = [ // 配置multidex参数
                                 '--multi-dex', // 多dex分包
                                 '--set-max-idx-number=50000', // 每个包内方法数上限
                                 '--main-dex-list=' + '/multidex.keep', // 打包到主classes.dex的文件列表
                                 '--minimal-main-dex'
        ]
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.android.support:multidex:1.0.3'
}

(下)
八,我们看下手写怎么实现
在这里插入图片描述
这是我们的目录结构
在这里插入图片描述
现在Calculator中有一个bug,我们看下

package com.dn.lsn16_demo;

import android.content.Context;
import android.widget.Toast;

public class Calculator {
    public void calculate(Context context){
        int a = 666;
        int b = 0;
        Toast.makeText(context, "calculate >>> " + a / b, Toast.LENGTH_SHORT).show();
    }
}

我们现在假设我们已经从服务器上把修复好的类下载到了本地

发布了208 篇原创文章 · 获赞 15 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qczg_wxg/article/details/93595669