mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-02 17:12:55 +01:00
refactor: clean up style and redundancy (#3232)
* refactor: clean up redundancy * refactor: no need for both setApkFile and setApkFileName
This commit is contained in:
parent
ce180dce87
commit
33ca2929c9
@ -29,8 +29,7 @@ import brut.util.AaptManager;
|
||||
import brut.util.OSDetection;
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
|
@ -22,13 +22,8 @@ import brut.common.BrutException;
|
||||
import brut.util.AaptManager;
|
||||
import brut.util.OS;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AaptInvoker {
|
||||
@ -81,8 +76,7 @@ public class AaptInvoker {
|
||||
}
|
||||
|
||||
private void invokeAapt2(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include,
|
||||
List<String> cmd, boolean customAapt)
|
||||
throws AndrolibException {
|
||||
List<String> cmd, boolean customAapt) throws AndrolibException {
|
||||
|
||||
List<String> compileCommand = new ArrayList<>(cmd);
|
||||
File resourcesZip = null;
|
||||
@ -249,8 +243,7 @@ public class AaptInvoker {
|
||||
}
|
||||
|
||||
private void invokeAapt1(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include,
|
||||
List<String> cmd, boolean customAapt)
|
||||
throws AndrolibException {
|
||||
List<String> cmd, boolean customAapt) throws AndrolibException {
|
||||
|
||||
cmd.add("p");
|
||||
|
||||
@ -365,7 +358,7 @@ public class AaptInvoker {
|
||||
}
|
||||
|
||||
public void invokeAapt(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include)
|
||||
throws AndrolibException {
|
||||
throws AndrolibException {
|
||||
|
||||
String aaptPath = mConfig.aaptPath;
|
||||
boolean customAapt = !aaptPath.isEmpty();
|
||||
|
@ -52,9 +52,9 @@ public class ApkBuilder {
|
||||
private final static Logger LOGGER = Logger.getLogger(ApkBuilder.class.getName());
|
||||
|
||||
private final Config mConfig;
|
||||
private final ExtFile mApkDir;
|
||||
private ApkInfo mApkInfo;
|
||||
private int mMinSdkVersion = 0;
|
||||
private final ExtFile mApkDir;
|
||||
|
||||
private final static String APK_DIRNAME = "build/apk";
|
||||
private final static String UNK_DIRNAME = "unknown";
|
||||
@ -87,7 +87,7 @@ public class ApkBuilder {
|
||||
}
|
||||
|
||||
if (outFile == null) {
|
||||
String outFileName = mApkInfo.getApkFileName();
|
||||
String outFileName = mApkInfo.apkFileName;
|
||||
outFile = new File(mApkDir, "dist" + File.separator + (outFileName == null ? "out.apk" : outFileName));
|
||||
}
|
||||
|
||||
@ -96,17 +96,17 @@ public class ApkBuilder {
|
||||
File manifest = new File(mApkDir, "AndroidManifest.xml");
|
||||
File manifestOriginal = new File(mApkDir, "AndroidManifest.xml.orig");
|
||||
|
||||
buildSources(mApkDir);
|
||||
buildNonDefaultSources(mApkDir);
|
||||
buildManifestFile(mApkDir, manifest, manifestOriginal);
|
||||
buildResources(mApkDir, mApkInfo.usesFramework);
|
||||
buildLibs(mApkDir);
|
||||
buildCopyOriginalFiles(mApkDir);
|
||||
buildApk(mApkDir, outFile);
|
||||
buildSources();
|
||||
buildNonDefaultSources();
|
||||
buildManifestFile(manifest, manifestOriginal);
|
||||
buildResources();
|
||||
buildLibs();
|
||||
buildCopyOriginalFiles();
|
||||
buildApk(outFile);
|
||||
|
||||
// we must go after the Apk is built, and copy the files in via Zip
|
||||
// this is because Aapt won't add files it doesn't know (ex unknown files)
|
||||
buildUnknownFiles(mApkDir, outFile, mApkInfo);
|
||||
buildUnknownFiles(outFile);
|
||||
|
||||
// we copied the AndroidManifest.xml to AndroidManifest.xml.orig so we can edit it
|
||||
// lets restore the unedited one, to not change the original
|
||||
@ -122,11 +122,9 @@ public class ApkBuilder {
|
||||
LOGGER.info("Built apk into: " + outFile.getPath());
|
||||
}
|
||||
|
||||
private void buildManifestFile(File appDir, File manifest, File manifestOriginal)
|
||||
throws AndrolibException {
|
||||
|
||||
private void buildManifestFile(File manifest, File manifestOriginal) throws AndrolibException {
|
||||
// If we decoded in "raw", we cannot patch AndroidManifest
|
||||
if (new File(appDir, "resources.arsc").exists()) {
|
||||
if (new File(mApkDir, "resources.arsc").exists()) {
|
||||
return;
|
||||
}
|
||||
if (manifest.isFile() && manifest.exists()) {
|
||||
@ -143,36 +141,34 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildSources(File appDir)
|
||||
throws AndrolibException {
|
||||
if (!buildSourcesRaw(appDir, "classes.dex") && !buildSourcesSmali(appDir, "smali", "classes.dex")) {
|
||||
private void buildSources() throws AndrolibException {
|
||||
if (!buildSourcesRaw("classes.dex") && !buildSourcesSmali("smali", "classes.dex")) {
|
||||
LOGGER.warning("Could not find sources");
|
||||
}
|
||||
}
|
||||
|
||||
private void buildNonDefaultSources(ExtFile appDir)
|
||||
throws AndrolibException {
|
||||
private void buildNonDefaultSources() throws AndrolibException {
|
||||
try {
|
||||
// loop through any smali_ directories for multi-dex apks
|
||||
Map<String, Directory> dirs = appDir.getDirectory().getDirs();
|
||||
Map<String, Directory> dirs = mApkDir.getDirectory().getDirs();
|
||||
for (Map.Entry<String, Directory> directory : dirs.entrySet()) {
|
||||
String name = directory.getKey();
|
||||
if (name.startsWith("smali_")) {
|
||||
String filename = name.substring(name.indexOf("_") + 1) + ".dex";
|
||||
|
||||
if (!buildSourcesRaw(appDir, filename) && !buildSourcesSmali(appDir, name, filename)) {
|
||||
if (!buildSourcesRaw(filename) && !buildSourcesSmali(name, filename)) {
|
||||
LOGGER.warning("Could not find sources");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop through any classes#.dex files for multi-dex apks
|
||||
File[] dexFiles = appDir.listFiles();
|
||||
File[] dexFiles = mApkDir.listFiles();
|
||||
if (dexFiles != null) {
|
||||
for (File dex : dexFiles) {
|
||||
// skip classes.dex because we have handled it in buildSources()
|
||||
if (dex.getName().endsWith(".dex") && ! dex.getName().equalsIgnoreCase("classes.dex")) {
|
||||
buildSourcesRaw(appDir, dex.getName());
|
||||
if (dex.getName().endsWith(".dex") && !dex.getName().equalsIgnoreCase("classes.dex")) {
|
||||
buildSourcesRaw(dex.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,15 +177,14 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean buildSourcesRaw(File appDir, String filename)
|
||||
throws AndrolibException {
|
||||
File working = new File(appDir, filename);
|
||||
private boolean buildSourcesRaw(String filename) throws AndrolibException {
|
||||
File working = new File(mApkDir, filename);
|
||||
if (!working.exists()) {
|
||||
return false;
|
||||
}
|
||||
File stored = new File(appDir, APK_DIRNAME + "/" + filename);
|
||||
File stored = new File(mApkDir, APK_DIRNAME + "/" + filename);
|
||||
if (mConfig.forceBuildAll || isModified(working, stored)) {
|
||||
LOGGER.info("Copying " + appDir.toString() + " " + filename + " file...");
|
||||
LOGGER.info("Copying " + mApkDir.toString() + " " + filename + " file...");
|
||||
try {
|
||||
BrutIO.copyAndClose(Files.newInputStream(working.toPath()), Files.newOutputStream(stored.toPath()));
|
||||
return true;
|
||||
@ -200,14 +195,13 @@ public class ApkBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean buildSourcesSmali(File appDir, String folder, String filename)
|
||||
throws AndrolibException {
|
||||
ExtFile smaliDir = new ExtFile(appDir, folder);
|
||||
private boolean buildSourcesSmali(String folder, String filename) throws AndrolibException {
|
||||
ExtFile smaliDir = new ExtFile(mApkDir, folder);
|
||||
if (!smaliDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
File dex = new File(appDir, APK_DIRNAME + "/" + filename);
|
||||
if (! mConfig.forceBuildAll) {
|
||||
File dex = new File(mApkDir, APK_DIRNAME + "/" + filename);
|
||||
if (!mConfig.forceBuildAll) {
|
||||
LOGGER.info("Checking whether sources has changed...");
|
||||
}
|
||||
if (mConfig.forceBuildAll || isModified(smaliDir, dex)) {
|
||||
@ -219,28 +213,25 @@ public class ApkBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void buildResources(ExtFile appDir, UsesFramework usesFramework)
|
||||
throws BrutException {
|
||||
if (!buildResourcesRaw(appDir) && !buildResourcesFull(appDir, usesFramework)
|
||||
&& !buildManifest(appDir, usesFramework)) {
|
||||
private void buildResources() throws BrutException {
|
||||
if (!buildResourcesRaw() && !buildResourcesFull() && !buildManifest()) {
|
||||
LOGGER.warning("Could not find resources");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean buildResourcesRaw(ExtFile appDir)
|
||||
throws AndrolibException {
|
||||
private boolean buildResourcesRaw() throws AndrolibException {
|
||||
try {
|
||||
if (!new File(appDir, "resources.arsc").exists()) {
|
||||
if (!new File(mApkDir, "resources.arsc").exists()) {
|
||||
return false;
|
||||
}
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
if (! mConfig.forceBuildAll) {
|
||||
File apkDir = new File(mApkDir, APK_DIRNAME);
|
||||
if (!mConfig.forceBuildAll) {
|
||||
LOGGER.info("Checking whether resources has changed...");
|
||||
}
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APK_RESOURCES_FILENAMES, appDir),
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APK_RESOURCES_FILENAMES, mApkDir),
|
||||
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
||||
LOGGER.info("Copying raw resources...");
|
||||
appDir.getDirectory().copyToDir(apkDir, APK_RESOURCES_FILENAMES);
|
||||
mApkDir.getDirectory().copyToDir(apkDir, APK_RESOURCES_FILENAMES);
|
||||
}
|
||||
return true;
|
||||
} catch (DirectoryException ex) {
|
||||
@ -248,46 +239,45 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean buildResourcesFull(File appDir, UsesFramework usesFramework)
|
||||
throws AndrolibException {
|
||||
private boolean buildResourcesFull() throws AndrolibException {
|
||||
try {
|
||||
if (!new File(appDir, "res").exists()) {
|
||||
if (!new File(mApkDir, "res").exists()) {
|
||||
return false;
|
||||
}
|
||||
if (! mConfig.forceBuildAll) {
|
||||
if (!mConfig.forceBuildAll) {
|
||||
LOGGER.info("Checking whether resources has changed...");
|
||||
}
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
File apkDir = new File(mApkDir, APK_DIRNAME);
|
||||
File resourceFile = new File(apkDir.getParent(), "resources.zip");
|
||||
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APP_RESOURCES_FILENAMES, appDir),
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APP_RESOURCES_FILENAMES, mApkDir),
|
||||
newFiles(APK_RESOURCES_FILENAMES, apkDir)) || (mConfig.isAapt2() && !isFile(resourceFile))) {
|
||||
LOGGER.info("Building resources...");
|
||||
|
||||
if (mConfig.debugMode) {
|
||||
if (mConfig.isAapt2()) {
|
||||
LOGGER.info("Using aapt2 - setting 'debuggable' attribute to 'true' in AndroidManifest.xml");
|
||||
ResXmlPatcher.setApplicationDebugTagTrue(new File(appDir, "AndroidManifest.xml"));
|
||||
ResXmlPatcher.setApplicationDebugTagTrue(new File(mApkDir, "AndroidManifest.xml"));
|
||||
} else {
|
||||
ResXmlPatcher.removeApplicationDebugTag(new File(appDir, "AndroidManifest.xml"));
|
||||
ResXmlPatcher.removeApplicationDebugTag(new File(mApkDir, "AndroidManifest.xml"));
|
||||
}
|
||||
}
|
||||
|
||||
if (mConfig.netSecConf) {
|
||||
ApkInfo meta = ApkInfo.load(new ExtFile(appDir));
|
||||
ApkInfo meta = ApkInfo.load(new ExtFile(mApkDir));
|
||||
if (meta.getSdkInfo() != null && meta.getSdkInfo().get("targetSdkVersion") != null) {
|
||||
if (Integer.parseInt(meta.getSdkInfo().get("targetSdkVersion")) < ResConfigFlags.SDK_NOUGAT) {
|
||||
LOGGER.warning("Target SDK version is lower than 24! Network Security Configuration might be ignored!");
|
||||
}
|
||||
}
|
||||
File netSecConfOrig = new File(appDir, "res/xml/network_security_config.xml");
|
||||
File netSecConfOrig = new File(mApkDir, "res/xml/network_security_config.xml");
|
||||
if (netSecConfOrig.exists()) {
|
||||
LOGGER.info("Replacing existing network_security_config.xml!");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
netSecConfOrig.delete();
|
||||
}
|
||||
ResXmlPatcher.modNetworkSecurityConfig(netSecConfOrig);
|
||||
ResXmlPatcher.setNetworkSecurityConfig(new File(appDir, "AndroidManifest.xml"));
|
||||
ResXmlPatcher.setNetworkSecurityConfig(new File(mApkDir, "AndroidManifest.xml"));
|
||||
LOGGER.info("Added permissive network security config in manifest");
|
||||
}
|
||||
|
||||
@ -297,14 +287,13 @@ public class ApkBuilder {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
resourceFile.delete();
|
||||
|
||||
File ninePatch = new File(appDir, "9patch");
|
||||
File ninePatch = new File(mApkDir, "9patch");
|
||||
if (!ninePatch.exists()) {
|
||||
ninePatch = null;
|
||||
}
|
||||
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
|
||||
invoker.invokeAapt(apkFile, new File(appDir,
|
||||
"AndroidManifest.xml"), new File(appDir, "res"),
|
||||
ninePatch, null, parseUsesFramework(usesFramework));
|
||||
invoker.invokeAapt(apkFile, new File(mApkDir, "AndroidManifest.xml"),
|
||||
new File(mApkDir, "res"), ninePatch, null, getIncludeFiles());
|
||||
|
||||
ExtFile tmpExtFile = new ExtFile(apkFile);
|
||||
Directory tmpDir = tmpExtFile.getDirectory();
|
||||
@ -332,31 +321,29 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean buildManifestRaw(ExtFile appDir)
|
||||
throws AndrolibException {
|
||||
private boolean buildManifestRaw() throws AndrolibException {
|
||||
try {
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
File apkDir = new File(mApkDir, APK_DIRNAME);
|
||||
LOGGER.info("Copying raw AndroidManifest.xml...");
|
||||
appDir.getDirectory().copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||
mApkDir.getDirectory().copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||
return true;
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean buildManifest(ExtFile appDir, UsesFramework usesFramework)
|
||||
throws BrutException {
|
||||
private boolean buildManifest() throws BrutException {
|
||||
try {
|
||||
if (!new File(appDir, "AndroidManifest.xml").exists()) {
|
||||
if (!new File(mApkDir, "AndroidManifest.xml").exists()) {
|
||||
return false;
|
||||
}
|
||||
if (! mConfig.forceBuildAll) {
|
||||
if (!mConfig.forceBuildAll) {
|
||||
LOGGER.info("Checking whether resources has changed...");
|
||||
}
|
||||
|
||||
File apkDir = new File(appDir, APK_DIRNAME);
|
||||
File apkDir = new File(mApkDir, APK_DIRNAME);
|
||||
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APK_MANIFEST_FILENAMES, appDir),
|
||||
if (mConfig.forceBuildAll || isModified(newFiles(APK_MANIFEST_FILENAMES, mApkDir),
|
||||
newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
|
||||
LOGGER.info("Building AndroidManifest.xml...");
|
||||
|
||||
@ -364,15 +351,14 @@ public class ApkBuilder {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
apkFile.delete();
|
||||
|
||||
File ninePatch = new File(appDir, "9patch");
|
||||
File ninePatch = new File(mApkDir, "9patch");
|
||||
if (!ninePatch.exists()) {
|
||||
ninePatch = null;
|
||||
}
|
||||
|
||||
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
|
||||
invoker.invokeAapt(apkFile, new File(appDir,
|
||||
"AndroidManifest.xml"), null, ninePatch, null,
|
||||
parseUsesFramework(usesFramework));
|
||||
invoker.invokeAapt(apkFile, new File(mApkDir, "AndroidManifest.xml"),
|
||||
null, ninePatch, null, getIncludeFiles());
|
||||
|
||||
Directory tmpDir = new ExtFile(apkFile).getDirectory();
|
||||
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
|
||||
@ -385,25 +371,25 @@ public class ApkBuilder {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (AndrolibException ex) {
|
||||
LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file.");
|
||||
return buildManifestRaw(appDir);
|
||||
return buildManifestRaw();
|
||||
}
|
||||
}
|
||||
|
||||
private void buildLibs(File appDir) throws AndrolibException {
|
||||
buildLibrary(appDir, "lib");
|
||||
buildLibrary(appDir, "libs");
|
||||
buildLibrary(appDir, "kotlin");
|
||||
buildLibrary(appDir, "META-INF/services");
|
||||
private void buildLibs() throws AndrolibException {
|
||||
buildLibrary("lib");
|
||||
buildLibrary("libs");
|
||||
buildLibrary("kotlin");
|
||||
buildLibrary("META-INF/services");
|
||||
}
|
||||
|
||||
private void buildLibrary(File appDir, String folder) throws AndrolibException {
|
||||
File working = new File(appDir, folder);
|
||||
private void buildLibrary(String folder) throws AndrolibException {
|
||||
File working = new File(mApkDir, folder);
|
||||
|
||||
if (! working.exists()) {
|
||||
if (!working.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File stored = new File(appDir, APK_DIRNAME + "/" + folder);
|
||||
File stored = new File(mApkDir, APK_DIRNAME + "/" + folder);
|
||||
if (mConfig.forceBuildAll || isModified(working, stored)) {
|
||||
LOGGER.info("Copying libs... (/" + folder + ")");
|
||||
try {
|
||||
@ -415,25 +401,24 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildCopyOriginalFiles(File appDir)
|
||||
throws AndrolibException {
|
||||
private void buildCopyOriginalFiles() throws AndrolibException {
|
||||
if (mConfig.copyOriginalFiles) {
|
||||
File originalDir = new File(appDir, "original");
|
||||
File originalDir = new File(mApkDir, "original");
|
||||
if (originalDir.exists()) {
|
||||
try {
|
||||
LOGGER.info("Copy original files...");
|
||||
Directory in = (new ExtFile(originalDir)).getDirectory();
|
||||
if (in.containsFile("AndroidManifest.xml")) {
|
||||
LOGGER.info("Copy AndroidManifest.xml...");
|
||||
in.copyToDir(new File(appDir, APK_DIRNAME), "AndroidManifest.xml");
|
||||
in.copyToDir(new File(mApkDir, APK_DIRNAME), "AndroidManifest.xml");
|
||||
}
|
||||
if (in.containsFile("stamp-cert-sha256")) {
|
||||
LOGGER.info("Copy stamp-cert-sha256...");
|
||||
in.copyToDir(new File(appDir, APK_DIRNAME), "stamp-cert-sha256");
|
||||
in.copyToDir(new File(mApkDir, APK_DIRNAME), "stamp-cert-sha256");
|
||||
}
|
||||
if (in.containsDir("META-INF")) {
|
||||
LOGGER.info("Copy META-INF...");
|
||||
in.copyToDir(new File(appDir, APK_DIRNAME), "META-INF");
|
||||
in.copyToDir(new File(mApkDir, APK_DIRNAME), "META-INF");
|
||||
}
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
@ -442,12 +427,11 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildUnknownFiles(File appDir, File outFile, ApkInfo meta)
|
||||
throws AndrolibException {
|
||||
if (meta.unknownFiles != null) {
|
||||
private void buildUnknownFiles(File outFile) throws AndrolibException {
|
||||
if (mApkInfo.unknownFiles != null) {
|
||||
LOGGER.info("Copying unknown files/dir...");
|
||||
|
||||
Map<String, String> files = meta.unknownFiles;
|
||||
Map<String, String> files = mApkInfo.unknownFiles;
|
||||
File tempFile = new File(outFile.getParent(), outFile.getName() + ".apktool_temp");
|
||||
boolean renamed = outFile.renameTo(tempFile);
|
||||
if (!renamed) {
|
||||
@ -455,11 +439,11 @@ public class ApkBuilder {
|
||||
}
|
||||
|
||||
try (
|
||||
ZipFile inputFile = new ZipFile(tempFile);
|
||||
ZipOutputStream actualOutput = new ZipOutputStream(Files.newOutputStream(outFile.toPath()))
|
||||
ZipFile inputFile = new ZipFile(tempFile);
|
||||
ZipOutputStream actualOutput = new ZipOutputStream(Files.newOutputStream(outFile.toPath()))
|
||||
) {
|
||||
copyExistingFiles(inputFile, actualOutput);
|
||||
copyUnknownFiles(appDir, actualOutput, files);
|
||||
copyUnknownFiles(actualOutput, files);
|
||||
} catch (IOException | BrutException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
@ -481,7 +465,7 @@ public class ApkBuilder {
|
||||
outputFile.putNextEntry(entry);
|
||||
|
||||
// No need to create directory entries in the final apk
|
||||
if (! entry.isDirectory()) {
|
||||
if (!entry.isDirectory()) {
|
||||
BrutIO.copy(inputFile, outputFile, entry);
|
||||
}
|
||||
|
||||
@ -489,9 +473,9 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyUnknownFiles(File appDir, ZipOutputStream outputFile, Map<String, String> files)
|
||||
private void copyUnknownFiles(ZipOutputStream outputFile, Map<String, String> files)
|
||||
throws BrutException, IOException {
|
||||
File unknownFileDir = new File(appDir, UNK_DIRNAME);
|
||||
File unknownFileDir = new File(mApkDir, UNK_DIRNAME);
|
||||
|
||||
// loop through unknown files
|
||||
for (Map.Entry<String,String> unknownFileInfo : files.entrySet()) {
|
||||
@ -529,7 +513,7 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildApk(File appDir, File outApk) throws AndrolibException {
|
||||
private void buildApk(File outApk) throws AndrolibException {
|
||||
LOGGER.info("Building apk file...");
|
||||
if (outApk.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
@ -541,16 +525,14 @@ public class ApkBuilder {
|
||||
outDir.mkdirs();
|
||||
}
|
||||
}
|
||||
File assetDir = new File(appDir, "assets");
|
||||
File assetDir = new File(mApkDir, "assets");
|
||||
if (!assetDir.exists()) {
|
||||
assetDir = null;
|
||||
}
|
||||
zipPackage(outApk, new File(appDir, APK_DIRNAME), assetDir);
|
||||
zipPackage(outApk, new File(mApkDir, APK_DIRNAME), assetDir);
|
||||
}
|
||||
|
||||
private void zipPackage(File apkFile, File rawDir, File assetDir)
|
||||
throws AndrolibException {
|
||||
|
||||
private void zipPackage(File apkFile, File rawDir, File assetDir) throws AndrolibException {
|
||||
try {
|
||||
ZipUtils.zipFolders(rawDir, apkFile, assetDir, mApkInfo.doNotCompress);
|
||||
} catch (IOException | BrutException ex) {
|
||||
@ -558,8 +540,8 @@ public class ApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private File[] parseUsesFramework(UsesFramework usesFramework)
|
||||
throws AndrolibException {
|
||||
private File[] getIncludeFiles() throws AndrolibException {
|
||||
UsesFramework usesFramework = mApkInfo.usesFramework;
|
||||
if (usesFramework == null) {
|
||||
return null;
|
||||
}
|
||||
@ -580,7 +562,7 @@ public class ApkBuilder {
|
||||
}
|
||||
|
||||
private boolean isModified(File working, File stored) {
|
||||
return ! stored.exists() || BrutIO.recursiveModifiedTime(working) > BrutIO .recursiveModifiedTime(stored);
|
||||
return !stored.exists() || BrutIO.recursiveModifiedTime(working) > BrutIO .recursiveModifiedTime(stored);
|
||||
}
|
||||
|
||||
private boolean isFile(File working) {
|
||||
@ -604,17 +586,15 @@ public class ApkBuilder {
|
||||
return files;
|
||||
}
|
||||
|
||||
public boolean detectWhetherAppIsFramework(File appDir)
|
||||
throws AndrolibException {
|
||||
File publicXml = new File(appDir, "res/values/public.xml");
|
||||
if (! publicXml.exists()) {
|
||||
public boolean detectWhetherAppIsFramework() throws AndrolibException {
|
||||
File publicXml = new File(mApkDir, "res/values/public.xml");
|
||||
if (!publicXml.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<String> it;
|
||||
try {
|
||||
it = IOUtils.lineIterator(new FileReader(new File(appDir,
|
||||
"res/values/public.xml")));
|
||||
it = IOUtils.lineIterator(new FileReader(new File(mApkDir, "res/values/public.xml")));
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new AndrolibException(
|
||||
"Could not detect whether app is framework one", ex);
|
||||
|
@ -32,8 +32,7 @@ import brut.util.OS;
|
||||
import com.android.tools.smali.dexlib2.iface.DexFile;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
@ -44,6 +43,7 @@ public class ApkDecoder {
|
||||
private final Config mConfig;
|
||||
private final ExtFile mApkFile;
|
||||
protected final ResUnknownFiles mResUnknownFiles;
|
||||
private ApkInfo mApkInfo;
|
||||
private int mMinSdkVersion = 0;
|
||||
|
||||
private final static String SMALI_DIRNAME = "smali";
|
||||
@ -59,24 +59,24 @@ public class ApkDecoder {
|
||||
"jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|" +
|
||||
"m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv|webm|webp|mkv)$");
|
||||
|
||||
public ApkDecoder(File apkFile) {
|
||||
this(Config.getDefaultConfig(), new ExtFile(apkFile));
|
||||
}
|
||||
|
||||
public ApkDecoder(ExtFile apkFile) {
|
||||
this(Config.getDefaultConfig(), apkFile);
|
||||
}
|
||||
|
||||
public ApkDecoder(Config config, ExtFile apkFile) {
|
||||
mConfig = config;
|
||||
mResUnknownFiles = new ResUnknownFiles();
|
||||
mApkFile = apkFile;
|
||||
}
|
||||
|
||||
public ApkDecoder(File apkFile) {
|
||||
this(new ExtFile(apkFile));
|
||||
}
|
||||
|
||||
public ApkDecoder(Config config, File apkFile) {
|
||||
this(config, new ExtFile(apkFile));
|
||||
}
|
||||
|
||||
public ApkDecoder(Config config, ExtFile apkFile) {
|
||||
mConfig = config;
|
||||
mApkFile = apkFile;
|
||||
mResUnknownFiles = new ResUnknownFiles();
|
||||
}
|
||||
|
||||
public ApkInfo decode(File outDir) throws AndrolibException, IOException, DirectoryException {
|
||||
try {
|
||||
if (!mConfig.forceDelete && outDir.exists()) {
|
||||
@ -96,8 +96,11 @@ public class ApkDecoder {
|
||||
|
||||
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());
|
||||
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile);
|
||||
if (hasResources()) {
|
||||
mApkInfo = new ApkInfo(mApkFile);
|
||||
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile, mApkInfo);
|
||||
|
||||
if (mApkInfo.hasResources()) {
|
||||
switch (mConfig.decodeResources) {
|
||||
case Config.DECODE_RESOURCES_NONE:
|
||||
copyResourcesRaw(outDir);
|
||||
@ -108,7 +111,7 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasManifest()) {
|
||||
if (mApkInfo.hasManifest()) {
|
||||
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
|
||||
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
|
||||
resourcesDecoder.decodeManifest(outDir);
|
||||
@ -119,7 +122,7 @@ public class ApkDecoder {
|
||||
}
|
||||
resourcesDecoder.updateApkInfo(outDir);
|
||||
|
||||
if (hasSources()) {
|
||||
if (mApkInfo.hasSources()) {
|
||||
switch (mConfig.decodeSources) {
|
||||
case Config.DECODE_SOURCES_NONE:
|
||||
copySourcesRaw(outDir, "classes.dex");
|
||||
@ -131,12 +134,12 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMultipleSources()) {
|
||||
if (mApkInfo.hasMultipleSources()) {
|
||||
// foreach unknown dex file in root, lets disassemble it
|
||||
Set<String> files = mApkFile.getDirectory().getFiles(true);
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".dex")) {
|
||||
if (! file.equalsIgnoreCase("classes.dex")) {
|
||||
if (!file.equalsIgnoreCase("classes.dex")) {
|
||||
switch(mConfig.decodeSources) {
|
||||
case Config.DECODE_SOURCES_NONE:
|
||||
copySourcesRaw(outDir, file);
|
||||
@ -158,19 +161,17 @@ public class ApkDecoder {
|
||||
}
|
||||
|
||||
// In case we have no resources. We should store the minSdk we pulled from the source opcode api level
|
||||
ApkInfo apkInfo = resourcesDecoder.getApkInfo();
|
||||
if (!hasResources() && mMinSdkVersion > 0) {
|
||||
apkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
|
||||
if (!mApkInfo.hasResources() && mMinSdkVersion > 0) {
|
||||
mApkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
|
||||
}
|
||||
|
||||
copyRawFiles(outDir);
|
||||
copyUnknownFiles(apkInfo, outDir);
|
||||
List<String> mUncompressedFiles = new ArrayList<>();
|
||||
recordUncompressedFiles(apkInfo, resourcesDecoder.getResFileMapping(), mUncompressedFiles);
|
||||
copyUnknownFiles(outDir);
|
||||
recordUncompressedFiles(resourcesDecoder.getResFileMapping());
|
||||
copyOriginalFiles(outDir);
|
||||
writeApkInfo(apkInfo, outDir);
|
||||
writeApkInfo(outDir);
|
||||
|
||||
return apkInfo;
|
||||
return mApkInfo;
|
||||
} finally {
|
||||
try {
|
||||
mApkFile.close();
|
||||
@ -178,53 +179,11 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasManifest() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
private void writeApkInfo(File outDir) throws AndrolibException {
|
||||
mApkInfo.save(new File(outDir, "apktool.yml"));
|
||||
}
|
||||
|
||||
private boolean hasResources() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("resources.arsc");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSources() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("classes.dex");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMultipleSources() throws AndrolibException {
|
||||
try {
|
||||
Set<String> files = mApkFile.getDirectory().getFiles(false);
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".dex")) {
|
||||
if (! file.equalsIgnoreCase("classes.dex")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeApkInfo(ApkInfo apkInfo, File outDir) throws AndrolibException {
|
||||
apkInfo.save(new File(outDir, "apktool.yml"));
|
||||
}
|
||||
|
||||
private void copyManifestRaw(File outDir)
|
||||
throws AndrolibException {
|
||||
private void copyManifestRaw(File outDir) throws AndrolibException {
|
||||
try {
|
||||
LOGGER.info("Copying raw manifest...");
|
||||
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
|
||||
@ -233,8 +192,7 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyResourcesRaw(File outDir)
|
||||
throws AndrolibException {
|
||||
private void copyResourcesRaw(File outDir) throws AndrolibException {
|
||||
try {
|
||||
LOGGER.info("Copying raw resources...");
|
||||
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
||||
@ -243,8 +201,7 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void copySourcesRaw(File outDir, String filename)
|
||||
throws AndrolibException {
|
||||
private void copySourcesRaw(File outDir, String filename) throws AndrolibException {
|
||||
try {
|
||||
LOGGER.info("Copying raw " + filename + " file...");
|
||||
mApkFile.getDirectory().copyToDir(outDir, filename);
|
||||
@ -253,8 +210,7 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeSourcesSmali(File outDir, String filename)
|
||||
throws AndrolibException {
|
||||
private void decodeSourcesSmali(File outDir, String filename) throws AndrolibException {
|
||||
try {
|
||||
File smaliDir;
|
||||
if (filename.equalsIgnoreCase("classes.dex")) {
|
||||
@ -277,8 +233,7 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyRawFiles(File outDir)
|
||||
throws AndrolibException {
|
||||
private void copyRawFiles(File outDir) throws AndrolibException {
|
||||
LOGGER.info("Copying assets and libs...");
|
||||
try {
|
||||
Directory in = mApkFile.getDirectory();
|
||||
@ -311,8 +266,7 @@ public class ApkDecoder {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void copyUnknownFiles(ApkInfo apkInfo, File outDir)
|
||||
throws AndrolibException {
|
||||
private void copyUnknownFiles(File outDir) throws AndrolibException {
|
||||
LOGGER.info("Copying unknown files...");
|
||||
File unknownOut = new File(outDir, UNK_DIRNAME);
|
||||
try {
|
||||
@ -331,14 +285,13 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
// update apk info
|
||||
apkInfo.unknownFiles = mResUnknownFiles.getUnknownFiles();
|
||||
mApkInfo.unknownFiles = mResUnknownFiles.getUnknownFiles();
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyOriginalFiles(File outDir)
|
||||
throws AndrolibException {
|
||||
private void copyOriginalFiles(File outDir) throws AndrolibException {
|
||||
LOGGER.info("Copying original files...");
|
||||
File originalDir = new File(outDir, "original");
|
||||
if (!originalDir.exists()) {
|
||||
@ -370,11 +323,9 @@ public class ApkDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void recordUncompressedFiles(ApkInfo apkInfo,
|
||||
Map<String, String> resFileMapping,
|
||||
List<String> uncompressedFilesOrExts)
|
||||
throws AndrolibException {
|
||||
private void recordUncompressedFiles(Map<String, String> resFileMapping) throws AndrolibException {
|
||||
try {
|
||||
List<String> uncompressedFilesOrExts = new ArrayList<>();
|
||||
Directory unk = mApkFile.getDirectory();
|
||||
Set<String> files = unk.getFiles(true);
|
||||
|
||||
@ -398,9 +349,8 @@ public class ApkDecoder {
|
||||
}
|
||||
// update apk info
|
||||
if (!uncompressedFilesOrExts.isEmpty()) {
|
||||
apkInfo.doNotCompress = uncompressedFilesOrExts;
|
||||
mApkInfo.doNotCompress = uncompressedFilesOrExts;
|
||||
}
|
||||
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
@ -20,18 +20,17 @@ import brut.androlib.ApktoolProperties;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import brut.androlib.res.data.ResConfigFlags;
|
||||
import brut.directory.DirectoryException;
|
||||
import brut.directory.ExtFile;
|
||||
import brut.directory.FileDirectory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class ApkInfo implements YamlSerializable {
|
||||
public String version;
|
||||
private transient ExtFile mApkFile;
|
||||
|
||||
private String apkFileName;
|
||||
public String version;
|
||||
public String apkFileName;
|
||||
public boolean isFrameworkApk;
|
||||
public UsesFramework usesFramework;
|
||||
private Map<String, String> sdkInfo = new LinkedHashMap<>();
|
||||
@ -47,7 +46,78 @@ public class ApkInfo implements YamlSerializable {
|
||||
public boolean compressionType;
|
||||
|
||||
public ApkInfo() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public ApkInfo(ExtFile apkFile) {
|
||||
this.version = ApktoolProperties.getVersion();
|
||||
if (apkFile != null) {
|
||||
setApkFile(apkFile);
|
||||
}
|
||||
}
|
||||
|
||||
public ExtFile getApkFile() {
|
||||
return mApkFile;
|
||||
}
|
||||
|
||||
public void setApkFile(ExtFile apkFile) {
|
||||
mApkFile = apkFile;
|
||||
if (this.apkFileName == null) {
|
||||
this.apkFileName = apkFile.getName();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasManifest() throws AndrolibException {
|
||||
if (mApkFile == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasResources() throws AndrolibException {
|
||||
if (mApkFile == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("resources.arsc");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSources() throws AndrolibException {
|
||||
if (mApkFile == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("classes.dex");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasMultipleSources() throws AndrolibException {
|
||||
if (mApkFile == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Set<String> files = mApkFile.getDirectory().getFiles(false);
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".dex")) {
|
||||
if (!file.equalsIgnoreCase("classes.dex")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String checkTargetSdkVersionBounds() {
|
||||
@ -61,14 +131,6 @@ public class ApkInfo implements YamlSerializable {
|
||||
return Integer.toString(target);
|
||||
}
|
||||
|
||||
public String getApkFileName() {
|
||||
return apkFileName;
|
||||
}
|
||||
|
||||
public void setApkFileName(String apkFileName) {
|
||||
this.apkFileName = apkFileName;
|
||||
}
|
||||
|
||||
public Map<String, String> getSdkInfo() {
|
||||
return sdkInfo;
|
||||
}
|
||||
@ -134,9 +196,7 @@ public class ApkInfo implements YamlSerializable {
|
||||
}
|
||||
|
||||
public void save(File file) throws AndrolibException {
|
||||
try (
|
||||
YamlWriter writer = new YamlWriter(new FileOutputStream(file));
|
||||
) {
|
||||
try (YamlWriter writer = new YamlWriter(new FileOutputStream(file))) {
|
||||
write(writer);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new AndrolibException("File not found");
|
||||
@ -153,10 +213,10 @@ public class ApkInfo implements YamlSerializable {
|
||||
}
|
||||
|
||||
public static ApkInfo load(File appDir) throws AndrolibException {
|
||||
try(
|
||||
InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml");
|
||||
) {
|
||||
return ApkInfo.load(in);
|
||||
try (InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml")) {
|
||||
ApkInfo apkInfo = ApkInfo.load(in);
|
||||
apkInfo.setApkFile(new ExtFile(appDir));
|
||||
return apkInfo;
|
||||
} catch (DirectoryException | IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
@ -49,8 +49,7 @@ public class Framework {
|
||||
installFramework(frameFile, config.frameworkTag);
|
||||
}
|
||||
|
||||
public void installFramework(File frameFile, String tag)
|
||||
throws AndrolibException {
|
||||
public void installFramework(File frameFile, String tag) throws AndrolibException {
|
||||
InputStream in = null;
|
||||
ZipOutputStream out = null;
|
||||
try {
|
||||
@ -198,8 +197,7 @@ public class Framework {
|
||||
return dir;
|
||||
}
|
||||
|
||||
public File getFrameworkApk(int id, String frameTag)
|
||||
throws AndrolibException {
|
||||
public File getFrameworkApk(int id, String frameTag) throws AndrolibException {
|
||||
File dir = getFrameworkDirectory();
|
||||
File apk;
|
||||
|
||||
@ -216,8 +214,10 @@ public class Framework {
|
||||
}
|
||||
|
||||
if (id == 1) {
|
||||
try (InputStream in = getAndroidFrameworkResourcesAsStream();
|
||||
OutputStream out = Files.newOutputStream(apk.toPath())) {
|
||||
try (
|
||||
InputStream in = getAndroidFrameworkResourcesAsStream();
|
||||
OutputStream out = Files.newOutputStream(apk.toPath())
|
||||
) {
|
||||
IOUtils.copy(in, out);
|
||||
return apk;
|
||||
} catch (IOException ex) {
|
||||
|
@ -31,10 +31,7 @@ import brut.directory.ExtFile;
|
||||
import brut.directory.FileDirectory;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -43,93 +40,51 @@ public class ResourcesDecoder {
|
||||
|
||||
private final Config mConfig;
|
||||
private final ExtFile mApkFile;
|
||||
private final ResTable mResTable;
|
||||
private final ApkInfo mApkInfo;
|
||||
private final ResTable mResTable;
|
||||
private final Map<String, String> mResFileMapping = new HashMap<>();
|
||||
|
||||
private final static String[] IGNORED_PACKAGES = new String[] {
|
||||
"android", "com.htc", "com.lge", "com.lge.internal", "yi", "flyme", "air.com.adobe.appentry",
|
||||
"FFFFFFFFFFFFFFFFFFFFFF" };
|
||||
|
||||
public ResourcesDecoder(Config config, ExtFile apkFile) {
|
||||
public ResourcesDecoder(Config config, ExtFile apkFile, ApkInfo apkInfo) {
|
||||
mConfig = config;
|
||||
mApkFile = apkFile;
|
||||
mApkInfo = new ApkInfo();
|
||||
mApkInfo.setApkFileName(apkFile.getName());
|
||||
mApkInfo = apkInfo;
|
||||
mResTable = new ResTable(mConfig, mApkInfo);
|
||||
}
|
||||
|
||||
public boolean hasManifest() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasResources() throws AndrolibException {
|
||||
try {
|
||||
return mApkFile.getDirectory().containsFile("resources.arsc");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ResTable getResTable() throws AndrolibException {
|
||||
if (! (hasManifest() || hasResources())) {
|
||||
if (!mApkInfo.hasManifest() && !mApkInfo.hasResources()) {
|
||||
throw new AndrolibException(
|
||||
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
||||
}
|
||||
return mResTable;
|
||||
}
|
||||
|
||||
public ApkInfo getApkInfo() {
|
||||
return mApkInfo;
|
||||
}
|
||||
|
||||
public Map<String, String> getResFileMapping() {
|
||||
return mResFileMapping;
|
||||
}
|
||||
|
||||
public void loadMainPkg() throws AndrolibException {
|
||||
mResTable.loadMainPkg(mApkFile);
|
||||
}
|
||||
|
||||
public void decodeManifest(File outDir) throws AndrolibException {
|
||||
if (hasManifest()) {
|
||||
decodeManifest(getResTable(), mApkFile, outDir);
|
||||
if (hasResources()) {
|
||||
if (!mConfig.analysisMode) {
|
||||
// Remove versionName / versionCode (aapt API 16)
|
||||
//
|
||||
// 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(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
|
||||
|
||||
ResXmlPatcher.removeManifestVersions(new File(
|
||||
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
|
||||
|
||||
// update apk info
|
||||
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
|
||||
}
|
||||
}
|
||||
if (!mApkInfo.hasManifest()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateApkInfo(File outDir) throws AndrolibException {
|
||||
mResTable.initApkInfo(mApkInfo, outDir);
|
||||
}
|
||||
|
||||
private void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
|
||||
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(resTable);
|
||||
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(mResTable);
|
||||
XmlPullStreamDecoder fileDecoder = new XmlPullStreamDecoder(axmlParser, getResXmlSerializer());
|
||||
|
||||
Directory inApk, out;
|
||||
try {
|
||||
inApk = apkFile.getDirectory();
|
||||
inApk = mApkFile.getDirectory();
|
||||
out = new FileDirectory(outDir);
|
||||
|
||||
if (hasResources()) {
|
||||
if (mApkInfo.hasResources()) {
|
||||
LOGGER.info("Decoding AndroidManifest.xml with resources...");
|
||||
} else {
|
||||
LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
|
||||
@ -141,18 +96,38 @@ public class ResourcesDecoder {
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
||||
if (mApkInfo.hasResources()) {
|
||||
if (!mConfig.analysisMode) {
|
||||
// Remove versionName / versionCode (aapt API 16)
|
||||
//
|
||||
// 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(outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
|
||||
|
||||
ResXmlPatcher.removeManifestVersions(new File(
|
||||
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
|
||||
|
||||
// update apk info
|
||||
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustPackageManifest(ResTable resTable, String filePath)
|
||||
throws AndrolibException {
|
||||
public void updateApkInfo(File outDir) throws AndrolibException {
|
||||
mResTable.initApkInfo(mApkInfo, outDir);
|
||||
}
|
||||
|
||||
private void adjustPackageManifest(String filePath) throws AndrolibException {
|
||||
// compare resources.arsc package name to the one present in AndroidManifest
|
||||
ResPackage resPackage = resTable.getCurrentResPackage();
|
||||
ResPackage resPackage = mResTable.getCurrentResPackage();
|
||||
String pkgOriginal = resPackage.getName();
|
||||
String pkgRenamed = resTable.getPackageRenamed();
|
||||
String pkgRenamed = mResTable.getPackageRenamed();
|
||||
|
||||
resTable.setPackageId(resPackage.getId());
|
||||
resTable.setPackageOriginal(pkgOriginal);
|
||||
mResTable.setPackageId(resPackage.getId());
|
||||
mResTable.setPackageOriginal(pkgOriginal);
|
||||
|
||||
// 1) Check if pkgOriginal is null (empty resources.arsc)
|
||||
// 2) Check if pkgRenamed is null
|
||||
@ -167,35 +142,18 @@ public class ResourcesDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private ExtMXSerializer getResXmlSerializer() {
|
||||
ExtMXSerializer serial = new ExtMXSerializer();
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, " ");
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, System.getProperty("line.separator"));
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
||||
serial.setDisabledAttrEscape(true);
|
||||
return serial;
|
||||
}
|
||||
|
||||
public void loadMainPkg() throws AndrolibException {
|
||||
mResTable.loadMainPkg(mApkFile);
|
||||
}
|
||||
|
||||
public ResTable decodeResources(File outDir) throws AndrolibException {
|
||||
if (hasResources()) {
|
||||
loadMainPkg();
|
||||
decodeResources(getResTable(), mApkFile, outDir);
|
||||
public void decodeResources(File outDir) throws AndrolibException {
|
||||
if (!mApkInfo.hasResources()) {
|
||||
return;
|
||||
}
|
||||
return mResTable;
|
||||
}
|
||||
|
||||
private void decodeResources(ResTable resTable, ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
mResTable.loadMainPkg(mApkFile);
|
||||
|
||||
ResStreamDecoderContainer decoders = new ResStreamDecoderContainer();
|
||||
decoders.setDecoder("raw", new ResRawStreamDecoder());
|
||||
decoders.setDecoder("9patch", new Res9patchStreamDecoder());
|
||||
|
||||
AXmlResourceParser axmlParser = new AXmlResourceParser(resTable);
|
||||
AXmlResourceParser axmlParser = new AXmlResourceParser(mResTable);
|
||||
decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
|
||||
|
||||
ResFileDecoder fileDecoder = new ResFileDecoder(decoders);
|
||||
@ -203,14 +161,14 @@ public class ResourcesDecoder {
|
||||
|
||||
try {
|
||||
out = new FileDirectory(outDir);
|
||||
in = apkFile.getDirectory();
|
||||
in = mApkFile.getDirectory();
|
||||
out = out.createDir("res");
|
||||
} catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
||||
ExtMXSerializer xmlSerializer = getResXmlSerializer();
|
||||
for (ResPackage pkg : resTable.listMainPackages()) {
|
||||
for (ResPackage pkg : mResTable.listMainPackages()) {
|
||||
|
||||
LOGGER.info("Decoding file-resources...");
|
||||
for (ResResource res : pkg.listFiles()) {
|
||||
@ -230,6 +188,15 @@ public class ResourcesDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
private ExtMXSerializer getResXmlSerializer() {
|
||||
ExtMXSerializer serial = new ExtMXSerializer();
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, " ");
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, System.getProperty("line.separator"));
|
||||
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
||||
serial.setDisabledAttrEscape(true);
|
||||
return serial;
|
||||
}
|
||||
|
||||
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
|
||||
ExtXmlSerializer serial) throws AndrolibException {
|
||||
try {
|
||||
|
@ -57,6 +57,10 @@ public class ResTable {
|
||||
this(Config.getDefaultConfig(), new ApkInfo());
|
||||
}
|
||||
|
||||
public ResTable(ExtFile apkFile) {
|
||||
this(Config.getDefaultConfig(), new ApkInfo(apkFile));
|
||||
}
|
||||
|
||||
public ResTable(Config config, ApkInfo apkInfo) {
|
||||
mConfig = config;
|
||||
mApkInfo = apkInfo;
|
||||
@ -145,8 +149,7 @@ public class ResTable {
|
||||
mMainPkgLoaded = true;
|
||||
}
|
||||
|
||||
private ResPackage loadFrameworkPkg(int id)
|
||||
throws AndrolibException {
|
||||
private ResPackage loadFrameworkPkg(int id) throws AndrolibException {
|
||||
Framework framework = new Framework(mConfig);
|
||||
File frameworkApk = framework.getFrameworkApk(id, mConfig.frameworkTag);
|
||||
|
||||
@ -168,8 +171,7 @@ public class ResTable {
|
||||
return pkg;
|
||||
}
|
||||
|
||||
private ResPackage[] loadResPackagesFromApk(ExtFile apkFile, boolean keepBrokenResources)
|
||||
throws AndrolibException {
|
||||
private ResPackage[] loadResPackagesFromApk(ExtFile apkFile, boolean keepBrokenResources) throws AndrolibException {
|
||||
try {
|
||||
Directory dir = apkFile.getDirectory();
|
||||
try (BufferedInputStream bfi = new BufferedInputStream(dir.getFileInput("resources.arsc"))) {
|
||||
|
@ -40,8 +40,7 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
|
||||
throws IOException, AndrolibException {
|
||||
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException {
|
||||
String type = getTypeAsString();
|
||||
|
||||
serializer.startTag(null, "attr");
|
||||
@ -106,7 +105,7 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
||||
throw new AndrolibException("Could not decode attr value");
|
||||
}
|
||||
|
||||
protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
|
||||
protected void serializeBody(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException {
|
||||
}
|
||||
|
||||
protected String getTypeAsString() {
|
||||
|
@ -19,19 +19,14 @@ package brut.androlib.res.decoder;
|
||||
import android.util.TypedValue;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import brut.androlib.res.data.*;
|
||||
import brut.androlib.res.data.arsc.*;
|
||||
import brut.androlib.res.data.value.*;
|
||||
import brut.androlib.res.data.arsc.ARSCData;
|
||||
import brut.androlib.res.data.arsc.ARSCHeader;
|
||||
import brut.androlib.res.data.arsc.EntryData;
|
||||
import brut.androlib.res.data.arsc.FlagsOffset;
|
||||
import brut.util.Duo;
|
||||
import brut.util.ExtDataInput;
|
||||
import com.google.common.io.LittleEndianDataInputStream;
|
||||
import org.apache.commons.io.input.CountingInputStream;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -25,13 +25,11 @@ import brut.androlib.res.data.arsc.ARSCHeader;
|
||||
import brut.androlib.res.data.axml.NamespaceStack;
|
||||
import brut.androlib.res.xml.ResXmlEncoders;
|
||||
import brut.util.ExtDataInput;
|
||||
import org.apache.commons.io.input.CountingInputStream;
|
||||
import com.google.common.io.LittleEndianDataInputStream;
|
||||
import org.apache.commons.io.input.CountingInputStream;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -27,11 +27,7 @@ import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
|
||||
public class Res9patchStreamDecoder implements ResStreamDecoder {
|
||||
@Override
|
||||
|
@ -31,8 +31,7 @@ public class ResAttrDecoder {
|
||||
mResTable = resTable;
|
||||
}
|
||||
|
||||
public String decode(int type, int value, String rawValue, int attrResId)
|
||||
throws AndrolibException {
|
||||
public String decode(int type, int value, String rawValue, int attrResId) throws AndrolibException {
|
||||
ResScalarValue resValue = mResTable.getCurrentResPackage().getValueFactory().factory(type, value, rawValue);
|
||||
|
||||
String decoded = null;
|
||||
@ -47,9 +46,7 @@ public class ResAttrDecoder {
|
||||
return decoded != null ? decoded : resValue.encodeAsResXmlAttr();
|
||||
}
|
||||
|
||||
public String decodeFromResourceId(int attrResId)
|
||||
throws AndrolibException {
|
||||
|
||||
public String decodeFromResourceId(int attrResId) throws AndrolibException {
|
||||
if (attrResId != 0) {
|
||||
try {
|
||||
ResResSpec resResSpec = mResTable.getResSpec(attrResId);
|
||||
|
@ -139,8 +139,8 @@ public class ResFileDecoder {
|
||||
public void decode(Directory inDir, String inFileName, Directory outDir,
|
||||
String outFileName, String decoder) throws AndrolibException {
|
||||
try (
|
||||
InputStream in = inDir.getFileInput(inFileName);
|
||||
OutputStream out = outDir.getFileOutput(outFileName)
|
||||
InputStream in = inDir.getFileInput(inFileName);
|
||||
OutputStream out = outDir.getFileOutput(outFileName)
|
||||
) {
|
||||
mDecoders.decode(in, out, decoder);
|
||||
} catch (DirectoryException | IOException ex) {
|
||||
@ -160,8 +160,8 @@ public class ResFileDecoder {
|
||||
public void decodeManifest(Directory inDir, String inFileName,
|
||||
Directory outDir, String outFileName) throws AndrolibException {
|
||||
try (
|
||||
InputStream in = inDir.getFileInput(inFileName);
|
||||
OutputStream out = outDir.getFileOutput(outFileName)
|
||||
InputStream in = inDir.getFileInput(inFileName);
|
||||
OutputStream out = outDir.getFileOutput(outFileName)
|
||||
) {
|
||||
((XmlPullStreamDecoder) mDecoders.getDecoder("xml")).decodeManifest(in, out);
|
||||
} catch (DirectoryException | IOException ex) {
|
||||
|
@ -19,9 +19,7 @@ package brut.androlib.res.decoder;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
|
||||
public class ResRawStreamDecoder implements ResStreamDecoder {
|
||||
@Override
|
||||
|
@ -17,8 +17,7 @@
|
||||
package brut.androlib.res.decoder;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
|
||||
public interface ResStreamDecoder {
|
||||
void decode(InputStream in, OutputStream out)
|
||||
|
@ -17,10 +17,8 @@
|
||||
package brut.androlib.res.decoder;
|
||||
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ResStreamDecoderContainer {
|
||||
private final Map<String, ResStreamDecoder> mDecoders = new HashMap<>();
|
||||
|
@ -28,9 +28,7 @@ import org.xmlpull.v1.wrapper.XmlPullWrapperFactory;
|
||||
import org.xmlpull.v1.wrapper.XmlSerializerWrapper;
|
||||
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
|
||||
public class XmlPullStreamDecoder implements ResStreamDecoder {
|
||||
public XmlPullStreamDecoder(XmlPullParser parser,
|
||||
|
@ -18,9 +18,7 @@ package brut.androlib.res.util;
|
||||
|
||||
import org.xmlpull.renamed.MXSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.io.*;
|
||||
|
||||
public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
||||
@Override
|
||||
|
@ -29,9 +29,7 @@ import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.xpath.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class ResXmlPatcher {
|
||||
@ -135,7 +133,7 @@ public final class ResXmlPatcher {
|
||||
* @throws ParserConfigurationException XML nodes could be written
|
||||
*/
|
||||
public static void modNetworkSecurityConfig(File file)
|
||||
throws ParserConfigurationException, TransformerException, IOException, SAXException {
|
||||
throws ParserConfigurationException, TransformerException, IOException, SAXException {
|
||||
|
||||
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
|
||||
|
@ -25,9 +25,7 @@ import com.android.tools.smali.dexlib2.Opcodes;
|
||||
import com.android.tools.smali.dexlib2.writer.builder.DexBuilder;
|
||||
import com.android.tools.smali.dexlib2.writer.io.FileDataStore;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -27,8 +27,7 @@ import com.android.tools.smali.dexlib2.analysis.InlineMethodResolver;
|
||||
import com.android.tools.smali.dexlib2.iface.DexFile;
|
||||
import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
|
||||
public class SmaliDecoder {
|
||||
|
||||
|
@ -18,10 +18,7 @@ package org.xmlpull.renamed;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,7 @@
|
||||
package brut.androlib.aapt2;
|
||||
|
||||
import brut.androlib.*;
|
||||
import brut.androlib.apk.ApkInfo;
|
||||
import brut.androlib.exceptions.AndrolibException;
|
||||
import brut.androlib.res.ResourcesDecoder;
|
||||
import brut.androlib.res.data.ResTable;
|
||||
@ -27,8 +28,6 @@ import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class NonStandardPkgIdTest extends BaseTest {
|
||||
@ -50,16 +49,18 @@ public class NonStandardPkgIdTest extends BaseTest {
|
||||
config.verbose = true;
|
||||
|
||||
LOGGER.info("Building pkgid8.apk...");
|
||||
File testApk = new File(sTmpDir, "pkgid8.apk");
|
||||
ExtFile testApk = new ExtFile(sTmpDir, "pkgid8.apk");
|
||||
new ApkBuilder(config, sTestOrigDir).build(testApk);
|
||||
|
||||
LOGGER.info("Decoding pkgid8.apk...");
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
|
||||
Config.getDefaultConfig(), new ExtFile(testApk));
|
||||
ApkInfo testInfo = new ApkInfo(testApk);
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), testApk, testInfo);
|
||||
|
||||
sTestNewDir.mkdirs();
|
||||
mResTable = resourcesDecoder.decodeResources(sTestNewDir);
|
||||
resourcesDecoder.decodeResources(sTestNewDir);
|
||||
resourcesDecoder.decodeManifest(sTestNewDir);
|
||||
|
||||
mResTable = resourcesDecoder.getResTable();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -24,7 +24,7 @@ import static org.junit.Assert.*;
|
||||
public class ApkInfoReaderTest {
|
||||
|
||||
private void checkStandard(ApkInfo apkInfo) {
|
||||
assertEquals("standard.apk", apkInfo.getApkFileName());
|
||||
assertEquals("standard.apk", apkInfo.apkFileName);
|
||||
assertFalse(apkInfo.resourcesAreCompressed);
|
||||
assertEquals(1, apkInfo.doNotCompress.size());
|
||||
assertEquals("resources.arsc", apkInfo.doNotCompress.iterator().next());
|
||||
@ -85,7 +85,7 @@ public class ApkInfoReaderTest {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/unknown_files.yml"));
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertEquals("testapp.apk", apkInfo.apkFileName);
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
@ -118,7 +118,7 @@ public class ApkInfoReaderTest {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/list_with_indent.yml"));
|
||||
assertEquals("2.8.0", apkInfo.version);
|
||||
assertEquals("basic.apk", apkInfo.getApkFileName());
|
||||
assertEquals("basic.apk", apkInfo.apkFileName);
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
|
@ -39,9 +39,7 @@ public class ApkInfoSerializationTest {
|
||||
|
||||
File savedApkInfo = folder.newFile( "saved.yml" );
|
||||
control.save(savedApkInfo);
|
||||
try (
|
||||
FileInputStream fis = new FileInputStream(savedApkInfo);
|
||||
) {
|
||||
try (FileInputStream fis = new FileInputStream(savedApkInfo)) {
|
||||
ApkInfo saved = ApkInfo.load(fis);
|
||||
check(saved);
|
||||
}
|
||||
@ -49,7 +47,7 @@ public class ApkInfoSerializationTest {
|
||||
|
||||
private void check(ApkInfo apkInfo) {
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertEquals("testapp.apk", apkInfo.apkFileName);
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertNotNull(apkInfo.usesFramework);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
|
@ -29,7 +29,7 @@ public class ConsistentPropertyTest {
|
||||
this.getClass().getResourceAsStream("/apk/basic.yml"));
|
||||
|
||||
assertEquals("2.8.0", apkInfo.version);
|
||||
assertEquals("basic.apk", apkInfo.getApkFileName());
|
||||
assertEquals("basic.apk", apkInfo.apkFileName);
|
||||
assertFalse(apkInfo.isFrameworkApk);
|
||||
assertEquals(1, apkInfo.usesFramework.ids.size());
|
||||
assertEquals("tag", apkInfo.usesFramework.tag);
|
||||
|
@ -28,7 +28,7 @@ public class DoNotCompressHieroglyphTest {
|
||||
ApkInfo apkInfo = ApkInfo.load(
|
||||
this.getClass().getResourceAsStream("/apk/donotcompress_with_hieroglyph.yml"));
|
||||
assertEquals("2.0.0", apkInfo.version);
|
||||
assertEquals("testapp.apk", apkInfo.getApkFileName());
|
||||
assertEquals("testapp.apk", apkInfo.apkFileName);
|
||||
assertEquals(2, apkInfo.doNotCompress.size());
|
||||
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1", apkInfo.doNotCompress.get(0));
|
||||
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1.manifest", apkInfo.doNotCompress.get(1));
|
||||
|
@ -20,6 +20,7 @@ import brut.androlib.ApkDecoder;
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.Config;
|
||||
import brut.androlib.TestUtils;
|
||||
import brut.androlib.apk.ApkInfo;
|
||||
import brut.androlib.res.ResourcesDecoder;
|
||||
import brut.androlib.res.data.ResTable;
|
||||
import brut.androlib.res.data.value.ResArrayValue;
|
||||
@ -51,11 +52,10 @@ public class DecodeArrayTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
public void decodeStringArray() throws BrutException {
|
||||
String apk = "issue1994.apk";
|
||||
//ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + apk));
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
|
||||
Config.getDefaultConfig(),
|
||||
new ExtFile(sTmpDir + File.separator + apk));
|
||||
ExtFile apkFile = new ExtFile(sTmpDir, "issue1994.apk");
|
||||
ApkInfo apkInfo = new ApkInfo(apkFile);
|
||||
//ApkDecoder apkDecoder = new ApkDecoder(apkFile);
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), apkFile, apkInfo);
|
||||
|
||||
resourcesDecoder.loadMainPkg();
|
||||
ResTable resTable = resourcesDecoder.getResTable();
|
||||
@ -66,10 +66,9 @@ public class DecodeArrayTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
public void decodeArray() throws BrutException {
|
||||
String apk = "issue1994.apk";
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
|
||||
Config.getDefaultConfig(),
|
||||
new ExtFile(sTmpDir + File.separator + apk));
|
||||
ExtFile apkFile = new ExtFile(sTmpDir, "issue1994.apk");
|
||||
ApkInfo apkInfo = new ApkInfo(apkFile);
|
||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), apkFile, apkInfo);
|
||||
|
||||
resourcesDecoder.loadMainPkg();
|
||||
ResTable resTable = resourcesDecoder.getResTable();
|
||||
|
@ -262,12 +262,9 @@ public abstract class AbstractDirectory implements Directory {
|
||||
|
||||
protected abstract void loadFiles();
|
||||
protected abstract void loadDirs();
|
||||
protected abstract InputStream getFileInputLocal(String name)
|
||||
throws DirectoryException;
|
||||
protected abstract OutputStream getFileOutputLocal(String name)
|
||||
throws DirectoryException;
|
||||
protected abstract AbstractDirectory createDirLocal(String name)
|
||||
throws DirectoryException;
|
||||
protected abstract InputStream getFileInputLocal(String name) throws DirectoryException;
|
||||
protected abstract OutputStream getFileOutputLocal(String name) throws DirectoryException;
|
||||
protected abstract AbstractDirectory createDirLocal(String name) throws DirectoryException;
|
||||
protected abstract void removeFileLocal(String name);
|
||||
|
||||
|
||||
|
@ -48,28 +48,21 @@ public interface Directory {
|
||||
|
||||
void copyToDir(Directory out) throws DirectoryException;
|
||||
|
||||
void copyToDir(Directory out, String[] fileNames)
|
||||
throws DirectoryException;
|
||||
void copyToDir(Directory out, String[] fileNames) throws DirectoryException;
|
||||
|
||||
void copyToDir(Directory out, String fileName)
|
||||
throws DirectoryException;
|
||||
void copyToDir(Directory out, String fileName) throws DirectoryException;
|
||||
|
||||
void copyToDir(File out) throws DirectoryException;
|
||||
|
||||
void copyToDir(File out, String[] fileNames)
|
||||
throws DirectoryException;
|
||||
void copyToDir(File out, String[] fileNames) throws DirectoryException;
|
||||
|
||||
void copyToDir(File out, String fileName)
|
||||
throws DirectoryException;
|
||||
void copyToDir(File out, String fileName) throws DirectoryException;
|
||||
|
||||
long getSize(String fileName)
|
||||
throws DirectoryException;
|
||||
long getSize(String fileName) throws DirectoryException;
|
||||
|
||||
long getCompressedSize(String fileName)
|
||||
throws DirectoryException;
|
||||
long getCompressedSize(String fileName) throws DirectoryException;
|
||||
|
||||
int getCompressionLevel(String fileName)
|
||||
throws DirectoryException;
|
||||
int getCompressionLevel(String fileName) throws DirectoryException;
|
||||
|
||||
void close() throws IOException;
|
||||
|
||||
|
@ -105,17 +105,13 @@ public class BrutIO {
|
||||
}
|
||||
|
||||
public static void copy(File inputFile, ZipOutputStream outputFile) throws IOException {
|
||||
try (
|
||||
FileInputStream fis = new FileInputStream(inputFile)
|
||||
) {
|
||||
try (FileInputStream fis = new FileInputStream(inputFile)) {
|
||||
IOUtils.copy(fis, outputFile);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copy(ZipFile inputFile, ZipOutputStream outputFile, ZipEntry entry) throws IOException {
|
||||
try (
|
||||
InputStream is = inputFile.getInputStream(entry)
|
||||
) {
|
||||
try (InputStream is = inputFile.getInputStream(entry)) {
|
||||
IOUtils.copy(is, outputFile);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user