项目基于Androidx,主语言是Kotlin,Android studio 4.0.2版本
本文目标
集成bugly的tinker热修复能力到项目中
gradle的wrapper
用的gradle-5.6.4-all.zip
#Fri Sep 11 14:53:57 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
项目根目录build.gradle
dependencies {
//gradle需要从原来的3.5.0降级到3.4.2 bugly插件还没适配
classpath 'com.android.tools.build:gradle:3.4.2'
classpath "com.tencent.bugly:tinker-support:1.1.5"
}
tinker-support.gradle
在根目录创建tinker-support.gradle文件,内容如下
apply plugin: 'com.tencent.bugly.tinker-support'
//配置打包生成的apk的路径,定位在APP模块下的build/bakApk目录下
//形式如/user/**/desktop/com/.../main/app/bakApk
//基准包路径:app/build/bakApk/app-0709-14-54-16/app-release.apk
def bakPath = file("${project(":app").buildDir}/bakApk/")
//此处填写需要构建patch的发布包所在目录
//因为每次打包都会在上面的bakApk目录下生成一个以当前打包时间命名的文件件,文件件中存放着本次打包生成的apk,mapping.txt,R.txt.
def baseApkDir = 'app-0226-13-59-13'
//https://bugly.qq.com/docs/utility-tools/plugin-gradle-hotfix/
tinkerSupport {
// 开启tinker-support插件,默认值true
enable = true
// 是否启用覆盖tinkerPatch配置功能,默认值false
// tinkerSupport是bugly提供的配置属性
// 如果为true ,下面tinkerPatch中配置的属性不会生效,推荐这种。tinker的配置太繁琐复杂
overrideTinkerPatchConfiguration = true
// 生成patch.dex目录,默认值当前module的子目录tinker
//补丁包路径: app/build/outputs/patch/release/patch_signed.apk
autoBackupApkDir = "${bakPath}"
// 编译补丁包时,必需指定基线版本的apk,也就是针对哪个线上版本生成patch
baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// 对应tinker插件applyMapping 混淆规则
baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// 对应tinker插件applyResourceMapping 资源id映射
baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
//自动生成下面的tinker的值 时间戳形式0707-12-10-10
autoGenerateTinkerId = true
// 构建基准包和补丁包都要指定不同的tinkerId,并且必须保证唯一性
tinkerId = "if autoGenerateTinkerId=true,no need set here"
// 是否开启反射Application模式
enableProxyApplication = true
// 是否支持新增非export的Activity(注意:设置为true才能修改AndroidManifest文件)
supportHotplugComponent = true
//支持加固,360加固是ok的
isProtectedApp = true
}
/**
* 一般来说,我们无需对下面的参数做任何的修改
* 对于各参数的详细介绍请参考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
//oldApk ="${bakPath}/${appName}/app-release.apk"
ignoreWarning = true
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
//tinkerId = "1.0.1-base"
//applyMapping = "${bakPath}/${appName}/app-release-mapping.txt" // 可选,设置mapping文件,建议保持旧apk的proguard混淆方式
//applyResourceMapping = "${bakPath}/${appName}/app-release-R.txt" // 可选,设置R.txt文件,通过旧apk文件保持ResId的分配
}
}
App根目录build.gradle
在主项目APP添加依赖配置签名和拆分包,应用tinker打包配置gradle文件
关于signingConfigs的配置,如果有不明白的小伙伴可以参考下Android-SigningConfigs打包配置
apply from: '../tinker-support.gradle'//应用上面创建的tinker-support.gradle文件
android {
signingConfigs {
config {
storeFile file('../as_key_store')
storePassword '123456'
keyAlias 'mall'
keyPassword '123456'
}
}
defaultConfig {
applicationId "com.i.proj.main"
//开启拆分包
multiDexEnabled true
//把tinker的相关类放到主包
multiDexKeepFile file('../app/multiDexKeep.txt')
//配置支持的动态库类型
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config//签名文件release和debug保存一致
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config//签名文件release和debug保存一致
}
}
//开启jumboMode开关,tinker在diff时,可以使得dex文件更小
dexOptions {
jumboMode = true
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
//添加multidex
implementation "androidx.multidex:multidex:2.0.1"
//添加对bugly 和 tinker,包含了crash捕获和热修复
implementation "com.tencent.bugly:crashreport_upgrade:1.3.6"
implementation "com.tencent.tinker:tinker-android-lib:1.9.9"
}
在app目录创建multiDexKeep.txt文件,保证tinker的相关类打包的时候都放到了主包
com/tencent/tinker/loader/shareutil/ShareResPatchInfo.class
com/tencent/tinker/loader/SystemClassLoaderAdder$V23.class
com/tencent/tinker/loader/hotplug/ActivityStubManager.class
com/tencent/tinker/loader/shareutil/ShareOatUtil$1.class
com/tencent/tinker/loader/shareutil/ShareOatUtil.class
com/tencent/tinker/loader/shareutil/SharePatchFileUtil.class
com/tencent/tinker/loader/shareutil/ShareFileLockHelper.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_04.class
com/tencent/tinker/loader/TinkerDexOptimizer$StreamConsumer$1.class
com/tencent/tinker/loader/TinkerDexLoader.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_06.class
com/tencent/tinker/loader/TinkerDexOptimizer$1.class
com/tencent/tinker/loader/TinkerDexOptimizer$StreamConsumer.class
com/tencent/tinker/loader/hotplug/IncrementComponentManager.class
com/tencent/tinker/loader/AndroidNClassLoader.class
com/tencent/tinker/loader/TinkerResourcesKey.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_09.class
com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_07.class
com/tencent/tinker/loader/shareutil/ShareIntentUtil.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_00.class
com/tencent/tinker/loader/TinkerResourcesKey$V24.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_05.class
com/tencent/tinker/loader/TinkerTestAndroidNClassLoader.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_01_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_01_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_01_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_07.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_00_T.class
com/tencent/tinker/loader/hotplug/handler/MHMessageHandler.class
com/tencent/tinker/loader/shareutil/ShareElfFile$SectionHeader.class
com/tencent/tinker/loader/TinkerDexOptimizer$ResultCallback.class
com/tencent/tinker/loader/TinkerResourceLoader.class
com/tencent/tinker/loader/SystemClassLoaderAdder$V19.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_06.class
com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor$1.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_08.class
com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor$BinderInvocationHandler.class
com/tencent/tinker/loader/shareutil/ShareResPatchInfo$LargeModeInfo.class
com/tencent/tinker/loader/hotplug/ActivityStubs.class
com/tencent/tinker/loader/hotplug/interceptor/TinkerHackInstrumentation.class
com/tencent/tinker/loader/TinkerResourcesKey$V19.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_02.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_09.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_00.class
com/tencent/tinker/loader/shareutil/ShareElfFile$1.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_02_T.class
com/tencent/tinker/loader/TinkerTestDexLoad.class
com/tencent/tinker/loader/shareutil/ShareElfFile$ProgramHeader.class
com/tencent/tinker/loader/TinkerSoLoader.class
com/tencent/tinker/loader/hotplug/interceptor/HandlerMessageInterceptor$CallbackWrapper.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_01_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_08.class
com/tencent/tinker/loader/shareutil/ShareElfFile$ElfHeader.class
com/tencent/tinker/loader/TinkerResourcePatcher.class
com/tencent/tinker/loader/shareutil/ShareTinkerInternals.class
com/tencent/tinker/loader/hotplug/ComponentHotplug.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_07.class
com/tencent/tinker/loader/TinkerDexOptimizer$OptimizeWorker.class
com/tencent/tinker/loader/hotplug/interceptor/InterceptFailedException.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_01.class
com/tencent/tinker/loader/BuildConfig.class
com/tencent/tinker/loader/TinkerLoader.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_03.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_01.class
com/tencent/tinker/loader/SystemClassLoaderAdder$V4.class
com/tencent/tinker/loader/hotplug/interceptor/Interceptor$ITinkerHotplugProxy.class
com/tencent/tinker/loader/shareutil/ShareSecurityCheck.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_09.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_00.class
com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor$FakeInterfaceHandler.class
com/tencent/tinker/loader/SystemClassLoaderAdder.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_08.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_06.class
com/tencent/tinker/loader/TinkerResourcesKey$V17.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_00.class
com/tencent/tinker/loader/hotplug/interceptor/HandlerMessageInterceptor.class
com/tencent/tinker/loader/shareutil/ShareBsDiffPatchInfo.class
com/tencent/tinker/loader/shareutil/ShareReflectUtil.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_00_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_00_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_02.class
com/tencent/tinker/loader/TinkerUncaughtHandler.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_02_T.class
com/tencent/tinker/loader/TinkerDexOptimizer.class
com/tencent/tinker/loader/shareutil/ShareConstants.class
com/tencent/tinker/loader/shareutil/SharePatchInfo.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_09.class
com/tencent/tinker/loader/hotplug/handler/PMSInterceptHandler.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_05.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_03.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_01.class
com/tencent/tinker/loader/SystemClassLoaderAdder$V14.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_03.class
com/tencent/tinker/loader/hotplug/IncrementComponentManager$AttrTranslator.class
com/tencent/tinker/loader/shareutil/ShareOatUtil$InstructionSet.class
com/tencent/tinker/loader/app/TinkerApplication.class
com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor$FakeClientBinderHandler.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_02.class
com/tencent/tinker/loader/hotplug/UnsupportedEnvironmentException.class
com/tencent/tinker/loader/TinkerRuntimeException.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_04.class
com/tencent/tinker/loader/hotplug/interceptor/HandlerMessageInterceptor$MessageHandler.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_06.class
com/tencent/tinker/loader/TinkerDexLoader$1.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_00_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_02_T.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_04.class
com/tencent/tinker/loader/hotplug/IncrementComponentManager$1.class
com/tencent/tinker/loader/hotplug/EnvConsts.class
com/tencent/tinker/loader/hotplug/handler/AMSInterceptHandler.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_05.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_03.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_02.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_07.class
com/tencent/tinker/loader/hotplug/ActivityStubs$STDStub_05.class
com/tencent/tinker/loader/AbstractTinkerLoader.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_02_T.class
com/tencent/tinker/loader/SystemClassLoaderAdder$1.class
com/tencent/tinker/loader/TinkerResourcesKey$V7.class
com/tencent/tinker/loader/shareutil/ShareDexDiffPatchInfo.class
com/tencent/tinker/loader/shareutil/ShareElfFile.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTKStub_08.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SGTStub_04.class
com/tencent/tinker/loader/hotplug/interceptor/Interceptor.class
com/tencent/tinker/loader/hotplug/ActivityStubs$SIStub_01.class
com/tencent/tinker/loader/R.class
混淆文件的配置,每个项目用到的三方库都不尽相同,在这里面只是给个示例
#-------app start-------
-keep class com.i.proj.main.app.IApplication
-keep class com.yadong.biz_main.model** { *; }
-keep class com.yadong.biz_detail.model** { *; }
-keep class com.yadong.pub_model** { *; }
-keep class com.yadong.service_login** { *; }
-keepclassmembers class * extends androidx.lifecycle.ViewModel {
*;
}
#-------app end-------
#-------arouter start-------
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
#-------arouter end-------
#-------retrofit start-------
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
#-------retrofit end-------
#-------okhttp start-------
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-dontwarn org.conscrypt.ConscryptHostnameVerifier
#-------okhttp end-------
#-------okio start-------
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
#-------okio end-------
#-------AndroidX start-------
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontwarn androidx.**
#-------AndroidX end-------
#-------bugly start-------
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
#-------bugly end-------
#-------Gson start-------
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
#-------Gson end-------
#-------glide start-------
-dontwarn com.bumptech.glide.**
-keep class com.bumptech.glide.**{*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
#-------glide end-------
#kotlin
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep class **.R$* {*;}
-keepclassmembers enum * { *;}
同步一下项目
Application初始化
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//分包
MultiDex.install(base);
//tinker
Beta.installTinker();
}
@Override
public void onCreate() {
super.onCreate();
Bugly.init(this, "846911389d", true);
//安装了这个app的设备设置为启动测试机,这样可以在开发测试阶段,只下发测试补丁,不影响线上用户
Bugly.setIsDevelopmentDevice(this, true);
}
Bugly的init中的ID需要去官网申请
mainfext清单文件,添加权限以及BetaActivity
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- bugly-->
<activity
android:name="com.tencent.bugly.beta.ui.BetaActivity"
android:configChanges="keyboardHidden|orientation|screenSize|locale"
android:theme="@android:style/Theme.Translucent" />
tinker-support.gradle打包配置文件,比原生tinker配置要简化的非常多,到这一步已经集成成功了,接下来重点来了
验证热修复能力
基准包
构建基准包(可以理解为发布的包).并且安装到你的手机,并联网打开,使得bugly上报该版本的tinkerId有人使用,否则发布patch时,将会报错没有匹配到基准包tinkerId
构建成功后,先把基准包apk安装到手机上跑起来,这样就可以让bugly知道已经有基准包已经安装上了
补丁包
然后把build/bakApk文件下的app-0708-19-25-58赋值到tinker-support文件的 def baseApkDir="app-0708-19-25-58",然后找个地方随便修改几行代码,比如说首页加个toast,然后按照上图步骤构建patch补丁文件,最后将补丁文件上传到bugly补丁管理后台
完整的测试流程
1.打基准包安装并上报联网(注:填写唯一的tinkerId)
2.对基准包的bug修复(可以是java代码变更,资源的变更)
3.修改基准包路径,修改补丁包tinkerId,mapping文件路径(如果开启了混淆需要配置),resId文件路径
4.执行buildTinkerPatchRelease打Release版本补丁包
5.选择app/build/outputs/patch目录下的补丁包并上传(注:不要选择tinkerPatch目录下的补丁包,不然上传会有问题)
6.编辑下发补丁规则,点击立即下发
7.杀死进程并重启基准包,请求补丁策略(SDK会自动下载补丁并合成)
8.再次重启基准包,检验补丁应用结果
9.查看页面,查看激活数据的变化
注意事项
1.Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的activity)
2.由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码
3.在Android N上,补丁对应用启动时间有轻微的影响
4.不支持部分三星android-21机型,加载补丁时会主动抛出 "TinkerRuntimeException:checkDexInstall failed"
5.对于资源替换,不支持修改remoteView.例如transtion动画,notification icon以及桌面图标
6.每个项目的配置打包,构建补丁都会出现各种各样的问题.那此时,请注意观察控制台错误日志的输出.接着可以到bugly和tinker在github上的issues上面,搜一搜,看一看,目前还有哪些现存的问题.那么这些问题有可能就是你遇到的问题.