it-swarm.com.de

Wie ersetze ich eine Zeichenfolge für eine Buildvariante mit Gradle in Android Studio?

Ich habe zwei Varianten meines Projekts:

flavor1 -> packagename: com.example.flavor1 
flavor2 -> packagename: com.example.flavor2

Nun möchte ich eine Buildvariante von flavor1 und flavor2 bauen. Der einzige Unterschied der Buildvariante ist ein anderer Paketname. 

Mein Projekt verwendet MapFragments und hat nur ein Manifest - daher füge ich den Berechtigungsnamen von MAPS_RECEIVE in meine String-Ressourcendateien der jeweiligen Varianten ein.

Die Frage ist: Wie kann ich eine String-Ressource einer Buildvariante ersetzen?

Ich habe folgenden Ansatz ausprobiert ( beschrieben in diesem Beitrag ): 

buildTypes{
    flavor1Rev{
        packageName 'com.example.rev.flavor1'
        filter(org.Apache.tools.ant.filters.ReplaceTokens, tokens: ['package_permission' : 'com.example.rev.flavor1.permission.MAPS_RECEIVE'])
    }
}

Aber damit habe ich diesen Fehler bekommen:

Die Methode filter () für die Argumente .__ konnte nicht gefunden werden. [{tokens = {package_permission = com.example.rev.flavor1.permission.MAPS_RECEIVE}}, BuildTypeDsl_D ecorated {name = ReplaceTokens, debuggable = false, jniDebugBuild = false, Rendering-Skript DebugBuild = false, renderscriptOptimLevel = 3, packageNameSuffix = null, versionNameS uffix = null, runProguard = false, zipAlign = true, signingConfig = null}] on BuildTypeD sl_Decorated {name = buderusFinal, debuggable = false, jniDebugBuild = false, rendert iptDebugBuild = false, renderscriptOptimLevel = 3, packageNameSuffix = null, versionNa meSuffix = null, runProguard = false, zipAlign = true, signingConfig = null}.

Muss ich für die Filtermethode eine eigene Aufgabe definieren?

EDIT [2013_07_09]:

Zeichenfolge in src/flavor1/res:

<string name="package_permission">package_permission</string>

Code in build.gradle zum Ersetzen der Zeichenfolge:

buildTypes{
    flavor1Rev{
        copy{
            from('src/res/'){
                include '**/*.xml'
                 filter{String line -> line.replaceAll(package_permission, 'com.example.rev.flavor1.permission.MAPS_RECEIVE')}
            }
            into '$buildDir/res'
        }
    }
} 
25
owe

Ich habe das Problem selbst gelöst, also hier ist die Lösung "Schritt für Schritt" - vielleicht hilft es einigen anderen Neulingen, graduieren zu können :)

  • Aufgabe allgemein kopieren:

    copy{
        from("pathToMyFolder"){
            include "my.file"
        }
        // you have to use a new path for youre modified file
        into("pathToFolderWhereToCopyMyNewFile")
    }
    
  • Ersetzen Sie eine Zeile im Allgemeinen:

    copy {
       ...
       filter{
           String line -> line.replaceAll("<complete line of regular expression>",
                                          "<complete line of modified expression>")
       }
    }
    
  • Ich denke, das größte Problem war, die richtigen Wege zu finden, weil ich das dynamisch machen musste ( dieser Link war für mich sehr hilfreich ). Ich habe mein Problem gelöst, indem ich die speziellen Zeilen im Manifest und nicht in der String-Datei ersetzt habe.

  • Das folgende Beispiel zeigt, wie Sie den Tag "meta-data" im Manifest ersetzen, um Ihren google-maps-api-key zu verwenden (in meinem Fall gibt es verschiedene Varianten, die unterschiedliche Schlüssel verwenden):

    Android.applicationVariants.each{ variant -> 
        variant.processManifest.doLast{ 
            copy{
                from("${buildDir}/manifests"){
                    include "${variant.dirName}/AndroidManifest.xml"
                }
                into("${buildDir}/manifests/$variant.name")
    
                // define a variable for your key:
                def gmaps_key = "<your-key>"
    
                filter{
                    String line -> line.replaceAll("<meta-data Android:name=\"com.google.Android.maps.v2.API_KEY\" Android:value=\"\"/>",
                                                   "<meta-data Android:name=\"com.google.Android.maps.v2.API_KEY\" Android:value=\"" + gmaps_key + "\"/>")
                }
    
                // set the path to the modified Manifest:
                variant.processResources.manifestFile = file("${buildDir}/manifests/${variant.name}/${variant.dirName}/AndroidManifest.xml")
            }    
       }
    }
    
37
owe

Ich benutze fast genau den Ansatz, den Sie wollten. Die Variable replaceInManfest ist ebenfalls generisch und kann auch für andere Platzhalter verwendet werden. Die getGMapsKey()-Methode gibt nur den entsprechenden Schlüssel basierend auf dem buildType zurück.

applicationVariants.all { variant ->
    def flavor = variant.productFlavors.get(0)
    def buildType = variant.buildType
    variant.processManifest.doLast {
        replaceInManifest(variant,
            'GMAPS_KEY',
            getGMapsKey(buildType))
    }
}

def replaceInManifest(variant, fromString, toString) {
    def flavor = variant.productFlavors.get(0)
    def buildtype = variant.buildType
    def manifestFile = "$buildDir/manifests/${flavor.name}/${buildtype.name}/AndroidManifest.xml"
    def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll(fromString, toString)
    new File(manifestFile).write(updatedContent, 'UTF-8')
}

Ich habe es auf einer Gist , auch wenn Sie sehen wollen, ob es sich später entwickelt.

Ich fand, dass dies eine elegantere und verallgemeinerungsfähigere Herangehensweise ist als die anderen (obwohl der Ersatz, der gerade funktioniert, schöner wäre).

11
Saad Farooq

Die Antworten sind ziemlich veraltet, es gibt jetzt bessere Möglichkeiten, sie zu archivieren. Sie können den Befehl in Ihrem build.gradle verwenden:

manifestPlaceholders = [
            myPlaceholder: "placeholder",
    ]

und in deinem Manifest:

Android:someManifestAttribute="${myPlaceholder}"

weitere Informationen finden Sie hier: https://developer.Android.com/studio/build/manifest-merge.html

2
Joao Gavazzi

Im aktuellen Android Gradle DSL hat sich die ApplicationVariant-Klasse geändert, und Saads Ansatz muss umgeschrieben werden, z. wie folgt:

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.processManifest.doLast {
            replaceInManifest(output,
                    'GMAPS_KEY',
                    getGmapsKey(buildType))

            }
        }
    }

def replaceInManifest(output, fromString, toString) {
    def updatedContent = output.processManifest.manifestOutputFile.getText('UTF-8')
        .replaceAll(fromString, toString)
    output.processManifest.manifestOutputFile.write(updatedContent, 'UTF-8')
}

Das neue DSL bietet auch einen saubereren Ansatz, um direkt zur Manifestdatei zu gelangen.

0
Thorstenvv