Использование вариантов сборки - правильное структурирование исходных папок и build.gradle


166

Обратите внимание: ответ отредактирован после ответа Ксавье

Я пытаюсь использовать разные варианты сборки для одного и того же проекта приложения в Android Studio. Тем не менее, мне кажется, что я ужасно настраиваю его для правильной работы.

шаги:

  1. Создайте новый проект Android Studio с именем «Test».
  2. Откройте build.gradle * и добавьте следующие строки:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
  3. После перезапуска Android Studio теперь я вижу 4 варианта сборки в разделе «Варианты сборки». То есть мы до сих пор успешно настраивали вкусы продуктов. **
  4. Создана новая папка Source для flavor1 ; однако я не уверен, правильно ли я это делаю. Вот как я это сделал:

    • Имейте в виду, что мое имя пакета для этого проекта: com.foo.test
    • Щелкните правой кнопкой мыши на srcпапке, для flavor1, я фактически создал отдельные папки в проводнике, таким образом, что структура src/flavor1/java/com/foo/test/MainActivity.java.
    • Вышесказанное сработало хорошо, поскольку папка 'java' выделена синим цветом , что означает, что среда IDE знает свой каталог с активным исходным кодом. Также пакет был создан автоматически. Несмотря на это, я получаю предупреждение об обнаружении повторяющегося класса. Смотрите скриншот здесь.
    • Для flav2 я попытался создать пакет вручную, но папка 'src' для flav2, кажется, не синего цвета, и поэтому при щелчке правой кнопкой мыши параметры отличаются, и я не могу использовать 'New Package'. Смотрите изображение здесь.
    • Обратите внимание, что для flav1 я также создал каталог 'res', который становится синим, но, несмотря на это, не дает возможности создавать ни файл ресурсов Android, ни каталог ресурсов Andorid, на случай, если я захочу использовать другой Ресурсы для разных вкусов.

Я делаю что-то неправильно? Или я что-то упустил? Дайте мне знать, если вам нужно больше информации.

* Мой проект, кажется, имеет два файла build.gradle. Один находится в корне папки проекта (\ GradleTest), этот пустой. Вторая, расположенная в корне подпапки \ GradleTest, также помечена как «GradleTest» (GradleTest-GradleTest), это та, у которой уже был код при открытии; поэтому это тот, который я отредактировал.

** Я проверил Gradle настройки и , видимо , использование автоматического импорта был уже включен. Несмотря на это, внесение изменений в файл build.gradle не приводит к автоматическому обновлению вариантов сборки. Примечание: я также пытался использовать Build - Rebuild Project и / или Build - Make Project, no-go. Мне все еще нужно закрыть проект и открыть заново, чтобы изменения вступили в силу.


Обратите внимание, что applicationIdтеперь поддерживается вместо packageName.
Хамзех Собох

Ответы:


220

Если вы попали в настройки Studio, в разделе Gradle вы можете включить автоматический импорт для вашего проекта (мы включим его по умолчанию позже). Это позволит Studio повторно импортировать ваш build.gradle всякий раз, когда вы его редактируете.

Создание ароматов не означает, что вы собираетесь использовать для них собственный код, поэтому мы не будем создавать папки. Вам нужно создать их самостоятельно.

Если вы посмотрите на мой разговор о IO вы увидите, как мы объединяем значения из вариантов и типа сборки для создания варианта.

Для источника Java:

src/main/java
src/flavor1/java
src/debug/java

Все 3 используются для создания одного выхода. Это означает, что они не могут определять один и тот же класс.

Если вы хотите иметь разные версии одного и того же класса в двух вариантах, вам нужно создать их в обоих вариантах.

src/flavor1/java/com/foo/A.java
src/flavor2/java/com/foo/A.java

И тогда ваш код в src / main / java может сделать

import com.foo.A

в зависимости от выбранного вкуса используется правильная версия com.foo.A.

Это также означает, что обе версии A должны иметь одинаковый API (по крайней мере, когда дело доходит до API, используемого классами в src / main / java / ...

Изменить, чтобы соответствовать пересмотренному вопросу

Кроме того, важно помещать один и тот же класс A только в исходные папки, которые являются взаимоисключающими. В этом случае src / flav1 / java и src / flavour2 / java никогда не выбираются вместе, а main и flavour1.

Если вы хотите предоставить другую версию действия в другом стиле, не помещайте ее в src / main / java.

Обратите внимание, что если у вас было 3 варианта аромата и вы хотели использовать только один вариант для flavor1, тогда как flavour2 и flav3 совместно использовали одно и то же действие, вы можете создать общие исходные папки для этих двух других действий. У вас есть полная гибкость в создании новых исходных папок и настройке исходного набора для их использования.

По другим вашим пунктам:

Это нормально, что 2-я папка с исходным кодом не синяя. Вам нужно переключиться на второй вариант, чтобы включить его, и тогда вы сможете создавать пакеты и классы внутри. До этого Studio не считает его исходной папкой. Надеемся, что в будущем мы улучшим это, чтобы в среде IDE было известно об этих неактивных исходных папках.

Я думаю, это также нормально, что вы не можете создавать файлы ресурсов в папке res. Система меню не была обновлена ​​для работы со всеми этими дополнительными папками ресурсов. Это будет позже.


1
Я добавил несколько новых элементов в конце моего ответа, но дубликат имеет смысл. Вы не можете иметь один и тот же класс в src / main / java и src / flav1 / java, так как оба они используются при выборе flav1. В моем ответе обратите внимание, как я поместил один и тот же класс только в flavor1 / java и flavour2 / java, поскольку они являются эксклюзивными и никогда не включаются вместе.
Ксавье Дюкрохет

Привет, Ксавье, можешь ли ты дать мне более подробное описание того, как я могу использовать другую версию деятельности в своих вкусах? У меня есть тестовый проект, в котором я хочу использовать разные версии своей MainActivity, но в обоих apks (flav1 и flavour2) есть только версия main / java. Когда я не помещаю MainActivity в main / java, приложение вылетает при запуске.
Дженс Дженсен

@XavierDucrohet как насчет того, чтобы иметь разные ресурсы, а также разный код, основанный на разновидностях, но располагать их в разных модулях, чтобы мы могли включать один или другой модуль, основанный на разновидности, без необходимости смешивать код и ресурсы в одном корневом проекте? Это поддерживается?
Валерио Сантинелли

3
@ValerioSantinelli Вы можете сделать зависимости для вкуса. ИспользованиеflavorCompile ...
Ксавье Дюкрохет

@XavierDucrohet Я попробовал то, что вы предложили, но это не работает, как я ожидал. Вы можете увидеть, как там структурирован мой проект: stackoverflow.com/q/24410995/443136
Валерио Сантинелли

19

«Ароматы продукта» на Android

Меня иногда спрашивали о том, как работать с разными хостами, иконками или даже именами пакетов, в зависимости от версии одного и того же приложения.

Есть много причин, чтобы сделать это, и один простой путь: вкусы продуктов.

Вы можете определить в своем скрипте build.gradle такие вещи, которые я описал ранее.

Ароматизаторы продукта. Часть этой статьи написана, размышляя о вкусовых качествах продукта. Что касается документации Android:

Аромат продукта определяет настроенную версию сборки приложения проектом. Один проект может иметь разные вкусы, которые изменяют сгенерированное приложение.

Как вы можете их определить? Вы должны написать в своем build.gradle, какие разновидности вы хотите определить:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

Теперь у нас будет два разных варианта нашего приложения. Вы можете проверить это на Android Studio тоже во вкладке Build Variants

Варианты сборки

Несколько имен пакетов

Что делать, если вы хотите установить на свой телефон одно приложение с состоянием разработки и одно для рабочего состояния. Как вы, возможно, знаете, вы можете установить только одно приложение с тем же именем пакета (если вы попытаетесь установить новый APK с таким же, как тот, который установлен на вашем телефоне, он попытается обновить его).

Единственное, что вам нужно сделать, это определить его для каждого из ваших ароматов продукта:

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
        }
        prod {
            applicationId "zuul.com.android"
        }
    }
}

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

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
            buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'

        }

        prod {
            applicationId "zuul.com.android"
               buildConfigField 'String', 'HOST', '"http://api.zuul.com"'

        }
    }
}

В качестве примера мы попытаемся показать вам, как вы можете интегрировать это с Retrofit для отправки запроса на соответствующий сервер, не обращаясь к тому серверу, на который вы указываете, и исходя из особенностей. В данном случае это отрывок из приложения Zuul для Android:

public class RetrofitModule {

    public ZuulService getRestAdapter() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(BuildConfig.HOST)
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .build();
        return restAdapter.create(ZuulService.class);
    }

}

Как видите, вам просто нужно использовать BuildConfigclass для доступа к только что определенной вами переменной.

Любая переменная, доступная через ваш код. Переменная HOST - не единственная, которую вы можете представить в своем коде. Вы можете делать это с чем угодно:

prod {  
    applicationId "zuul.com.android"
    buildConfigField 'String', 'HOST', '"http://api.zuul.com"'
    buildConfigField 'String', 'FLAVOR', '"prod"'
    buildConfigField "boolean", "REPORT_CRASHES", "true"
}

Вы можете получить к ним доступ следующим образом:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

Разные значки для аромата Если вы хотите иметь разные значки для аромата, чтобы вы могли визуально определить, какой из них вы открываете (вы можете сделать это и по имени ... Но это не может вписаться в пространство!), У вас просто есть определить новые структуры каталогов для каждого из вариантов.

В примере, который я только что использовал, есть два варианта: devel и prod. Затем мы можем определить две новые структуры каталогов, чтобы мы могли определить ресурсы, которые мы хотим:

структура

Это работает с другими типами ресурсов, такими как strings.xml, integers.xml, arrays.xmlи т. Д.

Настроить параметры подписи

Чтобы вручную настроить параметры подписи для вашего типа сборки выпуска, используя конфигурации сборки Gradle:

1. Создайте хранилище ключей. Хранилище ключей - это двоичный файл, который содержит набор закрытых ключей. Вы должны хранить свое хранилище ключей в надежном и безопасном месте. 2.Создайте закрытый ключ. Закрытый ключ представляет собой объект, который должен быть идентифицирован с приложением, например, лицо или компания. 3. Добавьте конфигурацию подписи в файл build.gradle уровня модуля:

android {
...
defaultConfig {...}
signingConfigs {
    release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
    }
}
buildTypes {
    release {
        ...
        signingConfig signingConfigs.release
    }
}

}

Создайте подписанный APK:

Чтобы создать подписанный APK, выберите «Построить»> «Создать подписанный APK» в главном меню. Пакет в app / build / apk / app-release.apk теперь подписан вашим ключом релиза.

ссылка: https://developer.android.com/studio/build/build-variants.html#signing,http://blog.brainattica.com/how-to-work-with-flavours-on-android/



7

Кажется, вам нужно перезагрузить проект после добавления новых вкусов в build.gradle. После этого вы увидите 4 варианта сборки в представлении «Варианты сборки» (доступ к ним осуществляется через левый край окна).

Что касается дополнительных исходных каталогов, кажется, вам нужно создавать их вручную: src/flavor1/javaи src/flavor2/java. Вы увидите, что изменение вида в представлении «Build Variants» изменит текущие активные исходные каталоги (каталог является синим, когда он является активным исходным каталогом )

И, наконец, «Gradle создаст новые sourceSets для ваших новых вкусов» означает , что Gradle будет создавать объекты android.sourceSets.flavor1и , android.sourceSets.flavor2и вы можете использовать их в build.gradle сценарии. Но эти объекты создаются динамически, поэтому вы не видите их в build.gradle(я предлагаю вам прочитать это: http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html Особенно 6.6: это объясняет создание динамического задания. Скрипт Gradle - это отличный скрипт, поэтому я предлагаю вам познакомиться и с Groovy)


2
Я думаю, что примечание к импорту - это Build Variantsпредставление, я этого не заметил.
Chris.Jenkins

2

У меня была та же проблема, когда я перенес свой проект в Gradle. Проблема заключалась в том, что сборка не нашла нужную папку ресурсов. Я исправил это, добавив это под элементом android в build.gradle:

sourceSets {
        main {
            res.srcDirs = ['myProject/res']
        }
    }

0

Что-то, что важно и блокировало меня довольно долго, - это то, что имя флейвора должно соответствовать пакету, а не пакету, определенному в определении аромата в gradle. Например:

src/flavor1/java/com/foo/A.java

будет соответствовать

productFlavors {
  flavor1 {
    packageName 'com.android.studio.test.foobar'
  }
}

но

src/foobar/java/com/foo/A.java не будет использоваться для сборки flav1.


0

В градле:

Для типов сборки вам нужно только:

buildTypes {
   release{
    //proguard, signing etc.
   }
   debug {
    //development
   }
  }
}

А потом для ароматов вы добавляете те, которые вам нужны

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.