这篇文章的集成AS版本是2.1.3,gradle版本也是2.x版本,其实2.x版本和3.x版本的gradle差别不是很大。
文章就直接写我从开始集成到结束的整个过程,在这中间遇到的问题我会用红色标注出来。
集成Tinker当然首先是看官方文档,进入GitHub的Tinker地址tinker去查看官方文档,点击右侧的接入指南,看整个接入的过程,大概浏览了一遍,感觉头大啊,太tm麻烦了,但是没办法不学不行啊,一步步来吧。
1:项目的build.gradle中添加依赖:
buildscript {
dependencies {
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
}
}
2:在Module的gradle中添加依赖
dependencies {
//可选,用于生成application类
provided('com.tencent.tinker:tinker-android-anno:1.9.1')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.9.1')
}
...
...
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'
好,从文档上来看,基本上配置就完了,就是这么简单,然后同步一下,错误开始
问题一:
同步完毕出现了上面的报错tinkerid is not set
,然后查询tinkerid
是个什么东西,文档的解释如下
那么这个东西在哪里配置呢,这个东西是配置在Module中的gradle文件中的,具体怎么配置,比较复杂,所以一般的解决办法是导入Tinker中的例子项目tinker-sample-android
,导入以后,把它的Module中的gradle文件全部复制到自己项目中,然后在根据自己原来定义的配置去修改。
建议建个新工程,只导入sample这一个项目,因为Tinker中除了这个例子工程还有其他的工程,使用import Module
导入以后,开始出现问题
问题二:找不到is_gradle_3()
函数
上面sample工程中的gradle文件的一部分,其中有一个is_gradle_3
函数,仔细看上面的截图就能明白,这个函数其实是判断项目用的哪个版本的gradle,根据不同的版本来进行不同的依赖,但是这个函数例子中没有定义,系统也没有提供,所以只能自己来删除另一个版本的依赖语句。
问题三:找不到TINKER_VERSION
这个问题比较好解决,仔细看上面的gradle截图,为了修改版本号方便,这里使用动态引入版本的方式,在工程的gradle.properties
文件中定义就好,如下图:
然后继续同步,有可能会再次出现上面的tinkerid is not set
的错误,如果出现了这个错误,咱们就去gradle文件中找到这个id的位置,如下图:
在这里,返回了tinker_id
,首先去获取TINKER_ID
字段有没有值,如果没有,会执行gitSha()
方法返回这个id,由于我们的gradle.properties
文件中没有定义TINKER_ID
,所以会执行gitSha()
方法,返回tinker_id
,这个方法我就不截图了,这个方法返回的是git的版本号,也就是说,如果这个sample工程,你是使用git的方式clone下来的,这个方法会返回git的版本号,如果不是,就获取不到,就会报错,总而言之,这个tinker_id
是为了获取一个唯一标识,所以这里可以直接在gradle.properties
文件中定义好TINKER_ID
,如下图
好,到此,基本上,配置就集成完毕了,注意,最后要把复制过来的gradle文件修改一下,部分配置要改成原来项目中的,比如applicationId
要改成包名,由于Tinker需要自动签名,所以在gradle中也好配置好签名文件的路径。
Tinker为了能够做到热修复Application类,使用了将原来Application类隔离的方式来做的,具体见自定义Application,所以这里要使用注解的方式来完成Application的改造。
public class MyApplicationLinke extends ApplicationLike {}
@DefaultLifeCycle(application = ".MyApplication",//而这个类是真正的自定义的application,别忘了在AndroidManifest.xml中使用
flags = ShareConstants.TINKER_ENABLE_ALL,
loadVerifyFlag =false)
注意上面的注释,真正在清单文件中注释的是application
这个字段定义的类名,具体每个字段的含义,可以直接取文档中查,这里需要注意,在清单文件配置Application的name的时候,会报红,但是没有关系,因为这个类是通过注解动态生成的,所以编译的时候就可以通过。
//相当于attachBaseContext
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
}
@Override
public void onCreate() {
super.onCreate();
}
可以把原来attachbaseContext
方法中的逻辑放到onBaseContextAttached
中
之前使用到Application对象的位置,可以通过getApplication()
来替换
在application中注册Tinker
TinkerInstaller.install(this);
到此,集成完毕,开始生成基准包,基准包的意思就是我们第一次发布的apk包。
基准包使用如下图的方式来生成,可以是debug的也可以Release的,因为gradle中配置了前面文件的路径,apk生成直接就是签名了的。
生成的基准包在如下图的,build的目录下的bakApk的目录下,直接使用这个包发布即可
当线上出现了bug的时候,我们就需要生成补丁包了,直接修改bug代码,然后需要配置gradle,再生成补丁包,配置gradle如下图
把上图1的位置的apk的名称,拷贝到2的位置,也就是说,告诉Tinker,我是在哪个基准包的基础上生成的补丁包,这里需要注意:不要删掉基准包apk,因为我们每次生成补丁包都需要在基准包的基础之上,即使修复多次也是从基准包的基础上生成的。
修改完以后,如下图的方式,生成patch补丁包
生成的补丁包,在build – outputs–tinkerPatch目录下,如下图:
然后通过TinkerInstaller.onReceiveUpgradePatch(this,path);
直接加载补丁包就好了,Tinker在加载完补丁包以后,需要重启进程才能生效。
最后一个问题:第二次加载patch不生效的问题。
我在集成测试的时候,出现了第一次加载补丁是生效的,当第二次加载的时候补丁不生效,原因是版本的问题,我使用的是1.9.13版本,sample工程中使用的1.9.1,这个版本是稳定的。
好了,到此Tinker的集成就完毕了,接下来就是了解Tinker的原理的