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。他让我更清楚地思考了这一点。
我已经在 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。他让我更清楚地思考了这一点。