前言
做前端开发的都知道,当我们项目做完了以后,都会把应用上传到应用市场上供用户下载使用,比如上传到应用宝啊,应用汇啊,360啊,小米,华为,魅族啊,等等
但是,有时候我们会经常遇到一些很扯淡的事情,刚刚熬夜加班将项目发到应用市场上,第二天,又发现一个严重bug,难道是开会研究看看是否能在下一版解决?还是将bug解决了,
在给测试进行测试,然后再发版?如果从新发版,这个成本太高了,那怎么办呢,今天我们就来谈一谈热修复——Tinker!
现在市场上的热修复工具或者框架有很多很多,比较出名的有阿里的 AndFix、美团的 Robust 以及 QZone 的超级补丁方案。这个方案各有利弊,但是今天我们不说这几个方案,我们来聊一聊另一个补丁方案——Tinker。首先我们上一张图:
Tinker热补丁方案·不仅支持类、So以及资源的替换,它还是2.X-7.X的全平台支持。
在官网上,介绍这个Tinker,用了一句话:Tinker 已运行在微信的数亿 Android 设备上,那么为什么你不使用 Tinker 呢? ps:别人几亿的用户量在用Tinker,都不担心出现什么问题,
你们几个用户量的应用,还整天瞎担心。
这篇文章,主要是和大家聊一下怎么集成这个Tinker,并不会设计很多原理的东西,如果需要了解更深入的原理性的东西,可以到官网看看。点击官网http://tinkerpatch.com/Docs/intro
集成SDK
第一步 添加 gradle 插件依赖
在项目的Gradle添加远程依赖
1 buildscript {
2 repositories {
3 jcenter()
4 }
5 dependencies {
6 classpath 'com.android.tools.build:gradle:2.3.2'
7 // TinkerPatch 插件
8 classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.8"
9 // NOTE: Do not place your application dependencies here; they belong
10 // in the individual module build.gradle files
11 }
12 }
第二步 集成 TinkerPatch SDK
在app中的gradle添加denpendencies 依赖,注意:这两个gradle不是同一个gradle,上面的那个build gradle 是整个项目的,下面这个build gradle是在app里面的,注意区分
1 dependencies {
2 // 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
3 provided("com.tinkerpatch.tinker:tinker-android-anno:1.8.0")
4 compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.8")
5 }
注意,若使用 annotation 自动生成 Application, 需要单独引入 Tinker 的 tinker-android-anno 库。除此之外,我们无需再单独引入 tinker 的其他库。
为了简单方便,我们将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中, 我们需要将其引入:
1 apply from: 'tinkerpatch.gradle'
第三步 配置 tinkerpatchSupport 参数
好了,接下来我们就在app目录下创建这个tinkerpatch.gradle,如图所示的目录

打开tinkerpatch.gradle,将 TinkerPatch 相关的配置都放于tinkerpatch.gradle中。
1 apply plugin: 'tinkerpatch-support'
2
3 /**
4 * TODO: 请按自己的需求修改为适应自己工程的参数
5 */
6
7 //基包路径
8 def bakPath = file("${buildDir}/bakApk/")
9 //基包文件夹名(打补丁包的时候,需要修改)
10 def baseInfo = "app-1.0.1-1018-17-29-31"
11 //版本名称
12 def variantName = "debug"
13
14 /**
15 * 对于插件各参数的详细解析请参考
16 *
17 */
18 tinkerpatchSupport {
19 //可以在debug的时候关闭 tinkerPatch
20 tinkerEnable = true
21 //是否使用一键接入功能 默认为false 是否反射 Application 实现一键接入;
22 // 一般来说,接入 Tinker 我们需要改造我们的 Application, 若这里为 true, 即我们无需对应用做任何改造即可接入。
23 reflectApplication = true
24 //将每次编译产生的 apk/mapping.txt/R.txt 归档存储的位置
25 autoBackupApkPath = "${bakPath}"
26 appKey = "这里的appKey修改成你自己的appkey"// 注意!!! 需要修改成你的appkey
27
28 /** 注意: 若发布新的全量包, appVersion一定要更新 **/
29 appVersion = "1.0.1"
30
31 def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
32 def name = "${project.name}-${variantName}"
33 /**
34 * 基准包的文件路径, 对应 tinker 插件中的 oldApk 参数;编译补丁包时,
35 * 必需指定基准版本的 apk,默认值为空,则表示不是进行补丁包的编译
36 */
37 baseApkFile = "${pathPrefix}/${name}.apk"
38
39 /**
40 * 基准包的 Proguard mapping.txt 文件路径, 对应 tinker 插件 applyMapping 参数;在编译新的 apk 时候,
41 * 我们希望通过保持基准 apk 的 proguard 混淆方式,
42 * 从而减少补丁包的大小。这是强烈推荐的,编译补丁包时,我们推荐输入基准 apk 生成的 mapping.txt 文件。
43 */
44 baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
45 /**
46 * 基准包的资源 R.txt 文件路径, 对应 tinker 插件 applyResourceMapping 参数;在编译新的apk时候,
47 * 我们希望通基准 apk 的 R.txt 文件来保持 Resource Id 的分配,这样不仅可以减少补丁包的大小,
48 * 同时也避免由于 Resource Id 改变导致 remote view 异常
49 */
50 baseResourceRFile = "${pathPrefix}/${name}-R.txt"
51 /**
52 * 若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample
53 * 注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)
54 **/
55 }
56
57 /**
58 * 用于用户在代码中判断tinkerPatch是否被使能
59 */
60 android {
61 defaultConfig {
62 buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
63 }
64 }
65 /**
66 * 一般来说,我们无需对下面的参数做任何的修改
67 * 对于各参数的详细介绍请参考:
68 * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
69 */
70 tinkerPatch {
71 ignoreWarning = false
72 useSign = true //是否需要签名,打正式包如果这里是true,则要配置签名,否则会编译不过去
73 dex {
74 dexMode = "jar"
75 pattern = ["classes*.dex"]
76 loader = []
77 }
78 lib {
79 pattern = ["lib/*/*.so"]
80 }
81
82 res {
83 pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
84 ignoreChange = []
85 largeModSize = 100
86 }
87 packageConfig {
88 }
89 sevenZip {
90 zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
91 // path = "/usr/local/bin/7za"
92 }
93 buildConfig {
94 keepDexApply = false
95 }
96 }
简单的说一下这里的参数配置:如图

这里还需要注意一个地方,就是appKey,在我们登录tinker的官网,并且添加一个app版本以后,都会生成一个appkey,我们要把自己的appkey填到上面的配置中,附上一张图
第四步 初始化 TinkerPatch SDK
官方给了我们两种方式来初始化TinkerPatch SDK,第一种是reflectApplication = true 的情况,另一种reflectApplication = false的情况,今天我们说reflectApplication = true这种情况,另一种情况,大家可以到官网中看看
简单来说一下这两种情况的区别啊,当reflectApplication = true这种情况是不需要更改我们项目的Application类,而reflectApplication = false的情况是需要改动Application这个类。
初始化TinkerPatch SDK
1 package com.example.administrator.tinkerdemotest;
2
3 import android.app.Application;
4
5 import com.tencent.tinker.loader.app.ApplicationLike;
6 import com.tinkerpatch.sdk.TinkerPatch;
7 import com.tinkerpatch.sdk.loader.TinkerPatchApplicationLike;
8
9 /**
10 * Created by Administrator on 2017/10/18 0018.
11 *
12 * reflectApplication = true 时
13 */
14
15 public class tinkerApplication extends Application {
16
17 private ApplicationLike tinkerApplicationLike;
18 @Override
19 public void onCreate() {
20 super.onCreate();
21
22 if (BuildConfig.TINKER_ENABLE) {
23 // 我们可以从这里获得Tinker加载过程的信息
24 tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
25
26 // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
27 TinkerPatch.init(tinkerApplicationLike)
28 .reflectPatchLibrary()
29 .setPatchRollbackOnScreenOff(true)
30 .setPatchRestartOnSrceenOff(true);
31
32 // 每隔3个小时去访问后台时候有更新,通过handler实现轮训的效果
33 new FetchPatchHandler().fetchPatchWithInterval(3);
34 }
35 }
36 }
最后在加上FetchPatchHandler这个类
1 package com.example.administrator.tinkerdemotest;
2
3
4 import android.os.Handler;
5 import android.os.Message;
6
7 import com.tinkerpatch.sdk.TinkerPatch;
8
9 /**
10 * Created by Administrator on 2017/10/18 0018.
11 */
12
13 public class FetchPatchHandler extends Handler {
14
15 public static final long HOUR_INTERVAL = 3600 * 1000;
16 private long checkInterval;
17
18
19 /**
20 * 通过handler, 达到按照时间间隔轮训的效果
21 */
22 public void fetchPatchWithInterval(int hour) {
23 //设置TinkerPatch的时间间隔
24 TinkerPatch.with().setFetchPatchIntervalByHours(hour);
25 checkInterval = hour * HOUR_INTERVAL;
26 //立刻尝试去访问,检查是否有更新
27 sendEmptyMessage(0);
28 }
29
30
31 @Override
32 public void handleMessage(Message msg) {
33 super.handleMessage(msg);
34 //这里使用false即可
35 TinkerPatch.with().fetchPatchUpdate(false);
36 //每隔一段时间都去访问后台, 增加10分钟的buffer时间
37 sendEmptyMessageDelayed(0, checkInterval + 10 * 60 * 1000);
38 }
39 }
最后将AndroidManifest.xml中的添加上相应的网络和SD的权限,还要在application中加上 android:name=".tinkerApplication",附上代码:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.administrator.tinkerdemotest"> 4 5 <uses-permission android:name="android.permission.INTERNET"/> 6 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 7 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 8 9 10 <application 11 android:allowBackup="true" 12 android:icon="@mipmap/ic_launcher" 13 android:label="@string/app_name" 14 android:roundIcon="@mipmap/ic_launcher_round" 15 android:name=".tinkerApplication" 16 android:supportsRtl="true" 17 android:theme="@style/AppTheme"> 18 <activity android:name=".MainActivity"> 19 <intent-filter> 20 <action android:name="android.intent.action.MAIN" /> 21 22 <category android:name="android.intent.category.LAUNCHER" /> 23 </intent-filter> 24 </activity> 25 </application> 26 27 </manifest>
好了,到这里,集成Tinker的代码基本上已经完成了,现在运行看看如图

双击assembleDebug就可以运行项目了,结果如图:

然后在app-->build下有个app-debug.apk的包,我们将这个包安装到手机上,就相当于是我们本地的应用,在里面我加了一句话,如图

接着我们打有补丁的包,打补丁的包之前,我们的改两个地方,在tinkerpatch.gradle中找到如图中的代码,我们需要将baseInfo,和variantName改成和自己的一直如图:
改完以后,我们就可以打补丁的包了,如图


将baseInfo的值改为 右图中1所对应的值,variantName的值改为右图2对应的值。改完以后,我们就可以打补丁的包了,如图

然后在build --> outputs --> tinkerPatch 中就可以找到我们的补丁的包了,如图

最后将我们的补丁包上传到tinker官网,就可以使用了,如图

最后附上一条动态的效果图。注意:一定要把app进程杀死,才会有效果。

最后给大家分享一份非常系统和全面的Android进阶技术大纲及进阶资料,及面试题集
想学习更多Android知识,请加入Android技术开发交流 7520 16839
进群与大牛们一起讨论,还可获取Android高级架构资料、源码、笔记、视频
包含高级UI、Gradle、RxJava、小程序、Hybrid、移动架构、React Native、性能优化等全面的Android高级实践技术讲解性能优化架构思维导图,和BATJ面试题及答案!
群里免费分享给有需要的朋友,希望能够帮助一些在这个行业发展迷茫的,或者想系统深入提升以及困于瓶颈的朋友,在网上博客论坛等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我在这免费分享一些架构资料及给大家。希望在这些资料中都有你需要的内容。
Android高级技术大纲,以及系统进阶视频,及面试题和答案

Android高级技术大纲

Android 进阶视频资料

面试题及答案
本文详述如何在Android项目中集成Tinker热修复框架,包括添加依赖、配置参数、初始化SDK及补丁包制作流程。
7375

被折叠的 条评论
为什么被折叠?



