/** * Checks if the replacement was properly made to a node. * * @param file File we are searching for value * @param saved boolean on whether we need to save * @param provider Node we are attempting to replace * @return boolean * @throws AndrolibException setting node value failed */ private static boolean isSaved(File file, boolean saved, Node provider) throws AndrolibException { String reference = provider.getNodeValue(); String replacement = pullValueFromStrings(file.getParentFile(), reference); if (replacement != null) { provider.setNodeValue(replacement); saved = true; } return saved; }
private void buildManifestFile(File appDir, File manifest, File manifestOriginal) throws AndrolibException { // If we decoded in "raw", we cannot patch AndroidManifest if (new File(appDir, "resources.arsc").exists()) { return; } if (manifest.isFile() && manifest.exists()) { try { if (manifestOriginal.exists()) { manifestOriginal.delete(); } FileUtils.copyFile(manifest, manifestOriginal); ResXmlPatcher.fixingPublicAttrsInProviderAttributes(manifest); } catch (IOException ex) { throw new AndrolibException(ex.getMessage()); } } }
if (file.exists()) { try { Document doc = loadDocument(file); XPath xPath = XPathFactory.newInstance().newXPath(); XPathExpression expression = xPath.compile("/manifest/application/provider"); saved = isSaved(file, saved, provider); saved = isSaved(file, saved, provider); saveDocument(file, doc);
/** * Replaces package value with passed packageOriginal string * * @param file File for AndroidManifest.xml * @param packageOriginal Package name to replace * @throws AndrolibException */ public static void renameManifestPackage(File file, String packageOriginal) throws AndrolibException { try { Document doc = loadDocument(file); // Get the manifest line Node manifest = doc.getFirstChild(); // update package attribute NamedNodeMap attr = manifest.getAttributes(); Node nodeAttr = attr.getNamedItem("package"); nodeAttr.setNodeValue(packageOriginal); saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } }
/** * Finds key in strings.xml file and returns text value * * @param directory Root directory of apk * @param key String reference (ie @string/foo) * @return String|null * @throws AndrolibException */ public static String pullValueFromStrings(File directory, String key) throws AndrolibException { if (key == null || ! key.contains("@")) { return null; } File file = new File(directory, "/res/values/strings.xml"); key = key.replace("@string/", ""); if (file.exists()) { try { Document doc = loadDocument(file); XPath xPath = XPathFactory.newInstance().newXPath(); XPathExpression expression = xPath.compile("/resources/string[@name=" + '"' + key + "\"]/text()"); Object result = expression.evaluate(doc, XPathConstants.STRING); if (result != null) { return (String) result; } } catch (SAXException | ParserConfigurationException | IOException | XPathExpressionException ignored) { } } return null; }
public void adjustPackageManifest(ResTable resTable, String filePath) throws AndrolibException { // compare resources.arsc package name to the one present in AndroidManifest ResPackage resPackage = resTable.getCurrentResPackage(); String packageOriginal = resPackage.getName(); mPackageRenamed = resTable.getPackageRenamed(); resTable.setPackageId(resPackage.getId()); resTable.setPackageOriginal(packageOriginal); // 1) Check if packageOriginal === mPackageRenamed // 2) Check if packageOriginal is ignored via IGNORED_PACKAGES // 2a) If its ignored, make sure the mPackageRenamed isn't explicitly allowed if (packageOriginal.equalsIgnoreCase(mPackageRenamed) || (Arrays.asList(IGNORED_PACKAGES).contains(packageOriginal) && ! Arrays.asList(ALLOWED_PACKAGES).contains(mPackageRenamed))) { LOGGER.info("Regular manifest package..."); } else { LOGGER.info("Renamed manifest package found! Replacing " + mPackageRenamed + " with " + packageOriginal); ResXmlPatcher.renameManifestPackage(new File(filePath), packageOriginal); } }
ResXmlPatcher.removeApplicationDebugTag(new File(appDir, "AndroidManifest.xml"));
public void decodeManifestWithResources(ResTable resTable, ExtFile apkFile, File outDir) throws AndrolibException { Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder(); ResFileDecoder fileDecoder = duo.m1; ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder(); attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator().next()); Directory inApk, in = null, out; try { inApk = apkFile.getDirectory(); out = new FileDirectory(outDir); LOGGER.info("Decoding AndroidManifest.xml with resources..."); fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out, "AndroidManifest.xml"); // Remove versionName / versionCode (aapt API 16) if (!resTable.getAnalysisMode()) { // check for a mismatch between resources.arsc package and the package listed in AndroidManifest // also remove the android::versionCode / versionName from manifest for rebuild // this is a required change to prevent aapt warning about conflicting versions // it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml adjustPackageManifest(resTable, outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"); ResXmlPatcher.removeManifestVersions(new File( outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml")); mPackageId = String.valueOf(resTable.getPackageId()); } } catch (DirectoryException ex) { throw new AndrolibException(ex); } }
/** * Removes "debug" tag from file * * @param file AndroidManifest file * @throws AndrolibException */ public static void removeApplicationDebugTag(File file) throws AndrolibException { if (file.exists()) { try { Document doc = loadDocument(file); Node application = doc.getElementsByTagName("application").item(0); // load attr NamedNodeMap attr = application.getAttributes(); Node debugAttr = attr.getNamedItem("android:debuggable"); // remove application:debuggable if (debugAttr != null) { attr.removeNamedItem("android:debuggable"); } saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } } }
private void putVersionInfo(MetaInfo meta) throws AndrolibException { VersionInfo info = getResTable().getVersionInfo(); String refValue = ResXmlPatcher.pullValueFromStrings(mOutDir, info.versionName); if (refValue != null) { info.versionName = refValue; } meta.versionInfo = info; }
/** * Removes attributes like "versionCode" and "versionName" from file. * * @param file File representing AndroidManifest.xml * @throws AndrolibException */ public static void removeManifestVersions(File file) throws AndrolibException { if (file.exists()) { try { Document doc = loadDocument(file); Node manifest = doc.getFirstChild(); NamedNodeMap attr = manifest.getAttributes(); Node vCode = attr.getNamedItem("android:versionCode"); Node vName = attr.getNamedItem("android:versionName"); if (vCode != null) { attr.removeNamedItem("android:versionCode"); } if (vName != null) { attr.removeNamedItem("android:versionName"); } saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } } }
private void putVersionInfo(MetaInfo meta) throws AndrolibException { VersionInfo info = getResTable().getVersionInfo(); String refValue = ResXmlPatcher.pullValueFromStrings(mOutDir, info.versionName); if (refValue != null) { info.versionName = refValue; } meta.versionInfo = info; }