web-dev-qa-db-fra.com

Comment remplacer une chaîne pour un buildvariant par gradle dans Android studio?

J'ai deux saveurs de mon projet:

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

Maintenant, je veux construire un buildvariant de flaveur1 et saveur2. La seule différence de buildvariant est un autre nom de fichier. 

Mon projet utilise MapFragments et ne contient qu'un seul manifeste. Je mets donc le nom de permission de MAPS_RECEIVE dans mes fichiers de ressources de chaîne des types respectifs.

La question est: comment puis-je remplacer une ressource de chaîne d'un buildvariant?

J'ai essayé l'approche suivante ( décrite dans ce post ): 

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

Mais en utilisant ceci, j'ai eu cette erreur:

Impossible de trouver la méthode filter () pour les arguments [{tokens = {package_permission = com.example.rev.flavor1.permission.MAPS_RECEIVE}}, BuildTypeDsl_D ecorated {name = ReplaceTokens, debuggable = false, jniDebugBuild = false, renderscript DebugBuild = false, renderscriptOptimLevel = 3, packageNameSuffix = null, versionNameS uffix = null, runProguard = false, zipAlign = true, signatureConfig = null}] sur BuildTypeD sl_Decorated {name = buderusFinal, debuggable = false, jniDebugBuild = false, rend iptDebugBuild = false, renderscriptOptimLevel = 3, packageNameSuffix = null, versionNa meSuffix = null, runProguard = false, zipAlign = true, signatureConfig = null}.

Dois-je définir une tâche propre à la méthode de filtrage?

EDIT [2013_07_09]:

Chaîne dans src/flavour1/res:

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

Code dans build.gradle pour remplacer la chaîne:

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

J'ai résolu le problème moi-même, alors voici la solution "étape par étape" - cela aidera peut-être d'autres débutants à évaluer :)

  • Copier la tâche en général:

    copy{
        from("pathToMyFolder"){
            include "my.file"
        }
        // you have to use a new path for youre modified file
        into("pathToFolderWhereToCopyMyNewFile")
    }
    
  • Remplacer une ligne en général:

    copy {
       ...
       filter{
           String line -> line.replaceAll("<complete line of regular expression>",
                                          "<complete line of modified expression>")
       }
    }
    
  • Je pense que le plus gros problème était de trouver les bons chemins, car je devais le faire de manière dynamique ( ce lien m'a été très utile ). J'ai résolu mon problème en remplaçant les lignes spéciales dans le manifeste et non dans le fichier chaîne.

  • L'exemple suivant montre comment remplacer la balise "meta-data" dans le manifeste pour utiliser votre clé google-maps-api (dans mon cas, différentes variantes utilisent des clés différentes):

    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

J'utilise presque exactement l'approche que vous vouliez. La replaceInManfest est également générique et peut également être utilisée pour d'autres espaces réservés. La méthode getGMapsKey() renvoie simplement la clé appropriée en fonction du buildType.

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')
}

Je l'ai sur une Gist aussi si vous voulez voir si cela évolue plus tard.

J'ai trouvé que c'était une approche plus élégante et généralisable que les autres (bien que le remplacement de jeton fonctionnant bien aurait été plus agréable).

11
Saad Farooq

Les réponses sont assez obsolètes, il existe maintenant de meilleurs moyens pour l'archiver. Vous pouvez utiliser la commande dans votre build.gradle:

manifestPlaceholders = [
            myPlaceholder: "placeholder",
    ]

et dans votre manifeste:

Android:someManifestAttribute="${myPlaceholder}"

plus d'informations peuvent être trouvées ici: https://developer.Android.com/studio/build/manifest-merge.html

2
Joao Gavazzi

Dans la version actuelle d'Android Gradle DSL, la classe ApplicationVariant a changé et l'approche de Saad doit être réécrite, par exemple. comme suit:

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')
}

Le nouveau DSL offre également une approche plus propre pour accéder directement au fichier manifeste.

0
Thorstenvv