Android Studio: сочетание вкусов продукта с более чем двумя вкусовыми измерениями (группами вкусов).

Я разрабатываю приложение для Android с помощью Android Studio (v 2.1, плагин gradle v 2.1.0). У моего приложения есть различные версии, которые имеют много общего кода, поэтому я решил использовать параметры вкуса и вкусы продукта, чтобы настроить код и ресурсы, когда и где они запрашиваются. Это работало нормально, пока у меня было только два вкусовых измерения. Например, мой app.gradle был

…
flavorDimensions "fruit", "color"

productFlavors {

    apple {
        dimension "fruit"
    }
    pear {
        dimension "fruit"
    }

    red {
        dimension "color"
    }
    yellow {
        dimension "color"
    }
}
…

и моя папка src была

src/
    appleRed/
    appleYellow/
    pearRed/
    pearYellow/

каждый с пользовательской версией моего кода. Опять же, как пример

src/
    appleRed/java/com/example/ExampleFragment.java
    appleYellow/java/com/example/ExampleFragment.java
    pearRed/java/com/example/ExampleFragment.java
    pearYellow/java/com/example/ExampleFragment.java

конечно, экземпляра ExampleFragment в src/main нет.

В какой-то момент разработки мне пришлось добавить бесплатную и платную версии приложения. Я подумал, что этого можно легко добиться, добавив новое измерение вкуса с именем version и два вкуса продукта с именами free и paid:

 …
flavorDimensions "fruit", "color”, “version”

productFlavors {

    apple {
        dimension "fruit"
    }
    pear {
        dimension "fruit"
    }

    red {
        dimension "color"
    }
    yellow {
        dimension "color"
    }

    free {
        dimension "version"
    }
    paid {
        dimension “version”
    }
}
…

но внезапно пользовательский код, сгенерированный комбинацией fruit и color, больше не обнаруживался Android Studio. Таким образом, ни appleRed, ни appleYellow, ни pearRed, ни pearYellow нельзя использовать для пользовательского кода, и единственный способ, которым я смог восстановить свою конфигурацию, — это использовать все комбинации всех трех аспектов:

  src/
      appleRedFree/java/com/example/ExampleFragment.java
      appleRedPaid/java/com/example/ExampleFragment.java
      appleYellowFree/java/com/example/ExampleFragment.java
      appleYellowPaid/java/com/example/ExampleFragment.java
      pearRedFree/java/com/example/ExampleFragment.java
      pearRedPaid/java/com/example/ExampleFragment.java
      pearYellowFree/java/com/example/ExampleFragment.java
      pearYellowPaid/java/com/example/ExampleFragment.java

Это нехорошо, потому что ExampleFragment дублируется в одной и той же комбинации fruitColor* (appleRedFree, appleRedPaid имеют одинаковые ExampleFragment). Та же проблема возникает с ресурсами (те, что в папке res).

Мои вопросы:

1) Является ли это ожидаемым поведением от gradle в Android Studio (т. е. невозможность комбинировать подмножество вкусов продуктов, следуя их приоритету в зависимости от их измерения, при наличии более двух измерений вкуса)?

2) Учитывая тот факт, что это ожидаемое поведение, есть ли другой способ добиться моей настройки без дублированного кода или без единого файла с if-statement внутри (например,, if (BuildConfig.FLAVOR_version == "free") ...) ?

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




Ответы (2)


Вы хотите использовать один и тот же дополнительный исходный каталог для некоторых вариантов;

appleRedFree + appleRedPaid --> src/appleRed
pearRedFree + pearRedPaid --> src/pearRed
appleYellowFree + appleYellowPaid --> src/appleYellow
pearYellowFree + pearYellowPaid --> src/pearYellow

Вы можете установить sourceSet для ваших вкусов:

android {

    // Other stuff here

    flavorDimensions "fruit", "color”, “version”

    productFlavors {

        apple {
            dimension "fruit"
        }
        pear {
            dimension "fruit"
        }

        red {
            dimension "color"
        }
        yellow {
            dimension "color"
        }

        free {
            dimension "version"
        }
        paid {
            dimension “version”
        }
    }

    sourceSets {
        appleRedFree {
            java.srcDirs = ['src/main/java', 'src/appleRed/java']
        }

        appleRedPaid {
            java.srcDirs = ['src/main/java', 'src/appleRed/java']
        }

        appleYellowFree {
            java.srcDirs = ['src/main/java', 'src/appleYellow/java']
        }

        appleYellowPaid {
            java.srcDirs = ['src/main/java', 'src/appleYellow/java']
        }

        pearRedFree {
            java.srcDirs = ['src/main/java', 'src/pearRed/java']
        }

        pearRedPaid {
            java.srcDirs = ['src/main/java', 'src/pearRed/java']
        }

        pearYellowFree {
            java.srcDirs = ['src/main/java', 'src/pearYellow/java']
        }

        pearYellowPaid {
            java.srcDirs = ['src/main/java', 'src/pearYellow/java']
        }
    }

   // Other stuff here
}
person Devrim    schedule 15.08.2016
comment
Не работает. Синхронизация проекта Gradle завершается с ошибкой: Error:(46, 0) Could not find method appleRedFree() for arguments [build_5p3mtjx0cpg9la7ms46x7bgzz$_run_closure2$_closure8@5d22a1be] on AndroidSourceSet container. Вы забыли где-то включить apply plugin? - person Vangaorth; 02.03.2017
comment
@Vangaorth Я обновил свой ответ. - person Devrim; 02.03.2017
comment
Теперь это работает! Вы также должны использовать последний (на момент написания) плагин Gradle для Android (2.3.0) и Gradle (3.3). Итак, в Android Studio Файл -> Структура проекта -> Вкладка «Проект», версия Gradle до 3.3 и версия плагина Android до 2.3.0. - person Vangaorth; 03.03.2017
comment
как установить переоценку для каждого вкуса? - person roghayeh hosseini; 01.03.2020
comment
@roghayehhosseini Просто используйте pearYellowPaid.res.srcDirs += 'src/pearYellow/res` - person wrozwad; 01.07.2020

У меня есть небольшое улучшение, потому что я действительно не люблю копировать/вставлять наборы src :)

Итак, вы можете сделать что-то вроде этого:

android {
    …
    applicationVariants.all { variant ->
        def flavors = variant.productFlavors
        def fruit = flavors[0].name
        def color = flavors[1].name
        def version = flavors[2].name

        def fruitColorSrcSet = fruit + color.capitalize()
        def srcSet = fruitColorSrcSet + version.capitalize()
        android.sourceSets."$srcSet".java.srcDirs += "src/$fruitColorSrcSet/java"
    }
}

Я не тестировал его, но он основан на моей текущей реализации с дополнительным использованием variant.buildType.name


Приложение - для настройки использования каталога ресурсов

android.sourceSets."$srcSet".res.srcDirs = "src/$fruitColorSrcSet/res"
person wrozwad    schedule 01.07.2020