[toc]
关闭Tinker Gradle 编译插件后 Android 5.0版本以下机型运行Crash分析报告
一、再现场景
集成Tinker并使用tinkerEnabled = false关闭Tinker Gradle 编译插件开关)运行在华为CHM-UL00( Android版本4.4.2)直接crash,根据目前手中测试机测试后,Android版本5.0以下手机都会出现同样的问题,5.0以上均运行正常。
二、错误日志
Caused by: com.tencent.tinker.loader.TinkerRuntimeException: Tinker Exception:createDelegate failed
Tinker.UncaughtHandler: catch exception when loading tinker:java.lang.RuntimeException: Unable to instantiate application com.iflytek.elpmobile.smartlearning.ThisApplication: com.tencent.tinker.loader.TinkerRuntimeException: Tinker Exception:createDelegate failed
三、原因分析
故根据 Android版本5.0前后现象不同和错误日志分析,怀疑问题与分Dex方案Multidex在Android 5.0前后版本引用策略不同有关。经查询:
Multidex支持Android 5.0之前的版本 : Android5.0版本的平台之前,Android使用的是Dalvik Runtime执行的程序代码。默认情况下,限制应用到一个单一的classes.dex。Dalvik字节码文件每APK。为了绕过这个限制,你可以使用multidex支持库,成为你的应用程序的主要部分和DEX文件进行管理,获得额外的dex文件,它们包含的代码。
Multidex支持Android 5.0及更高版本 : Android 5.0和更高的Runtime 如art,本身就支持从应用的APK文件加载多个DEX文件。art支持预编译的应用程序在安装时扫描类(..)。Dex文件编译成一个单一的Android设备上执行.oat文件。
- Tinker需要确保下述文件放在主dex中:
- ApplicationLike实现类以及它的直接引用类
- 在调用Multidex install之前加载的类
- com.tencent.tinker.loader.*类
- 自定义了TinkerLoader类
- 而关闭tinkerEnabled后,Tinker Gradle 编译插件 中 生成需要放在主dex的keep规则和相关文件混淆的keep规则 的自动处理脚本 均不会执行,所以需要手动配置相关keep规则
四. 解决方案
- 方案一:打开tinkerEnabled = true,测试均运行正常。
- 方案二:关闭tinkerEnabled false,并如下手动引入分包策略文件,测试均运行正常,步骤如下:
- 首先暂时打开tinkerEnabled = true,使插件生成需要放在主Dex的keep规则。
- 然后将app/build/intermediates/tinker_intermediates/tinker_multidexkeep.pro(生成的keep规则文件)拷贝到主Module目录下,在主Module的app build中配置该规则:
defaultConfig { multiDexKeepProguard file("./tinker_multidexkeep.pro") }
五、keep规则
#tinker multidex keep patterns:
#proguardFiles adds
-keep public class * implements com.tencent.tinker.loader.app.ApplicationLifeCycle {
<init>(...);
void onBaseContextAttached(android.content.Context);
}
-keep public class * extends com.tencent.tinker.loader.TinkerLoader {
<init>(...);
}
-keep public class * extends android.app.Application {
<init>();
void attachBaseContext(android.content.Context);
}
-keep class com.tencent.tinker.loader.TinkerTestAndroidNClassLoader {
<init>(...);
}
-keep class com.iflytek.elpmobile.smartlearning.ThisApplication {
<init>(...);
}
-keep class com.tencent.tinker.loader.** {
<init>(...);
}