Переопределить ресурсы с помощью gradle в зависимости от типа buildType
Я хочу переопределить некоторые строки в файле res/strings.xml с помощью gradle.
Я знаю, что с Android Gradle Plugin 0.7. + позволяет иметь вариант конкретной исходной папки.
Но у моего приложения много вкусов, и я не хочу добавлять дополнительные варианты конкретных папок.
ОБНОВЛЕНИЕ 2014-01-17
Что я хочу подробно:
У меня есть некоторые переменные в моих ресурсах, которые зависят только от типа buildType (например, "release" ).
Сначала я думал, что мой SOLUTION_1 (переопределить данные после объединения ресурсов) приятно, потому что, если мне нужно изменить эти переменные, мне просто нужно их изменить в файле build.config(всего одно место).
Но, как написал Скотт Барта в комментарии ниже, есть несколько веских причин, почему это решение НЕ является хорошей идеей.
Итак, я попробовал другое решение SOLUTION_2 (просто объединить нужные ресурсы) на основе этого проекта GitHub shakalaca, Я думаю, что этот способ более изящный, и у меня все еще есть преимущество просто изменить переменные в одном месте!
SOLUTION_1 (переопределение данных после объединения ресурсов):
Что я сделал в AS 0.4.2:
-
in build.gradle
Я пытаюсь переопределить строку "Hello World" на "OVERRIDE" (на основе моего ответа в этом сообщении):
android.applicationVariants.all{ variant ->
// override data in resource after merge task
variant.processResources.doLast {
overrideDataInResources(variant)
}
}
def overrideDataInResources(buildVariant){
copy {
// *** SET COPY PATHS ***
try {
from("${buildDir}/res/all/${buildVariant.dirName}") {
// println "... FROM: ${buildDir}/res/all/${buildVariant.dirName}"
include "values/values.xml"
}
} catch (e) {
println "... EXCEPTION: " + e
}
into("${buildDir}/res/all/${buildVariant.dirName}/values")
// println "... INTO: ${buildDir}/res/all/${buildVariant.dirName}/values"
// --- override string "hello_world"
filter {
String line ->
line.replaceAll("<string name=\"hello_world\">Hello world!</string>",
"<string name=\"hello_world\">OVERRIDE</string>");
}
// *** SET PATH TO NEW RES ***
buildVariant.processResources.resDir = file("${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml")
// println "... NEW RES PATH: " + "${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml"
}
}
Задача копирования и фильтрации работает отлично, но я не могу установить "new" values.xml в качестве ресурса строки.
SOLUTION_2 (просто объедините нужные ресурсы)
- определить floater для определенного типа buildType (например, "releaseRes" )
-
объединить эти ресурсы с вкусом, который вы хотите построить:
android.applicationVariants.all{ variant ->
variant.mergeResources.doFirst{
checkResourceFolder(variant)
}
}
def checkResourceFolder(variant){
def name = variant.name;
if(name.contains("Release")){
android.sourceSets.release.res.srcDirs = ['src/releaseRes/res']
android.sourceSets.flavor1.res.srcDirs = ['src/flavor1/res']
}
}
Ответы
Ответ 1
Вам следует попытаться найти решение, которое не связано с написанием какого-либо настраиваемого кода в ваших файлах сборки, особенно кода, который делает сложные вещи с переназначением исходных наборов на лету. Пользовательский Gradle код немного напуган, чтобы писать, и его сложно отлаживать и поддерживать. Новая система сборки чрезвычайно мощная и уже имеет массу гибкости, и, вероятно, вы уже можете делать то, что хотите; это просто вопрос обучения.
Особенно, если вы просто изучаете входы и выходы проектов Android- Gradle (и это настолько новое, что мы все), лучше всего стараться работать с функциональностью, встроенной в систему, прежде чем думать за пределами коробка.
Некоторые рекомендации:
- Вряд ли вам нужно будет изменять ресурсы на основе типа сборки. Тип сборки в Android- Gradle должен быть чем-то вроде отладки или выпуска, где разница в отлаживаемости, оптимизации компилятора или подписании; типы конструкций должны быть функционально эквивалентны друг другу. Если вы посмотрите на свойства которые вы можете установить на тип сборки с помощью Groovy DSL, вы можете увидеть намерение:
debuggable
, jniDebugBuild
, renderscriptDebugBuild
, renderscriptOptimLevel
, packageNameSuffix
, versionNameSuffix
, signingConfig
, zipAlign
, runProguard
, proguardFile
, proguardFiles
.
- Если вы все еще считаете, что хотите изменить ресурсы на основе типа сборки, там уже есть простой способ сделать это с помощью текущей системы сборки. У вас может быть каталог ресурсов, специфичный для типа сборки, размещенные там ресурсы, а слияние ресурсов в системе сборки позаботится о вас во время сборки. Это одна из мощных функций Android/ Gradle. См. Использование Build Flavors - правильная структура исходных папок и build.gradle для получения информации о том, как сделать эту работу.
- Если вы хотите изменить что-то на основе типа сборки, и ваши потребности очень быстрые и простые, вы можете захотеть сделать это в Java-коде вместо ресурсов, а не в системе сборки. Там механизм
BuildConfig
для такого рода вещей - это класс Java, который определяет флаг DEBUG
, основанный на статусе сборки debug/release, и вы можете добавить свой собственный код Java из разных типов сборки, чтобы сделать более значимые вещи, BuildConfig
был предназначен для обеспечения небольших функциональных различий между типами построения, в тех случаях, когда сборка отладки может потребовать некоторой расточительной операции для оказания помощи в разработке, например, для более обширной проверки данных или создания более подробного ведения журнала отладки, а также для тех расточительных вещей наилучшим образом оптимизированным из релизов. Сказав это, это может быть подходящий механизм для выполнения того, что вы хотите.
- Подумайте о том, как использовать ароматы для того, что вы используете сейчас. Концептуально аромат похож на тип сборки, поскольку это другой вариант вашего приложения, которое можно построить; система сборки создаст матрицу вкусов и типов сборки и может создавать все комбинации. Тем не менее, вкусы относятся к другому варианту использования, в котором разные ароматизаторы используют большинство кодов, но могут иметь значительные функциональные различия. Общим примером является бесплатная или платная версия вашего приложения. Поскольку другой ресурс в разных вариантах вашего приложения представляет собой разную функциональность, это может указывать на необходимость различного вкуса. Ароматизаторы могут иметь разные каталоги ресурсов, которые объединены во время сборки так же, как и конфигурации сборки; см. вопрос, связанный выше для получения дополнительной информации.
Ответ 2
Я не считаю, что вам нужно полностью настроить конструкцию script для достижения того, чего вы хотите. Согласно моему чтению http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants; при выполнении сборки ресурсы будут объединены из следующих папок, если они существуют;
src/[flavour][buildType]/res
src/[buildType]/res
src/[flavour]/res
src/main/res
Поэтому я считаю, что вы можете достичь того, чего хотите, просто добавив ресурсы в src/release/res.
Хотя вы можете настроить имена папок, указав соответствующие исходные коды. [type].res.srcDirs, если вы действительно хотите их изменить.
Ответ 3
Если кто-то наткнется на это
buildTypes {
debug{
buildConfigField "String", "Your_string_key", '"yourkeyvalue"'
buildConfigField "String", "SOCKET_URL", '"some text"'
buildConfigField "Boolean", "LOG", 'true'
}
release {
buildConfigField "String", "Your_string_key", '"release text"'
buildConfigField "String", "SOCKET_URL", '"release text"'
buildConfigField "Boolean", "LOG", 'false'
}
}
И для доступа к этим значениям с использованием вариантов сборки:
if(!BuildConfig.LOG)
// do something with the boolean value
или
view.setText(BuildConfig.yourkeyvalue);