Android开发 热修复Tinker框架接入、发布流程及问题解决 |
您所在的位置:网站首页 › 自动驾驶路径预测 › Android开发 热修复Tinker框架接入、发布流程及问题解决 |
Tinker的作用
作为移动端开发者,时常会遇到因为一些小bug而需要重新发版的问题,这还属于小问题,如遇到一些大问题的话,若是通过用户更新来修复那效率就太慢了,亦或是遇到不更新的用户,那么该bug将一直存在用户手机上,这是非常危险的。Tinker是为了解决这种问题而生的,修改少量的代码,生成差分包,然后用户无感下载非常小的更新包,就可以解决问题。它是微信官方的Android热补丁解决方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。 当然,你也可以使用Tinker来更新你的插件。虽然Tinker可以替代更新,但是为了适应单一职责,因此我还是建议如果需要更新功能的话还是直接发版本,如果是修复一些小bug,那么就可以使用Tinker。 Tinker源码Github地址 接入(亲历心路历程) 找文档首先打开Github地址,找到底部接入指南。OK,无中文版咋整?(后来发现有中文的文档,只是在他的github主页没有附上) 通过其他大牛和博主了解到,要接入Tinker且使用它,必须要还要接入Bugly。(WTF?) 看看其他热更新框架算了。 结果发现几个主流的全都停止更新了,只有Tinker还在持续更新中。为了可持续发展,没办法,只能接入Tinker了。 但是Tinker的接入文档跟没有一样,那就先看看Bugly如何接把。打开Bugly官网后发现了新大陆,原来Tinker的接入流程全在Bugly的官方文档里面。 这给我激动的差点哭了。 Bugly官网地址 Bugly热更新文档地址 接入Tinker时请拿本文与官方文档配合使用 开始接入 1、在Bugly官网新建我的产品并记录好AppId工程根目录下“build.gradle”文件中添加: buildscript { repositories { jcenter() mavenCentral() } dependencies { classpath "com.tencent.bugly:tinker-support:1.1.5" classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.14.6') } } 复制代码在app module的“build.gradle”文件中添加(注意signingConfigs的注释): apply plugin: 'com.android.application' // tinker依赖的插件脚本 apply from: 'tinker-support.gradle' android { //必须配置这个,否则打补丁包的时候会因为没有签名而报错 signingConfigs { release { storeFile file('D:\XXX.jks') storePassword 'XXX' keyAlias 'XXX' keyPassword 'XXX' } debug { storeFile file('D:\XXX.jks') storePassword 'XXX' keyAlias 'XXX' keyPassword 'XXX' } } defaultConfig { multiDexEnabled true ndk { abiFilters "arm64-v8a", "armeabi-v7a" } } // recommend dexOptions { jumboMode = true } buildTypes { release { // 混淆 minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField("boolean", "LOG_ERROR", "false") // 注意此处必填 signingConfig signingConfigs.release } debug { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField("boolean", "LOG_ERROR", "true") // 注意此处必填 signingConfig signingConfigs.debug } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { // tinker implementation "com.android.support:multidex:1.0.1" // 多dex配置 implementation 'com.tencent.bugly:crashreport_upgrade:1.3.6' implementation 'com.tencent.tinker:tinker-android-lib:1.9.14.6' } 复制代码如果此时同步会报错,因为tinker-support.gradle文件不存在,这个文件才是我们打包的主要文件,当我们项目接入Tinker后,如果临时不需要使用Tinker的话,注释apply from: 'tinker-support.gradle' 这段代码就行了。 3、新建tinker-support.gradle这里有几个点需要注意一下: 这个文件必须在app里面,与app的build.gradle同级 只有开启了enableProxyApplication = true,那么注释apply from: 'tinker-support.gradle'就会让Tinker停用,如果是按照官方的文档重写application的话,那么enableProxyApplication要等于false,那么想停用Tinker的话还需要去处理application。 bakPath、baseApkDir、myTinkerId三个参数的值在打包的时候有重要作用,这里注意一下就行,后面会有打包发布的操作流程。 4、初始化Bugly+Tinker 方式一:反射MyApplication public class MyApplication extends Application { private static MyApplication appContext; @Override public void onCreate() { super.onCreate(); appContext = this; configTinker(); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // you must install multiDex whatever tinker is installed! MultiDex.install(getApplication()); // 安装tinker 此接口仅用于反射Application方式接入。 Beta.installTinker(); } public static synchronized MyApplication getApplication() { return appContext; } /** * 初始化Tinker */ private void configTinker(){ //是否开启热更新能力 Beta.enableHotfix = true; //是否开启自动下载补丁 Beta.canAutoDownloadPatch = true; //是否自动合成补丁 Beta.canAutoPatch = true; //是否提示用户重启 Beta.canNotifyUserRestart = false; //补丁回调接口 Beta.betaPatchListener = new BetaPatchListener() { @Override public void onPatchReceived(String s) { LogUtil.e(TAG, "补丁下载地址:" + s); } @Override public void onDownloadReceived(long l, long l1) { LogUtil.e(TAG, String.format(Locale.getDefault(), "%s %d%%", Beta.strNotificationDownloading, (int) (l1 == 0 ? 0 : l * 100 / l1))); } @Override public void onDownloadSuccess(String s) { LogUtil.e(TAG, "补丁下载成功"); } @Override public void onDownloadFailure(String s) { LogUtil.e(TAG, "补丁下载失败"); } @Override public void onApplySuccess(String s) { LogUtil.e(TAG, "补丁应用成功"); } @Override public void onApplyFailure(String s) { LogUtil.e(TAG, "补丁应用失败"); } @Override public void onPatchRollback() { } }; //第二个参数true表示是开发设备,在Bugly的后台发布补丁时,可以选择全部用户还是开发设备 Bugly.setIsDevelopmentDevice(getApplication(), true); // 多渠道需求塞入 // String channel = WalleChannelReader.getChannel(getApplication()); // Bugly.setAppChannel(getApplication(), channel); // 这里实现SDK初始化,appId替换成你的在平台申请的appId isDebug是否是调试模式 Bugly.init(getApplication(), appId, isDebug); } } 复制代码 方式二:不反射,官方建议的方式,该方式会增加接入成本,但有更好的兼容性1、“tinker-support.gradle”文件中设置“enableProxyApplication = false”; 2、自定义Application,注意,继承TinkerApplication public class MyApplication extends TinkerApplication { // 此文件只写这段代码,其他代码统一全部放到MyApplicationLike里面去 public MyApplication() { super(ShareConstants.TINKER_ENABLE_ALL, "xx.xx.xx.MyApplicationLike", "com.tencent.tinker.loader.TinkerLoader", false); } } 复制代码3、自定义ApplicationLike public class MyApplicationLike extends DefaultApplicationLike { public MyApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) { super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent); } @Override public void onCreate() { super.onCreate(); configTinker(); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onBaseContextAttached(Context base) { super.onBaseContextAttached(base); // you must install multiDex whatever tinker is installed! MultiDex.install(base); // 安装tinker Beta.installTinker(this); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) { getApplication().registerActivityLifecycleCallbacks(callbacks); } /** * 初始化Tinker */ private void configTinker(){ //是否开启热更新能力 Beta.enableHotfix = true; //是否开启自动下载补丁 Beta.canAutoDownloadPatch = true; //是否自动合成补丁 Beta.canAutoPatch = true; //是否提示用户重启 Beta.canNotifyUserRestart = false; //补丁回调接口 Beta.betaPatchListener = new BetaPatchListener() { @Override public void onPatchReceived(String s) { LogTools.e(TAG, "补丁下载地址:" + s); } @Override public void onDownloadReceived(long l, long l1) { LogTools.e(TAG, String.format(Locale.getDefault(), "%s %d%%", Beta.strNotificationDownloading, (int) (l1 == 0 ? 0 : l * 100 / l1))); } @Override public void onDownloadSuccess(String s) { LogTools.e(TAG, "补丁下载成功"); } @Override public void onDownloadFailure(String s) { LogTools.e(TAG, "补丁下载失败"); } @Override public void onApplySuccess(String s) { LogTools.e(TAG, "补丁应用成功"); } @Override public void onApplyFailure(String s) { LogTools.e(TAG, "补丁应用失败"); } @Override public void onPatchRollback() { } }; //第二个参数true表示是开发设备,在Bugly的后台发布补丁时,可以选择全部用户还是开发设备 Bugly.setIsDevelopmentDevice(getApplication(), true); // 多渠道需求塞入 // String channel = WalleChannelReader.getChannel(getApplication()); // Bugly.setAppChannel(getApplication(), channel); // 这里实现SDK初始化,isDebug:是否是调试模式 Bugly.init(getApplication(), "APP ID", false); } } 复制代码 AndroidManifest文件只管权限就行了,1.3.1版本以上已经兼容了FileProvider,混淆参考官方文档,这里不做赘述。至此,Tinker接入完毕。 发布流程 首先我们需要了解两个名词 基准包:我们发布到线上的apk,用户正常使用的包 补丁包:基于基准包所产生的差异包,修复了基准包里面的bug,使用基准包的用户可以下载补丁包通过打补丁的方式来修复bug 实行热修复如果发现线上问题,经过评估应该利用热修复(而不是app升级)来解决的,在我们修复bug文件之后,按照如下流程: 1. 将生产包apk(生成包apk和mapping文件必须在打包的时候备份好)放在工程内的下面位置,这个目录地址必须是tinker-support.gradle文件里面的变量bakPath+baseApkDier的目录。这个目录需要自己新建而不是Tinker自动生成,这里需要注意一下。我一开始以为是Tinker会自动生成,导致我打补丁包的时候一直报错。
具体接入可以直接参考Tinker的文档 但是该方式对打基准包和补丁包,都需要消耗大量的时间 2、采用第三方框架Walle集成多渠道打包的方式(本人采用)Walle源码地址,里面附接入流程 接入完成之后,我们通过执行命令gradlew clean assembleReleaseChannels进行多渠道打包 打包成功的话会在命令控制台自动输出BUILD SUCCESSFUL,并且在该图片对应目录生成对应的渠道包
|
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |