Android Studio Gradle с указанием выходного каталога, специфичного для Flavor

Я реализовал Flavors в Android Studio и сейчас пытаюсь поместить каждый Flavor в отдельный каталог со своим уникальным именем - к сожалению, с именем, которое в некоторых случаях отличается от имени аромата.:(

У нас есть инструменты, в зависимости от того, что это одно и то же, так что, если я справлюсь с этим в Gradle, тем лучше.

У меня есть пример, который использует значение суффикса имени версии в качестве имени каталога, и это работает. Но то, что я хотел бы сделать, это указать значение где-то в конфигурации флейвора, которое будет использоваться, однако я обнаружил, что когда вы устанавливаете свойство с тем же именем, выигрывает последнее, а не каждое из них используется, как указано в конфиге.

Например, допустим, у меня есть два вкуса: Джимбо и Рэндольф. Однако я хочу поместить Jimbo.apk в папку "jimmy" и Randolph.apk в папку "randy". Как я могу указать значение (каталог) для каждого, который будет выбран и использован для хранения сгенерированного APK? Чтобы добавить к сложности, я переименую текущий APK в applicationVariants.all,

В приведенном ниже коде я ищу как-то заменить 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+, если заявления сделать это, и предпочел бы сделать это в Gradle. Я начинаю задумываться, нужно ли мне сделать внешний вызов Ant, чтобы все это работало.

2 ответа

Решение

Хорошо, в конце эта конкретная ссылка ДЕЙСТВИТЕЛЬНО помогла при назначении переменной, что мне и было нужно:

Android Studio: варианты продукта Gradle: определение пользовательских свойств

По сути, вы можете назначать переменные внутри аромата. Вот что я в итоге сделал, что на самом деле пошло немного дальше, чем когда я начинал, так как теперь я могу использовать 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. Он заставил меня думать об этом более четко.

Проблема в том, что setProperty устанавливает свойство Project, поэтому оно всегда перезаписывается. Простое решение - это использовать дополнительное свойство Varients. Что-то вроде этого.

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 объекта flavor, только если оно определено в объекте flavour. В противном случае он будет установлен в родительском или корневом объекте, которым является проект. Таким образом, чтобы это работало, мы сначала должны определить свойство в объекте flavour. Это можно сделать так, как @Stephen ответил ниже. Следуйте его проверенному методу.

Есть еще 3 варианта:
1. Используйте разные имена переменных для каждого вкуса, предварительно ожидая имя вкуса, например "Jimbo_archivesBaseName". Затем получите к нему доступ, используя свойство (flavName + "_archivesBaseName);
2. Используйте глобальную переменную HashMap, задав путь для каждого имени разновидности.
3. Использование функции, которая возвращает путь на основе имени аромата.

Другие вопросы по тегам