网上有关于几个热修复框架的功能对比,对比下来Tinker的功能比较强大一些,但是接入麻烦;Andfix接入简单,但
没有Tinker功能多,但是,都不支持加固(用的是360加固测试的)网上已经有好多文章说怎么接入的,自己也记录
一下,加深印象。如果能帮助到一两个人,那是极好的
一、阿里Andfix
参考文章: AndFix使用说明
文章提中提到:
1.加载过的补丁会被保存到data/packagename/files/apatch_opt目录下,所以下载过来的补丁用过一次就可以删除了,在初始化版本信息的时候,每次appversion变更都会导致所有补丁被删除,如果appversion没有改变,则会加载已经保存的所有补丁;
其他参考文章:
AndFix热修复初步上手(文章中说patch文件必须放在sdcard根目录下,我没有试过放在其他路径)
比较详细的一篇:
====================================================================================
二、微信Tinker
github地址:Tencent/tinker
现在版本已经更新到1.7.7,这里以1.7.6为例。
大体上分为四步:
1.添加tinker-gradle-plugin,在project的build.gradle里添加
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.6')
如图:
====================================================================================
compile 'com.android.support:multidex:1.0.1' //可选,用于生成application类 provided('com.tencent.tinker:tinker-android-anno:1.7.6') { changing = true } //tinker的核心库 compile('com.tencent.tinker:tinker-android-lib:1.7.6') { changing = true }
如图:
然后继续修改此文件,其实就是比较一下自己的gradle和demo里的差了哪些东西,少的东西复制上去稍作修改就行;
官方文档里说要直接添加
apply plugin: 'com.tencent.tinker.patch'
for some reason, you may want to ignore tinkerBuild, such as instant run debug build
就是说可能有些情况不需要使用tinkerBuild,比如使用instant run。
整理了一下需要复制的地方:
1.在android模块里加入:
//recommend dexOptions { jumboMode = true }
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
2.在android的defalutConfig{}里加入
multiDexEnabled true buildConfigField "String", "MESSAGE", "\"I am the base apk\"" buildConfigField "String", "TINKER_ID", "\"${getTinkerIdValue()}\"" buildConfigField "String", "PLATFORM", "\"all\""加入后是这样
3.剩下的就是一股脑复制就行了,贴图说明,我没有把里面的代码展开,结构看着更清晰一些:
对上面这些东西稍作一些说明,看一下比较容易明白的。
(1)gitSha():
如果没使用git的话可以把里面的值写死,不然会报错说tinkerId没有设置;
这个方法会在getTinkerIdValue()里用到。
def gitSha() { try { // String gitRev = 'git rev-parse --short HEAD'.execute(null, project.rootDir).text.trim() String gitRev = "TINKERID" //写死 if (gitRev == null) { throw new GradleException("can't get git rev, you should add git to
system path or just input test value, such as 'testTinkerId'")} return gitRev } catch (Exception e) { throw new GradleException( "can't get git rev, you should add git to system p
path or just input test value, such as 'testTinkerId'")}}
(2)bakApk
如果使用tinkerBuild,会在项目app/build 目录下生成bakApk文件夹,里面会复制打包生成的apk、mapping文件(只在release打包会生成)以及R文件
(3)ext,加了中文注释
ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? //是否使用tinkerBuild的标志位,在下面buildWithTinker()中会用到 tinkerEnabled = true //for normal build //old apk file to build patch apk //在app/build文件夹下生成的apk文件名 tinkerOldApkPath = "${bakPath}/app-debug-0116-14-53-58.apk" //proguard mapping file to build patch apk //在app/build文件夹下生成的mapping文件,在getApplyMappingPath()使用 tinkerApplyMappingPath = "${bakPath}/" //resource R.txt to build patch apk, must input if there is resource changed //在app/build文件夹下生成的R文件,在getApplyResourceMappingPath()中使用 tinkerApplyResourcePath = "${bakPath}/app-debug-0116-14-53-58-R.txt" //only use for build all flavor, if not, just ignore this field、 //多渠道我这里没用 tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47" }
(4)getOldApkPath()、getApplyMappingPath()和getApplyResourceMappingPath()
获取生成apk,mapping和R文件的路径,默认就是路径app/build/bakApk,加ext{...}中的几个路径
(5) buildWithTinker()
是否使用tinkerBuild
(6)getTinkerBuildFlavorDirectory
多渠道相关,这里我没有用
(7)if (buildWithTinker()) {}
上图中其他部分是和多渠道有关的,这里不使用
====================================================================================
3.复制demo中的java文件
如图:
复制后会有错误重新导包就可以了;
另外,在BuildInfo类中有MESSAGE、TINKER_ID、PLATFORM几个字段,用的是BuildConfig类中的属性值。
BuildConfg是编译自动生成的(路径是:
app\build\generated\source\buildConfig\debug\com\yq\tinkertest),这几个属性是在app/build.gradle的android{...}模
块中的defaultConfig{...}中设置的,之前已经复制粘贴过了。只是我刚开始不知道这几个属性的作用,复制的时候没有
复制,导致BuildInfo中报错,所以拎出来记一下。
====================================================================================
4.自定义Application类
官方推荐的是使用注释生成Application,就按官方的来。
新建类SampleApplicationLike(名字就按照demo的取了)继承DefaultApplication,重写一些方法,做一些需要的初
始化操作(把demo中的拷过来就可以了)。
重要的是这个类上面的注释,如图:
这样,编译时会在会在app/build文件夹对应路径下生成MyApplication.class文件,在manifest.xml里引入MyApplication
就可以了。或者现在manifest.xml中引入,此时会报错,
rebuild项目,如果错误小时,说明成功。
使用中发现,如果MyApplication再多一个层级,即把上图图中的路径修改为:com.yq.tinkertest.app.MyApplication,
则始终会报找不到MyApplication的class文件的错误,不知道什么原因,有知道的大神还请指教。
清单文件中引入自定义Application后,加入读写存储权限,并注册一下tinker的服务
<service android:name=".service.SampleResultService" android:exported="false"/>
如果项目刚开始使用的是继承Application的自定义Application,在onCreate方法中做了一些初始化的工作,如init()方法:
public class MyApplication extends Application {
@Override public void onCreate() { super.onCreate(); init();//初始化操作 }}
则把init()方法里的操作放在SampleApplicationLike的onCreate方法里就可以了。
如果注释的包名和你原来的MyApplication类的包名相同,则会在编译时包class文件重复的错误。
====================================================================================
====================================================================================
至此,tinker的引入就算完成了。
接下来就是打包了,这里以打正式包为例。将混淆打开,不然没有mapping文件。
1.先打一个正式包作为初始版本,是要装到手机上的。接下来的步骤看图就可以了
在步骤3进行之前,你可以去修改bug了,就是修改代码,修改完后,执行步骤三就行了。
执行完后会在app\build\outputs\tinkerPatch路径下生成一个patch_signed_7zip.apk的差异文件,就是修复是用来加载
的补丁文件。
如果没有生成,clean一下项目重新执行步骤3。
我这里比较简单,就是两个按钮。如图:
第一个就是弹出一个toast,初始版本信息是“修改前”,修复之后信息是“修改后”,用来区分热修复时候成功。
第二个按钮就是加载补丁文件了,加载方法很简单:
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), patchPath);
从demo中拷过来就行了。
加载完成后会有提示是否成功。修复的结果可以在刚才注册的服务SampleResultService里监听,你可以根据结果做
你自己需要的操作。加载成功的话,会将补丁文件删除。
如果加载成功要想看到效果,必须杀掉进程,重启app才可以。
还有一点就是,如果修改过资源文件,如布局的xml和value中的xml,则在上上图的步骤二中一定要将R.txt文件的路径
加上,否则不会生成补丁文件。
最后一点,网上都说,补丁文件不一定要是apk文件,可以使其他扩展名的文件,因为apk文件容易被运营商劫持。
以上只是tinker的初步接入,里面还有很多细节没有理解透彻,如果有理解错的地方,还请指正!