Android Studio Gradle 指定特定于 Flavor 的输出目录

Android Studio Gradle specifying output directory specific to Flavor

我已经在 Android Studio 中实现了 Flavors,现在正尝试将每个 Flavor 放在它自己的目录中,并使用其自己唯一的名称 - 遗憾的是,在某些情况下,名称与风味名称不同。 :(

我们有相同的工具,所以如果我能在 gradle 中完成它,那就更好了。

我有一个示例,它使用版本名称后缀值作为目录名称并且有效。但是我想做的是在将要使用的风味配置中的某处指定一个值,但是我发现当您设置具有相同名称的 属性 时,最后一个获胜 - 而不是每个都按指定使用在配置中。

例如,假设我有两种口味:Jimbo 和 Randolph。但是我想将 Jimbo.apk 放在 "jimmy" 文件夹中,将 Randolph.apk 放在 "randy" 文件夹中。如何为每个将被拾取并用于存储生成的 APK 的值(目录)指定一个值(目录)?为了增加复杂性,我正在重命名 applicationVariants.all 中的 APK 当前。

在下面的代码中,我希望以某种方式用我可以指定的变量替换 versionNameSuffix

这是我的:

apply plugin: 'com.android.application'

    android {
        compileSdkVersion 25
        buildToolsVersion '25.0.2'
        defaultConfig {
            applicationId "com.mycompany.default"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 11
            versionName "1.0.11"
            compileOptions {
                sourceCompatibility JavaVersion.VERSION_1_7
                targetCompatibility JavaVersion.VERSION_1_7
            }
            signingConfig signingConfigs.config
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            }
        }
        productFlavors {
            Randolph {
                applicationId 'com.mycompany.randy'
                versionNameSuffix 'randy'
            }
            Jimbo {
                applicationId 'com.mycompany.jimmy'
                versionNameSuffix 'jimmy'
            }
        }


        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].versionNameSuffix + "/"
                logger.error("Path = " + path)
                def SEP = "-"
                def flavor = variant.productFlavors[0].name
                def version = variant.versionCode
                def newApkName = path + version + SEP + flavor
                logger.error("newApkName = " + newApkName)
                output.outputFile = new File(newApkName + ".apk")
            }
        }
    }

    dependencies {
        }

}

更新

根据使用任务的问题,我尝试了这种方法,但设置目录的问题仍然存在 - 使用 属性 (archivesBaseName) 最后一组被使用,所以所有文件被复制到那个目录。这是其中的一个示例。因为我有超过 100 种口味要创建,所以我希望每一种都发送到它自己的目录和配置驱动。这是我尝试过的:

productFlavors {
    Randolph {
        applicationId 'com.mycompany.randy'
        setProperty("archivesBaseName", "randy")
    }
    Jimbo {
        applicationId 'com.mycompany.jimmy'
        setProperty("archivesBaseName", "jimmy")
    }
}


   applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def path = "C:/AndroidBuilds/MyCompany.Build/" + archivesBaseName + "/"
            logger.error("Path = " + path)
            def SEP = "-"
            def flavor = variant.productFlavors[0].name
            def version = variant.versionCode
            def newApkName = path + version + SEP + flavor
            logger.error("newApkName = " + newApkName)
            output.outputFile = new File(newApkName + ".apk")
            def copyApkTask = tasks.create(name: "copy" + variant.name + "Apk") {
                copy {
                    def newName = newApkName + ".apk"
                    logger.error("from = " + newName)
                    logger.error("into = " + path)
                    logger.error("old name = " + version + SEP + flavor + ".apk")
                    logger.error("new name = " + flavor + ".apk")
                    from newName
                    into path
                    rename (version + SEP + flavor + ".apk", flavor + ".apk")
                }
            }
            copyApkTask.mustRunAfter variant.assemble
        }
    } 

在上面的示例中,我添加了一个任务,用于将具有不同名称的 APK 额外复制到特定风格的目录中。所有 APK 最终都会复制到最后指定的 `archivesBaseName,即 "jimmy"。所以最后一个赢了。我希望它能像一个变量一样起作用。我宁愿不必有 100 多个 if 语句来执行此操作,并且更愿意在 Gradle 中执行此操作。我开始怀疑我是否需要进行外部 Ant 调用才能使这一切正常进行。

问题是 set属性 正在设置项目 属性,所以它总是被覆盖。一个简单的解决方案是使用 Varients Extra 属性。像这样。

productFlavors {
     Randolph { 
         applicationId 'com.mycompany.randy'
        ext.archivesBaseName = "randy" }
    Jimbo { 
        applicationId 'com.mycompany.jimmy'
        ext.archivesBaseName=jimmy" } 
    }

然后您将在任务中访问它作为

def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.ext.archivesBaseName + "/" 

我还没有测试过,它可能有一个错误,需要一些调整。

更新
这还不够,因为 Gradle 将设置为 flavor 对象的 ext 属性,前提是它已在 flavor 对象中定义。否则它会将其设置在父对象或根对象中,即项目。所以为了让它起作用,我们首先必须在 flavor 对象中定义 属性 。这可以按照@Stephen 在下面的回答来完成。按照他的测试方法。

还有3个选项:
1. 为每种口味使用不同的变量名称,通过在口味名称前添加,例如 "Jimbo_archivesBaseName"。然后使用 属性(flavorName + "_archivesBaseName);
访问它 2.使用一个全局的HashMap变量,为每个风味名称设置一个路径。
3. 使用一个函数,returns一个基于风味名称的路径。

好的,最后这个特定的 link 确实帮助了我需要的变量赋值:

基本上你可以在 flavor 中分​​配变量。这是我最后做的,实际上比我开始时更进一步,因为现在我可以使用 Flavor 作为 APK 名称或指定一个(我知道,它搞砸了,但历史可以这样!) :

apply plugin: 'com.android.application'

    android {
        compileSdkVersion 25
        buildToolsVersion '25.0.2'
        defaultConfig {
            applicationId "com.mycompany.default"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 11
            versionName "1.0.11"
            compileOptions {
                sourceCompatibility JavaVersion.VERSION_1_7
                targetCompatibility JavaVersion.VERSION_1_7
            }
            signingConfig signingConfigs.config
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            }
        }

        productFlavors.whenObjectAdded { flavor ->
            // Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
            flavor.ext.set('directoryPath', '')
            flavor.ext.set('apkName', '')
        }

        productFlavors {
            Randolph {
                applicationId 'com.mycompany.randy'
                directoryPath =  'randy'
                apkName = 'RandyBoy'  // If you want the APK name be different than the flavor
            }
            Jimbo {
                applicationId 'com.mycompany.jimmy'
                directoryPath =  'jimmy'
            }
        }

        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].directoryPath + "/"
                def SEP = "-"
                def apkName = variant.productFlavors[0].apkName
                def flavor = variant.productFlavors[0].name
                if (apkName != '')
                    flavor = apkName;
                def version = variant.versionCode
                def newApkName = path + version + SEP + flavor
                logger.error("newApkName = " + newApkName)
                output.outputFile = new File(newApkName + ".apk")
            }
        }
    }

    dependencies {
        }

}

因此 productFlavors.whenObjectAdded 为每种口味设置默认值,然后由每种口味覆盖。在 applicationVariants.all 中,检查 apkName 是否已被覆盖,如果是,则使用它,否则使用风味名称(版本代码附加在它前面)。目录直接由flavor设置。

非常感谢@lionscribe。他让我更清楚地思考了这一点。