概述 (Summary)
最近项目上遇到了一些崩溃,导致的原因都是忘记给一些反射使用的类添加Progurad Rule
遂决定使用混淆 (Obfuscation) 后的包去跑UI测试
使用(Usage)
- 启动混淆
android {
buildTypes {
getByName("release") {
// Enables code shrinking, obfuscation, and optimization for only
// your project's release build type.
isMinifyEnabled = true
}
}
- 添加必要的Proguard Rule
-keep class androidx.** { *;}
-keep class org.junit.** { *;}
-keep class org.hamcrest.** { *;}
-keep class kotlin.** { *;}
// add your project's dependency progurad rule if need
- ⚠️ 如果不是使用Android Studio的按钮去执行UI测试(最后运行的命令是 connected[VariantName]AndroidTest), 而是使用./gradlew assemble[variantName]AndroidTest生成对应的测试包后,使用adb command line去运行UI测试,可以继续阅读后面的内容
问题 (Issue)
启动混淆后,添加一些项目中必要支撑混淆包运行起来的Progurad Rule,本地运行成功
(本地运行:直接使用Android Studio自带的功能,点击开始按钮,开始运行)
在CI运行中,总是启动崩溃
报错信息:
Caused by: androidx.startup.StartupException: androidx.startup.StartupException: java.lang.NoSuchMethodError: No static method synchronizedMap(Ljava/util/Map;)Ljava/util/Map; in class Lj$/util/DesugarCollections; or its super classes (declaration of 'j$.util.DesugarCollections' appears in /data/app/~~XxxXxx==/Your_Package-name.test-XxxXxx==/base.apk!classes2.dex
分析 (Analyse)
-
报错信息
猜测
- 混淆导致无法找到对应方法
- 包名 Your_Package-name.test 指向 AndroidTest.apk
-
分析生成物 debug.apk 和 debugAndroidTest.apk
通过Android Studio可以直接查看apk文件中的dex文件中对应的jar文件
相同点
- 发现两个apk文件中,都包含了 DesugarCollections.class
区别
- debug.apk 是包含synchronizedMap方法的
- debugAndroidTest.apk是缺少synchronizedMap方法的
-
分析启动和未启动混淆的 debugAndroidTest.apk
区别
- 混淆的包含有desugar相关类
- 未混淆的不含有任何desugar相关类
结论 (Conclude)
- UI测试启动过程,先从 debugAndroidTest.apk中寻找对应的类,再从 debug.apk中寻找
- 混淆会运行
l8DexDesugarLibMockDebugAndroidTest
task对class文件进行添加desugar相关类
解决方案 (Workaround, not a solution)
基于结论,我们的解决方案是
不混淆debugAndroidTest.apk
// Sadly can't escape doing this in afterEvaluate :(
val variant = <yourVariantHere> // release, externalRelease, etc
project.afterEvaluate {
val inputFiles = tasks.withType<R8Task>()
.named("minify${variant}WithR8")
.flatMap { it.projectOutputKeepRules }
tasks.withType<L8DexDesugarLibTask>()
.named("l8DexDesugarLib${variant}AndroidTest")
.configure {
keepRulesFiles.from(inputFiles)
keepRulesConfigurations.set(listOf("-dontobfuscate"))
}
}
网友评论