2014-01-16 10 views
22

Ich möchte einige Zeichenfolgen in meiner res/strings.xml mit Gradle überschreiben.Ressourcen mit Gradle überschreiben je nach BuildType

Ich weiß, dass since Android Gradle Plugin 0.7.+ Theres die Möglichkeit, eine Variante spezifischen Quellordner haben. Aber meine App hat viele Geschmacksrichtungen und ich möchte keine zusätzlichen spezifischen Ordner hinzufügen.

UPDATE 2014-01-17

Was ich will, im Detail:

Ich habe einige Variablen in meinen Ressourcen, die nur durch die buildType (beispielsweise "release") abhängen. Zuerst dachte ich, meine SOLUTION_1 (überschreiben Daten nach Ressourcen wurden zusammengeführt) ist schön, denn wenn ich diese Variablen ändern muss ich nur ändern sie in der build.config (nur einen Ort). Aber wie Scott Barta im Kommentar unten schrieb, gibt es einige gute Gründe, warum diese Lösung keine gute Idee ist.

So versuchte ich eine andere Lösung LÖSUNG_2 (nur die richtigen Ressourcen zusammenführen) basierend auf this GitHub project of shakalaca. Ich denke, dieser Weg ist eleganter und ich habe immer noch den Vorteil, nur die Variablen in einen Platz zu ändern!

SOLUTION_1 (Überschreiben von Daten nach Ressourcen waren fusionierte):

Was ich AS 0.4.2 tat in:

  • in build.gradle Ich versuche, den String "Hallo Welt" außer Kraft zu setzen, um " KORREKTUR“(based on my answer at this post):

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

Die Kopier- und Filteraufgabe funktioniert einwandfrei, aber ich konnte die "neue" values.xml nicht als Zeichenfolgenressource festlegen.

SOLUTION_2 (merge nur die richtigen Ressourcen)

  • eine floavor für spezifische buildType definieren (zB "releaseRes")
  • merge diese resourses mit dem Aroma, das Sie bauen wollen:

    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'] 
        } 
    } 
    
+6

Dies ist im Allgemeinen nicht nur eine sehr gute Idee. Wenn Sie versuchen, in Ihrem Build-System signifikante Gymnastik durchzuführen, um Ihre Ressourcen zu modifizieren, wird Ihr gesamtes Projekt sehr schwierig zu warten und zu debuggen sein. Es wird extrem zerbrechlich sein, da Änderungen am Plugin es kaputt machen können oder Änderungen an Android Studio es möglicherweise nicht funktionieren lassen. Es würde sich lohnen, eine Frage zu stellen, in der genau erklärt wird, was Sie erreichen möchten, und welche Ansätze Sie in Betracht gezogen haben, einschließlich dieser. –

+0

Danke für Ihre Antwort. Ich habe meine Frage bearbeitet und ausführlicher erklärt, was ich will. Ich denke, ich habe eine gute Lösung (SOLUTION_2) für meine Frage gefunden! – owe

+0

Scott hatte Recht :) Ich hatte Lösung_1 implementiert, nach einem Jahr kehrte zu meinem Projekt mit aktualisierten IDE, aktualisierten Plugin und es ist alles kaputt. –

Antwort

18

Sie sollten sich bemühen, eine Lösung zu finden, die nicht involvieren Schreiben Sie einen beliebigen benutzerdefinierten Code in Ihre Build-Dateien, insbesondere Code, der knifflige Aufgaben erledigt, indem Sie Quellsätze im Handumdrehen neu zuweisen. Benutzerdefinierter Gradle-Code ist etwas unruhig zu schreiben, und es ist schwierig zu debuggen und zu warten. Das neue Build-System ist extrem leistungsfähig und hat bereits eine Menge Flexibilität, und es ist wahrscheinlich, dass Sie bereits tun können, was Sie wollen; es ist nur eine Frage des Lernens wie.

Vor allem, wenn Sie nur die Android-Gradle-Projekte kennenlernen (und es ist so neu, dass wir alle sind), sollten Sie versuchen, mit der Funktionalität des Systems zu arbeiten, bevor Sie über den Tellerrand schauen .

Einige Empfehlungen:

  • es unwahrscheinlich ist, müssen Sie Ressourcen variieren basierend auf Buildtyp. Ein Build-Typ in Android-Gradle sollte etwas wie Debuggen oder Freigeben sein, wobei der Unterschied in der Debuggability, Compiler-Optimierung oder Signieren liegt. Build-Typen sollen funktional gleichwertig sein. Wenn man sich die properties you can set on a build type through the Groovy DSL anschaut, kann man die Absicht sehen: debuggable, jniDebugBuild, renderscriptDebugBuild, renderscriptOptimLevel, packageNameSuffix, versionNameSuffix, signingConfig, zipAlign, runProguard, proguardFile, proguardFiles.
  • Wenn Sie immer noch denken, dass Sie Ressourcen basierend auf dem Build-Typ variieren möchten, gibt es bereits eine einfache Möglichkeit, dies mit dem aktuellen Build-System zu tun. Sie können ein build-type-spezifisches Ressourcenverzeichnis haben, Ihre Ressourcen dort einbinden und das Zusammenführen von Ressourcen im Build-System kümmert sich um Dinge, die für Sie zur Build-Zeit notwendig sind. Dies ist eine der leistungsstarken Funktionen in Android/Gradle. Informationen dazu, wie das funktioniert, finden Sie unter Using Build Flavors - Structuring source folders and build.gradle correctly.
  • Wenn Sie etwas basierend auf Build-Typ variieren möchten und Ihre Anforderungen sind sehr schnell und einfach, möchten Sie möglicherweise die Umstellung in Java-Code anstelle von Ressourcen und nicht im Build-System. Es gibt den Mechanismus BuildConfig für diese Art von Sache - es ist eine Java-Klasse, die ein DEBUG Flag basierend auf Debug/Release-Build-Status definiert, und Sie können Ihren eigenen benutzerdefinierten Java-Code aus verschiedenen Build-Typen hinzufügen, um sinnvollere Dinge zu tun. BuildConfig wurde entwickelt, um kleine Funktionsunterschiede zwischen Build-Typen zuzulassen, in Fällen, in denen ein Debugbuilding einige verschwenderische Operationen zur Unterstützung der Entwicklung ausführen möchte, wie umfassendere Datenvalidierung oder detailliertere Debugprotokollierung, und diese verschwenderischen Dinge werden am besten optimiert aus Release-Builds. Nachdem dies gesagt wurde, könnte es ein geeigneter Mechanismus sein, um das zu tun, was Sie wollen.
  • Erwägen Sie, Aromen für das zu verwenden, was Sie Buildtypen für jetzt verwenden. Konzeptionell ist ein Flavour wie ein Build-Typ, da es eine andere Variante Ihrer Anwendung ist, die gebaut werden kann; Das Build-System erstellt eine Matrix aus Aromen und Build-Typen und kann alle Kombinationen erstellen. Flavors adressieren jedoch einen anderen Anwendungsfall, bei dem verschiedene Flavours den meisten Code teilen, aber signifikante funktionale Unterschiede aufweisen können. Ein gängiges Beispiel ist eine kostenlose oder kostenpflichtige Version Ihrer Anwendung. Insofern eine andere Ressource in verschiedenen Varianten Ihrer App unterschiedliche Funktionen repräsentiert, könnte dies auf eine andere Geschmacksrichtung hindeuten. Flavors können verschiedene Ressourcenverzeichnisse haben, die zur Build-Zeit auf die gleiche Weise wie Build-Konfigurationen zusammengeführt werden; Siehe die oben verlinkte Frage für weitere Informationen.
+2

Jetzt gibt es die Möglichkeit, Ressourcenwerte über DSL zu generieren: https://plus.google.com/109385828142935151413/posts/UVKA58MZV3J. Nur für Interesse: Funktioniert das wie der 'BuildConfig' Mechanismus? Ich habe es gerade versucht - Gradle hat keine Ausnahme geworfen, aber ich konnte den Ressourcenwert nicht finden. – owe

+0

Es wäre wert, das als separate Frage mit dem Code, den Sie verwenden, zu veröffentlichen. Ich werde es aufheben ;-) –

+0

Yeah ... du hast Recht. Ich werde in den nächsten Tagen eine neue Frage schreiben. Danke für die Verbesserung :) – owe

5

Ich glaube nicht, dass Sie das Build-Skript überhaupt anpassen müssen, um zu erreichen, was Sie wollen. Laut meiner Lesung ; Wenn der Build ausgeführt wird, werden Ressourcen aus den folgenden Ordnern zusammengeführt, sofern sie vorhanden sind.

Also ich glaube, dass Sie erreichen können, was Sie wollen, indem Sie einfach die Ressourcen in src/release/res hinzufügen.

Sie können die Ordnernamen jedoch anpassen, indem Sie die relevanten sourceSets angeben [type] .res.srcDirs, wenn Sie sie wirklich ändern möchten.

+0

Ausgezeichnet! Die IDE empfiehlt sogar, den Build-Typ vor dem Erstellen der Ressourcendatei auszuwählen. Danke – Viktor

0

Wenn jemand darüber stolpert dieses

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' 

     } 
    } 

Und diese Werte für den Zugriff auf Varianten mit bauen:

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

Oder

view.setText(BuildConfig.yourkeyvalue); 
+1

Dies fügt eine String-Konstante, aber keine String-Ressource, wie OP will. Sie können beispielsweise eine Ressource benötigen, um aus dem Manifest oder einer XML-Datei zu referenzieren. – sorianiv

Verwandte Themen