在处理 Proguard、MultiDex、测试和产品风味时,啥是好的策略?

Posted

技术标签:

【中文标题】在处理 Proguard、MultiDex、测试和产品风味时,啥是好的策略?【英文标题】:What is the good strategy when dealing with Proguard, MultiDex, Testing and Product Flavors?在处理 Proguard、MultiDex、测试和产品风味时,什么是好的策略? 【发布时间】:2016-08-05 16:39:53 【问题描述】:

我有一个引用 ~ 100K 方法的应用,其中 min Sdk = 16

这里有两种组装方式:

Proguard 将这组方法缩减到只有 44K 个方法 使用多敏捷

现在我有一些常见的用例:

    在模拟器和设备上运行和调试 要求尽可能快 进行测试(集成和 UI) 它需要运行(我在使用 MultiDex 运行 Espresso 时遇到了一些问题) 制作 Prod APK 它要求尽可能可靠和缩小

你们对组装策略有什么建议吗?

3/ 产品

使用 Proguard 减小 APK 大小 使用 Proguard 进行混淆 尽量不要使用 Multidex(可能会失败)

2/ 测试

使用 minSdkVersion 21(我读到从 21 开始启用 pre-dexing,这样可以节省时间) ???

1/ 调试

使用 minSdkVersion 21(我读到从 21 开始启用 pre-dexing,这样可以节省时间) ???

这是 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
        
    

【问题讨论】:

【参考方案1】:

根据@Muzikant 的提议,我主要同意,我总结了我今天的愿景

如果可以,尽量不要使用MultiDex。 可能会碰巧达到 65K 的数量,方法是测试库带来的开销(所以使用 MutliDex) MultiDex 可能会比 Proguard 进程更快(待检查),因此调试可能会很有趣 尝试使用与发布 APK 最接近的 APK 进行测试

我的建议是:

    因为有 3 个构建案例,所以只需要 3 个构建类型:

    发布 调试 验证(test是保留字)

    使用两种口味:

    与您的应用程序的minSdkVersion 一起发布 还有一款用于开发,使用更新的 minSdkVersion(构建速度更快,测试功能更多,espresso 更易于使用...)

    不要混淆调试

    为了在测试阶段使用 Proguard,Gradle DSL 的特定关键字是必要的testProguardFile('proguard-rules-test.pro')

    使用testBuildType = "validation"指出将用于调试的构建

    对测试进行混淆处理(至少对于您的 CI 系统上的 UI 系统和功能测试)

    仅对发布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') 包含调试!

【讨论】:

可能为第一个打开点添加validation.initWith(buildTypes.debug)(待检查) 我明白了这一点“仅将优化 Proguard 规则用于发布 getDefaultProguardFile('proguard-android-optimize.txt'),用于测试和调试只需使用 getDefaultProguardFile('proguard-android.txt') “ 给出。为什么我们不使用优化代码运行测试?我已经对我的代码进行了混淆测试,但我遇到了优化代码的问题。【参考方案2】:

为了避免多重索引,我在调试和发布版本上都使用了 proguard。

我的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 文件包含以下 proguard 说明:

-include proguard_release.pro

-dontobfuscate
-dontoptimize
-keep class my.package.name.** *; 

这样,我只维护一个 proguard 配置(在 proguard_release.pro 中),调试版本是使用相同的配置构建的,但不会混淆代码。

该配置解决了所有提到的问题:

    不需要多索引(所以是否与 API 一起使用没有两难选择) 21+,你可以使用 Espresso) 调试版本和发布版本相同,只是调试版本不会混淆您的代码

【讨论】:

好的,很好。请注意,它也可能存在由混淆引起的问题!然而,构建 apk 对于调试和测试来说真的很慢。你能适应这种延迟吗? 考虑到替代方案,这对我来说是最好的解决方案。混淆不是问题,因为调试 proguard 配置具有 -dontobfuscate 标志 是的,我只是说混淆可能会给应用程序带来错误。这也很好测试 当代码被混淆和优化时,是否可以使用对象注入运行检测测试用例?

以上是关于在处理 Proguard、MultiDex、测试和产品风味时,啥是好的策略?的主要内容,如果未能解决你的问题,请参考以下文章

Multidex、Proguard 和 Firebase

在 Android 应用程序中使用 MultiDex 运行 ProGuard 两次,只有第二次出现警告/注释?

Android ProGuard +MultiDex 导致 ClassNotFoundException

使用 Multidex 的 Android proguard

Proguard 可以保存到 multidex 应用程序吗?

在 Xamarin Studio 中启用 MultiDex 或 ProGuard 时出错