Android Tinker热修复

来源:互联网 发布:战列舰炮击的威力知乎 编辑:程序博客网 时间:2024/06/04 18:18

文章参考:http://www.jianshu.com/p/db504b33bca5

应该都遇到过刚上线的app,突然发现一个严重的bug需要修复,怎么办,以前的做法修改bug,然后重新打包app,测试,发新版本。即使是仅仅改动一行代码,也需要这么繁琐的操作来修复bug。
后来,出现热修复技术,用户在使用过程中不知不觉bug就修复了。
现在已经出现了很多热修复技术了,这里记录Tinker的集成接入,更加详细的内容可以查阅官方文档

Tinker 是一个开源项目(Github链接),它是微信官方的 Android 热补丁解决方案,它支持动态下发代码、So 库以及资源,让应用能够在不需要重新安装的情况下实现更新。
这里写图片描述

Tinker SDK接入
第一步 添加 gradle 插件依赖,在项目的builder.gradle里面添加TinkerPatch 插件

buildscript {    repositories {        jcenter()    }    dependencies {        // TinkerPatch 插件        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.7"    }}

第二步 集成 TinkerPatch SDK
在app的gradle文件app/build.gradle中

dependencies {    // 若使用annotation需要单独引用,对于tinker的其他库都无需再引用    provided("com.tinkerpatch.tinker:tinker-android-anno:1.7.11")    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.7")}

第三步 配置 tinkerpatchSupport 参数
在app目录下,创建tinkerpatch.gradle
这里写图片描述

为了简单方便,我们将 TinkerPatch 相关的配置都放于 tinkerpatch.gradle 中, 我们需要在app的gradle文件app/build.gradle中还添加:

apply from: 'tinkerpatch.gradle'

打开引入的 tinkerpatch.gradle 文件,它的具体参数如下:

apply plugin: 'tinkerpatch-support'/** * TODO: 请按自己的需求修改为适应自己工程的参数 */def bakPath = file("${buildDir}/bakApk/")def baseInfo = "app-1.0.0-0803-17-03-11"// 注意!!!  改成对应的路径def variantName = "release"/** * 对于插件各参数的详细解析请参考 * http://tinkerpatch.com/Docs/SDK */tinkerpatchSupport {    /** 可以在debug的时候关闭 tinkerPatch **/    tinkerEnable = true    reflectApplication = true    autoBackupApkPath = "${bakPath}"    appKey = "1fb8b4539cbc48db"// 注意!!!  需要修改成你的appkey    /** 注意: 若发布新的全量包, appVersion一定要更新 **/    appVersion = "1.0.0"    def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"    def name = "${project.name}-${variantName}"    baseApkFile = "${pathPrefix}/${name}.apk"    baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"    baseResourceRFile = "${pathPrefix}/${name}-R.txt"    /**     *  若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample     *  注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)     **/}/** * 用于用户在代码中判断tinkerPatch是否被使能 */android {    defaultConfig {        buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"    }}/** * 一般来说,我们无需对下面的参数做任何的修改 * 对于各参数的详细介绍请参考: * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 */tinkerPatch {    ignoreWarning = false    useSign = true    dex {        dexMode = "jar"        pattern = ["classes*.dex"]        loader = []    }    lib {        pattern = ["lib/*/*.so"]    }    res {        pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]        ignoreChange = []        largeModSize = 100    }    packageConfig {    }    sevenZip {        zipArtifact = "com.tencent.mm:SevenZip:1.1.10"//        path = "/usr/local/bin/7za"    }    buildConfig {        keepDexApply = false    }}

将以上代码完整复制到tinkerpatch.gradle中
参数说明
bakPath:基包路径
baseInfo:基包文件夹名(打补丁包的时候,需要修改)
这里写图片描述
appKey:进入官网注册一个账号,新增APP,得到对应的appKey。这里写图片描述

第四步 初始化 TinkerPatch SDK
1. reflectApplication = true 的情况
若我们使用 reflectApplication 模式,我们无需为接入 Tinker 而改造我们的 Application 类。

public class MyApplication 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(3);            Log.i("TAG", "tinker init");        }    }}
  1. reflectApplication = false 的情况
    若我们已经完成了应用的 Application 改造,即将 Application 的逻辑移动到 ApplicationLike类中
public class MyApplicationLike extends DefaultApplicationLike {    ...    @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(3);            Log.i("TAG", "tinker init");        }    }}

创建FetchPatchHandler用于检测是否更新

public class FetchPatchHandler extends Handler {    public static final long HOUR_INTERVAL = 3600 * 1000;    private long checkInterval;    /**     * 通过handler, 达到按照时间间隔轮训的效果     * @param hour     */    public void fetchPatchWithInterval(int hour) {        //设置TinkerPatch的时间间隔        TinkerPatch.with().setFetchPatchIntervalByHours(hour);        checkInterval = hour * HOUR_INTERVAL;        //立刻尝试去访问,检查是否有更新        sendEmptyMessage(0);    }    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        //这里使用false即可        TinkerPatch.with().fetchPatchUpdate(false);        //每隔一段时间都去访问后台, 增加10分钟的buffer时间        sendEmptyMessageDelayed(0, checkInterval + 10 * 60 * 1000);    }}

最后在记得在Manifest.xml中配置Application,还要给SD卡读写权限

<manifest >    .....    <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       ...       android:name=".MyApplication"></manifest>

第五步 使用步骤
打正式包,打包前先配置签名
在app/build.gradle中,配置签名

 //需要配置自己的签名    signingConfigs {        release {                keyAlias '******' //签名别名                keyPassword '******' //签名密码                storeFile file('******')//签名文件.keystore或者.jks                storePassword '******'//签名密码        }    }    buildTypes {        release {            signingConfig signingConfigs.release        }    }

打开Studio右侧的Gradle,选择assemableRelease打正式包
这里写图片描述
完成后可以在文件夹build中找到生成的文件(这里称为基包)
这里写图片描述
打开build -> bakApk -> app-1.0.0-0803-17-03-11(根据时间命名)
release文件夹中会出现我们刚打完的包。一个apk,对应一个txt文件。
将apk安装到手机上,这是一个刚创建的项目,里面只有Hello World
这里写图片描述

然后,修改代码,弹出一个这就是补丁…

Toast.makeText(this, "这是个补丁...", Toast.LENGTH_SHORT).show();

打开tinkerpatch.gradle修改baseInfo成对应的文件名
这里写图片描述
修改tinkerpatch.gradle中的tinkerpatchSupport -> appVersion
这里写图片描述
完成后打开Gradle,如下选择tinkerPatchRelease
这里写图片描述
补丁包将位于 build/outputs/tinkerPatch 中,这里只需要用到patch_signed_7zip.apk
这里写图片描述
最后把生成的补丁包,在Tinker官网网站发布
这里写图片描述
这里写图片描述
版本号对应tinkerpatch.gradle中的appVersion
这里写图片描述
选择patch_signed_7zip.apk文件,提交即可(更多下发选项,参考官方文档)

提交后,查看补丁的下载数量以及成功应用数
这里写图片描述
这里补丁的成功率并不是100%,有时候应用下载了补丁,但是却没有更新,需要多试几次,或者过会再试。我刚开始试的时候有时立刻就更新补丁了,有时试过好多次都没更新,以为那里出错了,但是过会再试,又更新了。
这里写图片描述

提示:
1、添加SD卡权限,
2、下载补丁后,杀掉进程重新打开,补丁才会生效
3、补丁非即时生效,需要等一会儿

Demo下载

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 灯的开关闭不了怎么办 灯的开关按不动怎么办 灯开关按不动了怎么办 灯的开关摁不动怎么办 微信群500人满了怎么办 作业帮搜不到题目怎么办呢 金融社保卡密码忘了怎么办 工作未完想从国企辞职怎么办 宫腔粘连术后流血多怎么办 宫腔粘连术后一直流血怎么办? cad图框放不下图怎么办 简历假的入职怎么办 脱贫攻坚怎么看怎么办怎么干 吃的下没力气怎么办 恢复留查公示后怎么办 微语简报删了怎么办 小学生未完成作业作为老师怎么办 抽调人员想回原单位怎么办 扫码支付没成功怎么办 成都电表卡丢了怎么办 社保未满15年怎么办 60岁社保没交满15年怎么办 柴油车dpf是亮了怎么办 贴双眼皮贴眼睛肿了怎么办 送孩子赴澳洲家长怎么办签证? 开指过程中发烧怎么办 大水口热流道有料花怎么办 奶奶疼外孙胜过孙子怎么办 吃了有病的鸡怎么办 博士真毕不了业怎么办 35岁博士毕不了业怎么办 跨校考研失败了怎么办 开发商把网签房卖给我该怎么办 cad中命令行没了怎么办 平板玩游戏很卡怎么办 卵巢包块20厘米怎么办 耳机的橡胶破了怎么办 脚被树枝扎破了怎么办 脚被木头扎肿了怎么办 手表字面脚断了怎么办 捡到苹果电脑怎么办才能自己用