Here's a simple example of a gradle task executed before "preBuild" which checks all strings.xml it finds for string values with unescaped apostrophes. If errors found, fails build. Change the dependency as needed for your download task.
(Note the script fails on first error encountered - so if there is both an error in the en version and es version then only one file is reported as error.)
(Note2 since an XML parser is used it is only processing string-tagged values - and consequently also ignores any violations in xml comments - this is evident in the first test case of no errors.)
(In Module: app (build.gradle))
task checkUnescapedApostrophes {
doFirst {
println("checkUnescapedApostrophes")
fileTree("src").matching {
include "**/strings.xml"
}.each {
def stringsFile = it
def parser = (new XmlParser()).parse(stringsFile)
println("Processing file: "+stringsFile)
parser.'string'.each { m ->
def s = m.text()
def ss = "[^\\\\]\'"
println "[" + m.@name + "]: " + s
if (s =~ ss) {
throw new GradleException(
"Found a string value in " + stringsFile +
" have unescaped apostrophe: "+s)
}
}
}
println("strings.xml OK")
}
}
preBuild.dependsOn(checkUnescapedApostrophes)
In no-errors case of strings.xml (default locale + es):
<resources>
<!-- <string name="test">some value with '</string> -->
<string name="test2">some with escaped \'</string>
</resources>
<resources>
<!-- <string name="test">algún valor con apóstrofe sin escape '</string> -->
<string name="test2">algún valor con el apóstrofe escapado \'</string>
</resources>
Build Output:
> Configure project :app
checkUnescapedApostrophes
Processing file: ...\app\src\main\res\values\strings.xml
[test2]: some with escaped \'
Processing file: ....\app\src\main\res\values-es\strings.xml
[test2]: algún error con el apóstrofe escapado \'
strings.xml OK
> Task :app:checkUnescapedApostrophes UP-TO-DATE
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:checkDebugManifest UP-TO-DATE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:prepareLintJar UP-TO-DATE
> Task :app:prepareLintJarForPublish UP-TO-DATE
> Task :app:generateDebugSources UP-TO-DATE
BUILD SUCCESSFUL in 1s
4 actionable tasks: 4 up-to-date
And in error case of strings.xml (in default local and es)
<resources>
<string name="test">some value with '</string>
<string name="test2">some with escaped \'</string>
</resources>
<resources>
<string name="test">algún valor con apóstrofe sin escape '</string>
<string name="test2">algún valor con el apóstrofe escapado \'</string>
</resources>
(Note that in the above cases the unescaped apostraphe is red-flagged in studio with an error - as expected.)
Build Output:
> Configure project :app
checkUnescapedApostrophes
Processing file: ...\app\src\main\res\values\strings.xml
[test]: some value with '
FAILURE: Build failed with an exception.
* Where:
Build file '...\app\build.gradle' line: 43
* What went wrong:
A problem occurred evaluating project ':app'.
> Found a string value in ...\app\src\main\res\values\strings.xml have unescaped apostrophe: some value with '
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 1s
General gradle note: when testing for yourself and changing build.gradle - be sure to 'Rebuild Project' and not just 'Build Project' as any gradle changes don't seem to be picked up in the case when the build previously failed.
Also as an alternative which you mentioned this task will escape unescaped apostrophes by replacing in all strings.xml found. This is an in-place update - there is a more robust approach here: https://stackoverflow.com/a/48356111/2711811.
task replaceUnescapedApostrophes {
doFirst {
ant.replaceregexp(match: "([^\\\\])'", replace: "\\1\\\\\\\\'", byline: "true") {
fileset(dir: 'src/', excludes: '*', includes: '**/*strings.xml')
}
}
}
//preBuild.dependsOn(checkUnescapedApostrophes)
preBuild.dependsOn(replaceUnescapedApostrophes)