web-dev-qa-db-fra.com

Remplacer les ressources avec gradle selon buildType

Je veux remplacer certaines chaînes dans mon res/strings.xml avec gradle.

Je sais que depuis Android Gradle Plugin 0.7. + theres la possibilité d'avoir un dossier source spécifique à une variante. Mais mon application a beaucoup de saveurs et je n'ai pas souhaitez ajouter en plus des dossiers spécifiques aux variantes.

MISE À JOUR 2014-01-17

Ce que je veux en détail:

J'ai certaines variables dans mes ressources qui ne dépendent que du buildType (par exemple "release"). J'ai d'abord pensé que ma SOLUTION_1 (remplacer les données après la fusion des ressources) est sympa, car si je dois changer ces variables, je dois juste les changer dans le build.config (un seul endroit). Mais comme Scott Barta l'a écrit dans le commentaire ci-dessous, il existe de bonnes raisons pour lesquelles cette solution n'est PAS une bonne idée.

J'ai donc essayé une autre solution SOLUTION_2 (juste fusionner les bonnes ressources) basée sur ce projet GitHub de shakalaca . Je pense que cette façon est plus élégante et j'ai toujours l'avantage de changer les variables à un endroit!

SOLUTION_1 (remplacer les données après la fusion des ressources):

Ce que j'ai fait dans AS 0.4.2:

  • dans build.gradle J'essaie de remplacer la chaîne "Hello World" par "OVERRIDE" ( basé sur ma réponse à ce message ):

    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"
        }
    }
    

La tâche de copie et de filtrage fonctionne correctement, mais je n'ai pas pu définir le "nouveau" values.xml comme ressource de chaîne.

SOLUTION_2 (fusionnez simplement les bonnes ressources)

  • définir un flotteur pour un buildType spécifique (par exemple "releaseRes")
  • fusionnez ces ressources avec la saveur que vous souhaitez créer:

    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']
        }
    }
    
23
owe

Vous devez vous efforcer de trouver une solution qui n'implique pas d'écrire du code personnalisé dans vos fichiers de construction, en particulier du code qui fait des choses délicates avec la réaffectation des ensembles source à la volée. Le code Gradle personnalisé est un peu génial à écrire, et il est difficile à déboguer et à maintenir. Le nouveau système de construction est extrêmement puissant et dispose déjà de tonnes de flexibilité, et il est probable que vous puissiez déjà faire ce que vous voulez; c'est juste une question d'apprendre comment.

Surtout si vous apprenez les tenants et aboutissants des projets Android-Gradle (et c'est tellement nouveau que nous le sommes tous), il est préférable d'essayer de travailler avec les fonctionnalités intégrées au système avant de sortir des sentiers battus.

Quelques recommandations:

  • Il est peu probable que vous ayez besoin de varier les ressources en fonction du type de build. Un type de construction dans Android-Gradle est censé être quelque chose comme le débogage ou la version, où la différence réside dans le débogage, l'optimisation du compilateur ou la signature; les types de build sont censés être fonctionnellement équivalents les uns aux autres. Si vous regardez les propriétés que vous pouvez définir sur un type de build via le Groovy DSL , vous pouvez voir l'intention: debuggable, jniDebugBuild, renderscriptDebugBuild, renderscriptOptimLevel, packageNameSuffix, versionNameSuffix, signingConfig, zipAlign, runProguard, proguardFile , proguardFiles.
  • Si vous pensez toujours que vous souhaitez varier les ressources en fonction du type de build, il existe déjà un moyen simple de le faire avec le système de build actuel. Vous pouvez avoir un répertoire de ressources spécifique au type de build, y placer vos ressources, et la fusion des ressources dans le système de build prendra soin des choses pour vous au moment de la build. C'est l'une des puissantes fonctionnalités d'Android/Gradle. Voir tilisation de Build Flavors - Structuration des dossiers source et build.gradle correctement pour des informations sur la façon de faire fonctionner cela.
  • Si vous souhaitez modifier quelque chose en fonction du type de build et que vos besoins sont très rapides et simples, vous pouvez effectuer le changement dans Java code au lieu des ressources et au lieu du système de build. Il y a le mécanisme BuildConfig pour ce genre de chose - c'est une classe Java qui définit un indicateur DEBUG en fonction de l'état de la version de débogage/publication, et vous pouvez ajouter votre propre Java de différents types de build pour faire des choses plus significatives. BuildConfig était destiné à permettre de petites différences fonctionnelles entre les types de build, dans les cas où une build de débogage pourrait vouloir effectuer des opérations inutiles pour aider au développement, comme effectuer une validation des données plus approfondie ou créer un journal de débogage plus détaillé, et ces choses inutiles sont optimisées de manière optimale à partir des versions de versions. Cela dit, il peut s'agir d'un mécanisme approprié pour faire ce que vous voulez.
  • Envisagez d'utiliser des saveurs pour ce que vous utilisez pour le moment. Conceptuellement, une saveur est un peu comme un type de build dans la mesure où c'est une autre variante de votre application qui peut être construite; le système de construction créera une matrice de saveurs par rapport aux types de construction et peut créer toutes les combinaisons. Cependant, les saveurs répondent à un cas d'utilisation différent, où différentes saveurs partagent la plupart du code mais peuvent présenter des différences fonctionnelles importantes. Un exemple courant est une version gratuite ou payante de votre application. Dans la mesure où une ressource différente dans différentes variantes de votre application représente des fonctionnalités différentes, cela pourrait indiquer un besoin d'une saveur différente. Les saveurs peuvent avoir différents répertoires de ressources qui sont fusionnés au moment de la construction de la même manière que les configurations de build; voir la question liée ci-dessus pour plus d'informations.
18
Scott Barta

Je ne pense pas que vous ayez besoin de personnaliser le script de construction pour obtenir ce que vous voulez. Selon ma lecture de http://tools.Android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants ; lors de l'exécution de la génération, les ressources seront fusionnées à partir des dossiers suivants, s'ils existent;

src/[flavour][buildType]/res
src/[buildType]/res
src/[flavour]/res
src/main/res

Je pense donc que vous pouvez réaliser ce que vous voulez en ajoutant simplement les ressources dans src/release/res.

Bien que vous puissiez modifier les noms de dossier en spécifiant les sourceSets appropriés. [Type] .res.srcDirs si vous voulez vraiment les changer.

7
Jeremy Lakeman

Si quelqu'un tombe dessus

  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'

        }
    }

Et pour accéder à ces valeurs à l'aide de variantes de build:

 if(!BuildConfig.LOG)
      // do something with the boolean value

Ou

view.setText(BuildConfig.yourkeyvalue);
1
Ivan Milisavljevic