Как заменить строку для buildvariant с помощью gradle в студии Android?

У меня есть два варианта моего проекта:

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

Теперь я хочу построить buildvariant вкуса1 и flavor2. Единственное отличие buildvariant - другое имя пакета.

Мой проект использует MapFragments и имеет только один манифест - поэтому я поместил имя MAPS_RECEIVE в мои файлы с строковыми ресурсами соответствующих ароматов.

Возникает вопрос: как заменить строковый ресурс buildvariant?

Я пробовал следующий подход (описанный в этом сообщении):

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

Но используя это, я получил эту ошибку:

Не удалось найти метод filter() для аргументов [{{Лексемы = 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, signedConfig = null}] on BuildTypeD sl_Decorated {name = buderusFinal, debuggable = false, jniDebugBuild = false, renderscr iptDebugBuild = false, renderscriptOptimLevel = 3, packageNameSuffix = null, versionNa meSuffix = null, runProguard = false, zipAlign = true, signedConfig = null}.

Нужно ли определять собственную задачу для метода фильтрации?

EDIT [2013_07_09]:

Строка в src/flavor1/res:

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

Код в build.gradle для замены строки:

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

Ответ 1

Я решил проблему самостоятельно, так что вот решение "шаг за шагом" - возможно, это поможет некоторым другим новичкам в gradle:)

  • Скопировать задачу в целом:
copy{
    from("pathToMyFolder"){
        include "my.file"
    }
    // you have to use a new path for youre modified file
    into("pathToFolderWhereToCopyMyNewFile")
}
  • Заменить строку в целом:
filter{
    String line -> line.replaceAll("<complete line of regular expression>",
                                   "<complete line of modified expression>")
}
  • Я думаю, что самая большая проблема заключалась в том, чтобы получить правильные пути, потому что мне приходилось делать это динамически (эта ссылка была очень полезной для меня). Я решил свою проблему, заменив специальные строки в манифесте, а не в String файле.

  • В следующем примере показано, как заменить мета-данные -tag в манифесте, чтобы использовать ваши google-maps-api-key (в моем случае есть разные варианты, которые используют разные ключи):

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

Ответ 2

Я использую почти тот подход, который вы хотели. replaceInManfest также является общим и может использоваться и для других заполнителей. Метод getGMapsKey() просто возвращает соответствующий ключ на основе типа build.

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

У меня есть на gist, если вы хотите узнать, развивается ли он позже.

Я нашел, что это более элегантный и обобщаемый подход, чем другие (хотя замена токена просто работала бы лучше).

Ответ 3

Ответы довольно устарели, теперь лучше их архивировать. Вы можете использовать команду в файле build.gradle:

manifestPlaceholders = [
            myPlaceholder: "placeholder",
    ]

и в вашем манифесте:

android:someManifestAttribute="${myPlaceholder}"

дополнительную информацию можно найти здесь: https://developer.android.com/studio/build/manifest-merge.html

Ответ 4

В текущем DSL-телефоне Android Gradle класс ApplicationVariant изменился, и подход Saad должен быть перезаписан, например. следующим образом:

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

Новый DSL также предлагает более чистый подход для непосредственного доступа к файлу манифеста.