首先我们要知道为什么使用热修复?
热修复就是让用户不知道的情况下对App进行打补丁修复,比如用户反馈发现重大bug然后就会找到程序员进行及时修改,对App进行修复然后再从新打包上线,这样比较耗费人力,所以就出现了热修复,通过事先定设定的借口从网上下载无bug的代码来替换有bug的代码,这样比较省事用户体验也好,尤其是对于用户量多的App,一个bug不只是影响到几个几十个用户,一些创业公司的APP,崩溃或者bug可能直接导致用户卸载和永不使用所以我们的app也要适当考虑加入热修复
Tinker呢是基于类加载来实现的,对于底层我也不太懂,简单介绍一下
前提是不必须保证Apk的主包没有问题,可以跑得起来
首先有一个系统原有的Apk,然后我们自身也有一个类加载器加载和系统一样的apk进行对比,然后通过事先定义好的接口去下载没有问题的文件包,加载到自身进行合并,并且提升自己的优先级,让这个Dex文件排在dexElements数组前面 然后通过反射插入到系统的dexElements数组中,而ClassLoader加载到正确的类之后就不会去加载有bug的类了,然后让类加载器重新加载。
Android的类加载器分为两种 PathClassLoader和DexClassLoader 都继承BaseDexClassLoader
PathClassLoader用来加载系统类和应用类
DexClassLoader用来加载jar ,apk, dex文件,加载jar,apk也是最终抽取里面的Dex文件进行加载
基于ClassLoader的双亲委托模型,给原ClassLoader设置parent ClassLoader,这样查找类时,会优先会使用parent ClassLoader去加载补丁类,其余类交给原ClassLoader.
将补丁Dex路径插入到原ClassLoader的DexPathList的最前面,由于ClassLoader查找类时会顺序遍历Dex,所以补丁Dex会先于旧文件被查找到.
再来奉上UML:
优点:
合成整包,不用在构造函数插入代码,防止Verify和opt在编译期间就已经完成性能提高,兼容性和稳定性比较高开发者明确不用对包进行额外处理应用场景多 支持类/so/资源的修复,可支持用户调试,版本升级,发布需求厂商支持 受益于微信的影响力与华为厂商在thinker兼容性的问题上建立联系加固支持 联合乐加固/360/爱加密等加固厂商支持热修复加固方案缺点:
和超级补丁技术一样,不支持即时生效,必须重启才能生效需要给应用开始新的线程才能进行合并,并且容易因为内存消耗等原因合并失败合并时占用额外磁盘空间,对于多DEX的应用来说如果修改了多个Dex文件就需要下发多个patch.dex与对应的classes.dex进行合并操作时这种情况会更严重,因此合并过程的失败率也会变高好!
我们一步一步来 :接下来是集成步骤 超级详细:
第一步:去AS中创建个Demo 哈哈哈 惊喜吧
第二步:
图一:在项目的build.gradle中添加一个依赖
图二:在App的gradle添加依赖
图二:需要在App的gradle中引用的一个gradle文件的依赖
添加完之后进行编译,这个时候可能会报错,具体什么错误我忘记了,一个可以通过降低gradle版本号来解决,调成3.2.1(如上图所示),还有一个就是关于javaJDK的问题 这个问题需要添加一行代码(如下所示)
然后还要添加权限
接下来我把需要添加的依赖给你们复制出来 方便你们复制粘贴
//在项目gradle中添加的库 classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.13" //在App的gradle中添加的Tinker核心依赖库 compileOnly("com.tinkerpatch.tinker:tinker-android-anno:1.9.13.2") implementation("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.13.2") //需要引用一个gradle文件 apply from: 'tinkerpatch.gradle' //报错加入的代码 javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } 依赖添加完之后还需在AndroidManifest.xml添加权限 不多就三个 <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>需要在你的AppLication类中进行初始化Tinker的SDK,不初始化没办法用啊
public class TinkerApplication extends Application { private ApplicationLike tinkerApplicationLike; @Override public void onCreate() { super.onCreate(); if (BuildConfig.TINKER_ENABLE) { // 我们可以从这里获得Tinker加载过程的信息 tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike(); // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK TinkerPatch.init(tinkerApplicationLike) .reflectPatchLibrary() .setPatchRollbackOnScreenOff(true) .setPatchRestartOnSrceenOff(true); // 每隔3个小时去访问后台时候有更新,通过handler实现轮训的效果 new FetchPatchHandler().fetchPatchWithInterval(1); } } }接下来就是MainActivtiy了 没什东西 两个按钮,用来测试是否修复成功的(代码就不贴了)
对了!还有一个重要的文件,tinkerpatch.gradle 这个文件去官方的Demo中去下载就可以了,然后放到自己的App目录下
第一个固定的没什么,第二个得详细说一下,我们每打一次补丁包左侧就会多出一个,你本次去Tinker平台发布补丁这里一定要上次的文件夹名,记住一定要是上次的文件夹名,因为是基于上次的基础上改的bug OK? 了解了嘛?
下面我来说一下怎么打补丁包
在AS右侧有个gradle 点开会有如下所示的列表 ,图中我选中的就是打补丁包的位置,双击就行傻瓜操作
接着我来说打好补丁包后来发布补丁:
选择文件:
打开你的Project目录,按照图中的目录找 选择那个图中选中的 然后发布就可以了
然后进行测试 在Tinker官网有实时监控 可以看是否成功等等一些参数:
好啦,够详细吧!我也是第一次弄 所以记录一下 ,图中的gradle文件也可以找我要,或者哪里不够清楚我们也可以互相讨论