【问题标题】:Android Studio Gradle specifying output directory specific to FlavorAndroid Studio Gradle 指定特定于 Flavor 的输出目录
【发布时间】:2023-03-31 02:44:01
【问题描述】:

我已经在 Android Studio 中实现了 Flavor,现在我尝试将每个 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 调用才能使这一切正常工作。

【问题讨论】:

  • 移动 apk 的 afterTask 对你有用吗?
  • @lionscribe 如果它可以使用配置中的元素。如果在构建之后不需要辅助操作,那就太好了(如果是这样,我会坚持使用我的旧 Ant 脚本,它运行良好)。
  • 不确定你的意思,afterTask 被添加到你的 Gradle 文件中,并被 Gradle 自动调用。
  • @lionscribe 我已经更新了问题以显示任务的使用 - 但问题实际上不在任务范围内。更多的是尝试设置一个我可以在为所有风格运行 gradle 时访问的变量(例如,有点像用版本名称覆盖)。它可能在 Gradle 中 - 我只是没有找到它。感谢您的帮助,谢谢!

标签: android android-studio gradle android-productflavors


【解决方案1】:

好的,最后这个特定的链接真的有助于我需要的变量赋值:

Android Studio: Gradle Product Flavors: Define custom properties

基本上,您可以在风味中分配变量。这是我最终所做的,实际上比我开始时更进一步,因为现在我可以使用 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 是否已被覆盖,如果是,则使用它,否则使用风味名称(并且版本代码位于其前面)。目录由风味直接设置。

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

【讨论】:

  • 很高兴它有效。请接受您自己的答案,而不是我的答案,以便将来的用户找到它。
  • 会的。感谢帮助...Android Studio 和 Gradle 正在扼杀。 :)
  • 嗯,这是古老的选择,能力与简单。我选择前者。
  • @lionscribe 更多只是我的无知。现在我知道该怎么做,它非常优雅。我发现 if 的东西太复杂了,即使很流行,最终也会被抛弃(例如 EJB),但不确定这里是否是这种情况。再次感谢。
  • 请将productFlavors*.apkName[0] 更改为productFlavors[0].apkName。它应该可以工作,并使代码更易于理解和一致。我会解释。 productFlavors 似乎是一个数组或列表。因此你必须使用variant.productFlavors[0].apkName 来获得价值。现在,如果您使用 variant.productFlavors*.apkName,星号是一个 Groovy 命令,它在数组中的所有项目上调用 apkName,并返回它们的列表。因此,您需要在末尾添加一个 [0] 以获取第一个。在这种情况下,这完全是浪费时间和混淆代码。
【解决方案2】:

问题在于 setProperty 正在设置 Project 属性,因此它总是被覆盖。一个简单的解决方案是使用 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 将设置为风味对象的 ext 属性,前提是它在风味对象中定义。否则它将在父对象或根对象中设置它,即项目。因此,要使其工作,我们首先必须在风味对象中定义属性。这可以按照@Stephen 在下面的回答来完成。按照他的测试方法。

还有 3 个选项:
1. 为每个 flavir 使用不同的变量名,方法是预先添加风味名称,例如“Jimbo_archivesBaseName”。然后使用 property(flavorName + "_archivesBaseName);
访问它 2. 使用全局 HashMap 变量,为每个风味名称设置路径。
3. 使用函数,根据风味名称返回路径。

【讨论】:

  • 我之前试过了,它仍然选择了最后一个。我有一个解决方案,我会尽快发布。不过感谢您的帮助!
猜你喜欢
  • 2020-04-03
  • 1970-01-01
  • 2023-04-07
  • 2012-01-29
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多