在处理 Proguard、MultiDex、Testing 和 Product Flavors 时有什么好的策略?
What is the good strategy when dealing with Proguard, MultiDex, Testing and Product Flavors?
我有一个应用程序引用了大约 10 万个方法,最小 Sdk = 16
这里有2个组装选项:
- Proguard 将这一堆方法压缩到只有 44K 个方法
- 使用 Multi Dex
现在我有一些常见的用例:
- 运行 并在模拟器和设备上进行调试
- 要求越快越好
- 做测试(集成和UI)
- 它需要 运行(我在使用 MultiDex 运行ing Espresso 时遇到一些问题)
- 制作产品 APK
- 要求可靠,尽量缩小
大家有什么关于拼装攻略的推荐吗?
3/产品
- 使用 Proguard 减小 APK 大小
- 使用 Proguard 混淆
- 尽量不要使用Multidex(可能会失败)
2/测试
- 使用 minSdkVersion 21(我读到从 21 开始启用预索引,这样可以节省时间)
- ???
1/调试
- 使用 minSdkVersion 21(我读到从 21 开始启用预索引,这样可以节省时间)
- ???
这是 Gradle 文件:
productFlavors {
dev {
minSdkVersion 21
multiDexEnabled ???
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
multiDexEnabled false
}
}
defaultConfig {
applicationId "xxxx"
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
versionCode ANDROID_BUILD_VERSION_CODE
versionName ANDROID_BUILD_APP_VERSION_NAME
}
buildTypes {
release {
debuggable false
ext.enableCrashlytics = true
renderscriptOptimLevel 3
signingConfig android.signingConfigs.release
zipAlignEnabled true
minifyEnabled true
// shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
renderscriptOptimLevel 3
applicationIdSuffix ".debug"
versionNameSuffix "debug"
minifyEnabled false
}
}
为了避免 multidex,我在调试和发布版本上都使用了混淆器。
我的 build.gradle
文件看起来像这样:
debug {
minifyEnabled true
proguardFiles 'proguard_debug.pro'
signingConfig signingConfigs.debug
debuggable true
}
release {
minifyEnabled true
proguardFiles 'proguard_release.pro'
signingConfig signingConfigs.release
debuggable false
}
为了最小化调试和发布之间的差异,并允许正确调试调试版本,proguard_debug.pro
文件包含以下混淆指令:
-include proguard_release.pro
-dontobfuscate
-dontoptimize
-keep class my.package.name.** {*; }
那样的话,我只维护一个混淆器配置(在 proguard_release.pro
中),调试版本是使用相同的配置构建的,但没有混淆代码。
该配置解决了所有提到的问题:
- 不需要 multidex(所以没有两难选择是否与 API 一起使用
21 岁以上,您可以使用 Espresso)
- 调试版本和发布版本相同,只是调试版本不会混淆您的代码
根据@Muzikant的提议,我大体赞同,总结了今天的愿景
- 如果可以,尽量不要使用
MultiDex
。
- 测试库带来的方法开销可能会达到 65K 个数(所以使用 MutliDex)
- MultiDex 可能比 Proguard 进程更快(有待检查),因此调试可能很有趣
- 尝试使用最接近发布 APK 的 APK 进行测试
我的建议是:
因为有 3 个构建案例,只需制作 3 个 buildTypes :
- 发布
- 调试
- 验证(test为保留字)
使用 2 种口味:
- 一个与您的应用
minSdkVersion
一起发布
- 还有一个用于开发,使用更新的
minSdkVersion
(更快的构建、更多的测试功能、更易于使用的 espresso...)
不混淆调试
为了在测试阶段使用 Proguard,需要 Gradle DSL 的特定关键字 testProguardFile('proguard-rules-test.pro')
指向将用于调试的构建 testBuildType = "validation"
混淆测试(至少对 UI 系统和 CI 系统上的功能测试)
仅针对发布版 getDefaultProguardFile('proguard-android-optimize.txt')
使用优化 Proguard 规则,对于测试和调试只需使用 getDefaultProguardFile('proguard-android.txt')
我的 Proguard 文件的架构如下:
release proguard-rules-release.pro
的一个主文件,其中包含一组专用 Proguard 文件 -include proguard-rules-fabric.pro
用于 debug proguard-rules-debug.pro
的第二个文件,其中包括 proguard-rules-release.pro
第三个文件用于 调试 proguard-rules-dontobfuscate.pro
禁用混淆
测试proguard-rules-test.pro
的第四个文件,其中包括proguard-rules-debug.pro
和测试所需的规则
这是 Gradle 文件:
android {
...
compileSdkVersion ANDROID_BUILD_SDK_VERSION
buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
multiDexEnabled false
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
multiDexEnabled false
}
}
defaultConfig {
applicationId "x.y.app.z"
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
versionCode ANDROID_BUILD_VERSION_CODE
versionName ANDROID_BUILD_APP_VERSION_NAME
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
// point thge build for testing
testBuildType = "validation"
buildTypes {
release {
debuggable false
ext.enableCrashlytics = true
renderscriptOptimLevel 3
signingConfig android.signingConfigs.release
zipAlignEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-release.pro'
}
debug {
debuggable true
renderscriptOptimLevel 3
applicationIdSuffix ".debug"
versionNameSuffix "debug"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro', `proguard-rules-dontobfuscate.pro`
}
validation.initWith(debug)
validation {
signingConfig android.signingConfigs.release
debuggable false
renderscriptOptimLevel 3
applicationIdSuffix ".test"
versionNameSuffix "test"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro'
testProguardFile('proguard-rules-test.pro')
}
}
...
}
我还有一些未解决的问题需要解决:
如何使用 Android Studio 的自动调试签名进行验证构建? (但我不确定影响)
我仍然需要在验证 BuildType 中添加 proguardFiles
属性,而我有包含调试的 testProguardFile('proguard-rules-test.pro')
!
我有一个应用程序引用了大约 10 万个方法,最小 Sdk = 16
这里有2个组装选项:
- Proguard 将这一堆方法压缩到只有 44K 个方法
- 使用 Multi Dex
现在我有一些常见的用例:
- 运行 并在模拟器和设备上进行调试
- 要求越快越好
- 做测试(集成和UI)
- 它需要 运行(我在使用 MultiDex 运行ing Espresso 时遇到一些问题)
- 制作产品 APK
- 要求可靠,尽量缩小
大家有什么关于拼装攻略的推荐吗?
3/产品
- 使用 Proguard 减小 APK 大小
- 使用 Proguard 混淆
- 尽量不要使用Multidex(可能会失败)
2/测试
- 使用 minSdkVersion 21(我读到从 21 开始启用预索引,这样可以节省时间)
- ???
1/调试
- 使用 minSdkVersion 21(我读到从 21 开始启用预索引,这样可以节省时间)
- ???
这是 Gradle 文件:
productFlavors {
dev {
minSdkVersion 21
multiDexEnabled ???
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
multiDexEnabled false
}
}
defaultConfig {
applicationId "xxxx"
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
versionCode ANDROID_BUILD_VERSION_CODE
versionName ANDROID_BUILD_APP_VERSION_NAME
}
buildTypes {
release {
debuggable false
ext.enableCrashlytics = true
renderscriptOptimLevel 3
signingConfig android.signingConfigs.release
zipAlignEnabled true
minifyEnabled true
// shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
renderscriptOptimLevel 3
applicationIdSuffix ".debug"
versionNameSuffix "debug"
minifyEnabled false
}
}
为了避免 multidex,我在调试和发布版本上都使用了混淆器。
我的 build.gradle
文件看起来像这样:
debug {
minifyEnabled true
proguardFiles 'proguard_debug.pro'
signingConfig signingConfigs.debug
debuggable true
}
release {
minifyEnabled true
proguardFiles 'proguard_release.pro'
signingConfig signingConfigs.release
debuggable false
}
为了最小化调试和发布之间的差异,并允许正确调试调试版本,proguard_debug.pro
文件包含以下混淆指令:
-include proguard_release.pro
-dontobfuscate
-dontoptimize
-keep class my.package.name.** {*; }
那样的话,我只维护一个混淆器配置(在 proguard_release.pro
中),调试版本是使用相同的配置构建的,但没有混淆代码。
该配置解决了所有提到的问题:
- 不需要 multidex(所以没有两难选择是否与 API 一起使用 21 岁以上,您可以使用 Espresso)
- 调试版本和发布版本相同,只是调试版本不会混淆您的代码
根据@Muzikant的提议,我大体赞同,总结了今天的愿景
- 如果可以,尽量不要使用
MultiDex
。- 测试库带来的方法开销可能会达到 65K 个数(所以使用 MutliDex)
- MultiDex 可能比 Proguard 进程更快(有待检查),因此调试可能很有趣
- 尝试使用最接近发布 APK 的 APK 进行测试
我的建议是:
因为有 3 个构建案例,只需制作 3 个 buildTypes :
- 发布
- 调试
- 验证(test为保留字)
使用 2 种口味:
- 一个与您的应用
minSdkVersion
一起发布 - 还有一个用于开发,使用更新的
minSdkVersion
(更快的构建、更多的测试功能、更易于使用的 espresso...)
- 一个与您的应用
不混淆调试
为了在测试阶段使用 Proguard,需要 Gradle DSL 的特定关键字
testProguardFile('proguard-rules-test.pro')
指向将用于调试的构建
testBuildType = "validation"
混淆测试(至少对 UI 系统和 CI 系统上的功能测试)
仅针对发布版
getDefaultProguardFile('proguard-android-optimize.txt')
使用优化 Proguard 规则,对于测试和调试只需使用getDefaultProguardFile('proguard-android.txt')
我的 Proguard 文件的架构如下:
release
proguard-rules-release.pro
的一个主文件,其中包含一组专用 Proguard 文件-include proguard-rules-fabric.pro
用于 debug
proguard-rules-debug.pro
的第二个文件,其中包括proguard-rules-release.pro
第三个文件用于 调试
proguard-rules-dontobfuscate.pro
禁用混淆测试
proguard-rules-test.pro
的第四个文件,其中包括proguard-rules-debug.pro
和测试所需的规则
这是 Gradle 文件:
android {
...
compileSdkVersion ANDROID_BUILD_SDK_VERSION
buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
multiDexEnabled false
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
multiDexEnabled false
}
}
defaultConfig {
applicationId "x.y.app.z"
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION
versionCode ANDROID_BUILD_VERSION_CODE
versionName ANDROID_BUILD_APP_VERSION_NAME
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
// point thge build for testing
testBuildType = "validation"
buildTypes {
release {
debuggable false
ext.enableCrashlytics = true
renderscriptOptimLevel 3
signingConfig android.signingConfigs.release
zipAlignEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-release.pro'
}
debug {
debuggable true
renderscriptOptimLevel 3
applicationIdSuffix ".debug"
versionNameSuffix "debug"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro', `proguard-rules-dontobfuscate.pro`
}
validation.initWith(debug)
validation {
signingConfig android.signingConfigs.release
debuggable false
renderscriptOptimLevel 3
applicationIdSuffix ".test"
versionNameSuffix "test"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro'
testProguardFile('proguard-rules-test.pro')
}
}
...
}
我还有一些未解决的问题需要解决:
如何使用 Android Studio 的自动调试签名进行验证构建? (但我不确定影响)
我仍然需要在验证 BuildType 中添加
proguardFiles
属性,而我有包含调试的testProguardFile('proguard-rules-test.pro')
!