diff --git a/build.sh b/build.sh index 1a4fc86..237dfed 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ #!/bin/bash mvn clean compile assembly:single -cp ./target/appium_apk_tools-0.0.2-SNAPSHOT-jar-with-all.jar ./appium_apk_tools.jar \ No newline at end of file +cp ./target/appium_apk_tools-0.0.3-SNAPSHOT-jar-with-all.jar ./appium_apk_tools.jar \ No newline at end of file diff --git a/lib/apktool-cli-2.2.2-SNAPSHOT.jar b/lib/apktool-cli-2.2.2-SNAPSHOT.jar new file mode 100644 index 0000000..12aea5d Binary files /dev/null and b/lib/apktool-cli-2.2.2-SNAPSHOT.jar differ diff --git a/pom.xml b/pom.xml index 0eb0e7b..76aba54 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 appium_apk_tools appium_apk_tools - 0.0.2-SNAPSHOT + 0.0.3-SNAPSHOT appium_apk_tools jar @@ -25,8 +25,8 @@ maven-compiler-plugin 3.0 - 1.6 - 1.6 + 1.7 + 1.7 @@ -56,12 +56,12 @@ apktool.snapshot apktool - 1.5.3 + 2.2.2 system - ${project.basedir}/lib/apktool-cli-1.5.3-SNAPSHOT.jar + ${project.basedir}/lib/apktool-cli-2.2.2-SNAPSHOT.jar diff --git a/src/io/appium/apktools/StringsXML.java b/src/io/appium/apktools/StringsXML.java index 5ed2a67..6a877c7 100644 --- a/src/io/appium/apktools/StringsXML.java +++ b/src/io/appium/apktools/StringsXML.java @@ -12,6 +12,7 @@ import brut.androlib.res.data.ResResource; import brut.androlib.res.data.ResTable; import brut.androlib.res.data.ResValuesFile; +import brut.androlib.res.data.value.ResPluralsValue; import brut.androlib.res.data.value.ResScalarValue; import brut.androlib.res.util.ExtFile; import brut.androlib.res.util.ExtMXSerializer; @@ -34,15 +35,16 @@ public static void p(final Object msg) { } } - public static void toJSON(final ResValuesFile input, - final File outputDirectory) throws Exception { - String[] paths = input.getPath().split("/"); // always "/" even on Windows + public static void toJSON(final ResValuesFile stringValues, + final ResValuesFile pluralsValues, + final File outputDirectory) throws Exception { + String[] paths = stringValues.getPath().split("/"); // always "/" even on Windows final String outName = paths[paths.length - 1].replaceFirst("\\.xml$", - ".json"); + ".json"); final File outFile = new File(outputDirectory, outName); p("Saving to: " + outFile); JsonGenerator generator = json.createGenerator( - new FileOutputStream(outFile), JsonEncoding.UTF8); + new FileOutputStream(outFile), JsonEncoding.UTF8); // Ensure output stream is auto closed when generator.close() is called. generator.configure(Feature.AUTO_CLOSE_TARGET, true); @@ -56,20 +58,48 @@ public static void toJSON(final ResValuesFile input, generator.useDefaultPrettyPrinter(); // ResStringValue extends ResScalarValue which has field mRawValue - final Field valueField = ResScalarValue.class.getDeclaredField("mRawValue"); - valueField.setAccessible(true); + final Field stringValueField = ResScalarValue.class.getDeclaredField("mRawValue"); + stringValueField.setAccessible(true); + final Field pluralsValueField = ResPluralsValue.class.getDeclaredField("mItems"); + pluralsValueField.setAccessible(true); + final Field pluralsQuantityField = ResPluralsValue.class.getDeclaredField("QUANTITY_MAP"); + pluralsQuantityField.setAccessible(true); + final String[] pluralsQuantities = (String[]) pluralsQuantityField.get(String[].class); generator.writeStartObject(); - for (ResResource resource : input.listResources()) { - if (input.isSynthesized(resource)) { + for (ResResource resource : stringValues.listResources()) { + if (stringValues.isSynthesized(resource)) { continue; } final String name = resource.getResSpec().getName(); // Get the value field from the ResStringValue object. - final String value = (String) valueField.get(resource.getValue()); + final String value = (String) stringValueField.get(resource.getValue()); generator.writeStringField(name, value); } + + if (pluralsValues != null) + { + for (ResResource resource : pluralsValues.listResources()) { + if (pluralsValues.isSynthesized(resource)) { + continue; + } + + final String name = resource.getResSpec().getName(); + generator.writeObjectFieldStart(name); + // Get the values field from the ResPluralsValue object. + ResScalarValue[] valuesArray = (ResScalarValue[]) pluralsValueField.get(resource.getValue()); + for (int i = 0; i < valuesArray.length; i++) + { + ResScalarValue value = valuesArray[i]; + if (value != null) { + generator.writeStringField(pluralsQuantities[i], value.encodeAsResXmlValue()); + } + } + generator.writeEndObject(); + } + } + generator.writeEndObject(); generator.flush(); generator.close(); @@ -83,19 +113,27 @@ public static void run(final File input, final File outputDirectory, final ExtFile apkFile = new ExtFile(input); ResTable table = res.getResTable(apkFile, true); ResValuesFile stringsXML = null; + ResValuesFile pluralsXML = null; + final String stringsTargetPath = (localization + "/strings.xml").toLowerCase(); + final String pluralsTargetPath = (localization + "/plurals.xml").toLowerCase(); for (ResPackage pkg : table.listMainPackages()) { p(pkg); for (ResValuesFile values : pkg.listValuesFiles()) { // strings.xml is not case sensitive. xamarin will call it Strings.xml final String path = values.getPath().toLowerCase(); - final String targetPath = (localization + "/strings.xml").toLowerCase(); p(path); - if (path.endsWith(targetPath)) { + if (path.endsWith(stringsTargetPath)) { stringsXML = values; + } + if (path.endsWith(pluralsTargetPath)) { + pluralsXML = values; + } + if (stringsXML != null && pluralsXML != null) + { break; } } - if (stringsXML != null) { + if (stringsXML != null && pluralsXML != null) { break; } } @@ -104,7 +142,8 @@ public static void run(final File input, final File outputDirectory, e("Could not find the strings.xml file for localization: " + localization); } - toJSON(stringsXML, outputDirectory); + toJSON(stringsXML, pluralsXML, outputDirectory); + p("complete"); }