diff --git a/CHANGES b/CHANGES index d93f584f..213a9173 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,7 @@ v2.0.0 (TBA) -Fixed (issue #8) - Correctly uses -c to retain original manifest and META-INF. Thanks M1cha -Fixed (issue #403) - Uses new usage output to cleanup organization of features. -Fixed (issue #359) - Correclty handles malformed 9patch images. (Thanks Felipe Richards) +-Fixed (issue #401) - Uses versionInfo meta to correctly parse versionName and versionCode v1.5.3 (TBA) -Updated to smali/baksmali to v1.4.2 diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java index 9397a89f..ed035fde 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -32,6 +32,21 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -209,6 +224,7 @@ public class Androlib { : (Boolean) meta.get("compressionType")); mAndRes.setSdkInfo((Map) meta.get("sdkInfo")); mAndRes.setPackageId((String)meta.get("packageId")); + mAndRes.setVersionInfo((Map) meta.get("versionInfo")); if (outFile == null) { String outFileName = (String) meta.get("apkFileName"); @@ -469,6 +485,54 @@ public class Androlib { } } + public void remove_manifest_versions(String filePath) + throws AndrolibException { + + File f = new File(filePath); + + if (f.exists()) { + // remove versionCode and versionName + try { + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(filePath.toString()); + + Node manifest = doc.getFirstChild(); + + // load attr + NamedNodeMap attr = manifest.getAttributes(); + Node vCode = attr.getNamedItem("android:versionCode"); + Node vName = attr.getNamedItem("android:versionName"); + + // remove versionCode + if (vCode != null) { + attr.removeNamedItem("android:versionCode"); + } + if (vName != null) { + attr.removeNamedItem("android:versionName"); + } + + // save manifest + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = new DOMSource(doc); + StreamResult result = new StreamResult(new File(filePath)); + transformer.transform(source, result); + + } catch (ParserConfigurationException ex) { + throw new AndrolibException(ex); + } catch (SAXException ex) { + throw new AndrolibException(ex); + } catch (IOException ex) { + throw new AndrolibException(ex); + } catch (TransformerConfigurationException ex) { + throw new AndrolibException(ex); + } catch (TransformerException ex) { + throw new AndrolibException(ex); + } + } + } + public void buildApk(File appDir, File outApk, HashMap flags) throws AndrolibException { LOGGER.info("Building apk file..."); diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index b7145f3b..78369699 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -109,31 +109,34 @@ public class ApkDecoder { jf.close(); switch (mDecodeResources) { - case DECODE_RESOURCES_NONE: - mAndrolib.decodeResourcesRaw(mApkFile, outDir); - break; - case DECODE_RESOURCES_FULL: - mAndrolib.decodeResourcesFull(mApkFile, outDir, getResTable()); - break; - } + case DECODE_RESOURCES_NONE: + mAndrolib.decodeResourcesRaw(mApkFile, outDir); + break; + case DECODE_RESOURCES_FULL: + mAndrolib.decodeResourcesFull(mApkFile, outDir, getResTable()); + break; + } } else { // if there's no resources.asrc, decode the manifest without looking // up attribute references if (hasManifest()) { switch (mDecodeResources) { - case DECODE_RESOURCES_NONE: - mAndrolib.decodeManifestRaw(mApkFile, outDir); - break; - case DECODE_RESOURCES_FULL: - mAndrolib.decodeManifestFull(mApkFile, outDir, - getResTable()); - break; + case DECODE_RESOURCES_NONE: + mAndrolib.decodeManifestRaw(mApkFile, outDir); + break; + case DECODE_RESOURCES_FULL: + mAndrolib.decodeManifestFull(mApkFile, outDir, + getResTable()); + break; } } } mAndrolib.decodeRawFiles(mApkFile, outDir); mAndrolib.writeOriginalFiles(mApkFile, outDir); + + // remove version names in favour of aapt injection + mAndrolib.remove_manifest_versions(outDir.getAbsolutePath() + "/AndroidManifest.xml"); writeMetaFile(); } @@ -245,8 +248,9 @@ public class ApkDecoder { putUsesFramework(meta); putSdkInfo(meta); putPackageInfo(meta); + putVersionInfo(meta); putCompressionInfo(meta); - meta.put("packageId", getResTable().getPackageInfo().get("cur_package_id")); + //meta.put("packageId", getResTable().getPackageInfo().get("cur_package_id")); } mAndrolib.writeMetaFile(mOutDir, meta); @@ -290,6 +294,13 @@ public class ApkDecoder { meta.put("packageInfo", info); } } + + private void putVersionInfo(Map meta) throws AndrolibException { + Map info = getResTable().getVersionInfo(); + if (info.size() > 0) { + meta.put("versionInfo", info); + } + } private void putCompressionInfo(Map meta) throws AndrolibException { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java index 59b830b0..08978eb3 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java @@ -193,7 +193,7 @@ final public class AndrolibResources { } catch (TransformerException ex) { throw new AndrolibException(ex); } - } + } public void adjust_package_manifest(ResTable resTable, String filePath) throws AndrolibException { @@ -201,10 +201,9 @@ final public class AndrolibResources { // check if packages different, and that package is not equal to // "android" Map packageInfo = resTable.getPackageInfo(); - if ((packageInfo.get("cur_package").equalsIgnoreCase( - packageInfo.get("orig_package")) || ("android" - .equalsIgnoreCase(packageInfo.get("cur_package")) || ("com.htc" - .equalsIgnoreCase(packageInfo.get("cur_package")))))) { + if ((packageInfo.get("cur_package").equalsIgnoreCase(packageInfo.get("orig_package")) || + ("android".equalsIgnoreCase(packageInfo.get("cur_package")) || + ("com.htc".equalsIgnoreCase(packageInfo.get("cur_package")))))) { LOGGER.info("Regular manifest package..."); } else { @@ -306,6 +305,13 @@ final public class AndrolibResources { mMaxSdkVersion = map.get("maxSdkVersion"); } } + + public void setVersionInfo(Map map) { + if (map != null) { + mVersionCode = map.get("versionCode"); + mVersionName = map.get("versionName"); + } + } public void setPackageInfo(Map map) { if (map != null) { @@ -379,6 +385,14 @@ final public class AndrolibResources { cmd.add("--rename-manifest-package"); cmd.add(mPackageRenamed); } + if (mVersionCode != null) { + cmd.add("--version-code"); + cmd.add(mVersionCode); + } + if (mVersionName != null) { + cmd.add("--version-name"); + cmd.add(mVersionName); + } cmd.add("-F"); cmd.add(apkFile.getAbsolutePath()); @@ -758,6 +772,8 @@ final public class AndrolibResources { private String mMinSdkVersion = null; private String mMaxSdkVersion = null; private String mTargetSdkVersion = null; + private String mVersionCode = null; + private String mVersionName = null; private String mPackageRenamed = null; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java index b3c752d0..198083eb 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java @@ -37,6 +37,7 @@ public class ResTable { private Map mSdkInfo = new LinkedHashMap(); private Map mPackageInfo = new LinkedHashMap(); + private Map mVersionInfo = new LinkedHashMap(); public ResTable() { mAndRes = null; @@ -119,17 +120,17 @@ public class ResTable { public void setFrameTag(String tag) { mFrameTag = tag; } - - public Map getSdkInfo() { - return mSdkInfo; + + public void clearSdkInfo() { + mSdkInfo.clear(); } public void addSdkInfo(String key, String value) { mSdkInfo.put(key, value); } - - public void clearSdkInfo() { - mSdkInfo.clear(); + + public void addVersionInfo(String key, String value) { + mVersionInfo.put(key, value); } public void addPackageInfo(String key, String value) { @@ -139,6 +140,14 @@ public class ResTable { public Map getPackageInfo() { return mPackageInfo; } + + public Map getVersionInfo() { + return mVersionInfo; + } + + public Map getSdkInfo() { + return mSdkInfo; + } public boolean isPackageInfoValueSet(String key) { return (mPackageInfo.containsKey(key)); diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java index 89643fc3..28f9dd8e 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java @@ -93,11 +93,13 @@ public class XmlPullStreamDecoder implements ResStreamDecoder { // read for package: for (int i = 0; i < pp.getAttributeCount(); i++) { - if (pp.getAttributeName(i) - .equalsIgnoreCase(("package"))) { - restable.addPackageInfo("orig_package", - pp.getAttributeValue(i)); - } + if (pp.getAttributeName(i).equalsIgnoreCase(("package"))) { + restable.addPackageInfo("orig_package",pp.getAttributeValue(i)); + } else if (pp.getAttributeName(i).equalsIgnoreCase("versionCode")) { + restable.addVersionInfo("versionCode", pp.getAttributeValue(i)); + } else if (pp.getAttributeName(i).equalsIgnoreCase("versionName")) { + restable.addVersionInfo("versionName", pp.getAttributeValue(i)); + } } return true; }