Merge pull request #95 from iBotPeaches/cleanup_options

Options Cleanup
This commit is contained in:
Connor Tumbleson 2014-11-02 07:48:36 -06:00
commit e8dae927d4
9 changed files with 149 additions and 140 deletions

View File

@ -16,10 +16,7 @@
package brut.apktool; package brut.apktool;
import brut.androlib.Androlib; import brut.androlib.*;
import brut.androlib.AndrolibException;
import brut.androlib.ApkDecoder;
import brut.androlib.ApktoolProperties;
import brut.androlib.err.CantFindFrameworkResException; import brut.androlib.err.CantFindFrameworkResException;
import brut.androlib.err.InFileNotFoundException; import brut.androlib.err.InFileNotFoundException;
import brut.androlib.err.OutDirExistsException; import brut.androlib.err.OutDirExistsException;
@ -27,7 +24,6 @@ import brut.common.BrutException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.logging.*; import java.util.logging.*;
import brut.directory.DirectoryException; import brut.directory.DirectoryException;
@ -45,8 +41,7 @@ import org.apache.commons.cli.PosixParser;
* @author Connor Tumbleson <connor.tumbleson@gmail.com> * @author Connor Tumbleson <connor.tumbleson@gmail.com>
*/ */
public class Main { public class Main {
public static void main(String[] args) throws IOException, public static void main(String[] args) throws IOException, InterruptedException, BrutException {
InterruptedException, BrutException {
// set verbosity default // set verbosity default
Verbosity verbosity = Verbosity.NORMAL; Verbosity verbosity = Verbosity.NORMAL;
@ -198,37 +193,27 @@ public class Main {
private static void cmdBuild(CommandLine cli) throws BrutException { private static void cmdBuild(CommandLine cli) throws BrutException {
String[] args = cli.getArgs(); String[] args = cli.getArgs();
String appDirName = args.length < 2 ? "." : args[1]; String appDirName = args.length < 2 ? "." : args[1];
String mAaptPath = "";
File outFile = null; File outFile = null;
Androlib instance = new Androlib(); ApkOptions apkOptions = new ApkOptions();
// hold all the fields
HashMap<String, Boolean> flags = new HashMap<String, Boolean>();
flags.put("forceBuildAll", false);
flags.put("debug", false);
flags.put("verbose", false);
flags.put("framework", false);
flags.put("update", false);
flags.put("copyOriginal", false);
// check for build options // check for build options
if (cli.hasOption("f") || cli.hasOption("force-all")) { if (cli.hasOption("f") || cli.hasOption("force-all")) {
flags.put("forceBuildAll", true); apkOptions.forceBuildAll = true;
} }
if (cli.hasOption("d") || cli.hasOption("debug")) { if (cli.hasOption("d") || cli.hasOption("debug")) {
flags.put("debug", true); apkOptions.debugMode = true;
} }
if (cli.hasOption("v") || cli.hasOption("verbose")) { if (cli.hasOption("v") || cli.hasOption("verbose")) {
flags.put("verbose", true); apkOptions.verbose = true;
} }
if (cli.hasOption("a") || cli.hasOption("aapt")) { if (cli.hasOption("a") || cli.hasOption("aapt")) {
mAaptPath = cli.getOptionValue("a"); apkOptions.aaptPath = cli.getOptionValue("a");
} }
if (cli.hasOption("c") || cli.hasOption("copy-original")) { if (cli.hasOption("c") || cli.hasOption("copy-original")) {
flags.put("copyOriginal", true); apkOptions.copyOriginalFiles = true;
} }
if (cli.hasOption("p") || cli.hasOption("frame-path")) { if (cli.hasOption("p") || cli.hasOption("frame-path")) {
instance.setFrameworkFolder(cli.getOptionValue("p")); apkOptions.frameworkFolderLocation = cli.getOptionValue("p");
} }
if (cli.hasOption("o") || cli.hasOption("output")) { if (cli.hasOption("o") || cli.hasOption("output")) {
outFile = new File(cli.getOptionValue("o")); outFile = new File(cli.getOptionValue("o"));
@ -237,23 +222,22 @@ public class Main {
} }
// try and build apk // try and build apk
instance.build(new File(appDirName), outFile, flags,mAaptPath); new Androlib(apkOptions).build(new File(appDirName), outFile);
} }
private static void cmdInstallFramework(CommandLine cli) private static void cmdInstallFramework(CommandLine cli)
throws AndrolibException { throws AndrolibException {
int paraCount = cli.getArgList().size(); int paraCount = cli.getArgList().size();
String apkName = (String) cli.getArgList().get(paraCount - 1); String apkName = (String) cli.getArgList().get(paraCount - 1);
String tag = null;
String frame_path = null;
ApkOptions apkOptions = new ApkOptions();
if (cli.hasOption("p") || cli.hasOption("frame-path")) { if (cli.hasOption("p") || cli.hasOption("frame-path")) {
frame_path = cli.getOptionValue("p"); apkOptions.frameworkFolderLocation = cli.getOptionValue("p");
} }
if (cli.hasOption("t") || cli.hasOption("tag")) { if (cli.hasOption("t") || cli.hasOption("tag")) {
tag = cli.getOptionValue("t"); apkOptions.frameworkTag = cli.getOptionValue("t");
} }
new Androlib().installFramework(new File(apkName), tag, frame_path); new Androlib(apkOptions).installFramework(new File(apkName));
} }
private static void cmdPublicizeResources(CommandLine cli) private static void cmdPublicizeResources(CommandLine cli)

View File

@ -44,6 +44,17 @@ import org.yaml.snakeyaml.Yaml;
public class Androlib { public class Androlib {
private final AndrolibResources mAndRes = new AndrolibResources(); private final AndrolibResources mAndRes = new AndrolibResources();
protected final ResUnknownFiles mResUnknownFiles = new ResUnknownFiles(); protected final ResUnknownFiles mResUnknownFiles = new ResUnknownFiles();
public ApkOptions apkOptions;
public Androlib(ApkOptions apkOptions) {
this.apkOptions = apkOptions;
mAndRes.apkOptions = apkOptions;
}
public Androlib() {
this.apkOptions = new ApkOptions();
mAndRes.apkOptions = this.apkOptions;
}
public ResTable getResTable(ExtFile apkFile) public ResTable getResTable(ExtFile apkFile)
throws AndrolibException { throws AndrolibException {
@ -235,21 +246,20 @@ public class Androlib {
} }
} }
public void build(File appDir, File outFile, HashMap<String, Boolean> flags, String aaptPath) throws BrutException { public void build(File appDir, File outFile) throws BrutException {
build(new ExtFile(appDir), outFile, flags, aaptPath); build(new ExtFile(appDir), outFile);
} }
public void build(ExtFile appDir, File outFile, HashMap<String, Boolean> flags, String aaptPath) public void build(ExtFile appDir, File outFile)
throws BrutException { throws BrutException {
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + appDir.getName()); LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + appDir.getName());
mAaptPath = aaptPath;
Map<String, Object> meta = readMetaFile(appDir); Map<String, Object> meta = readMetaFile(appDir);
Object t1 = meta.get("isFrameworkApk"); Object t1 = meta.get("isFrameworkApk");
flags.put("framework", t1 == null ? false : (Boolean) t1); apkOptions.isFramework = (t1 == null ? false : (Boolean) t1);
flags.put("compression", meta.get("compressionType") == null apkOptions.resourcesAreCompressed = meta.get("compressionType") == null
? false ? false
: Boolean.valueOf(meta.get("compressionType").toString())); : Boolean.valueOf(meta.get("compressionType").toString());
mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo")); mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo"));
mAndRes.setPackageId((Map<String, String>) meta.get("packageInfo")); mAndRes.setPackageId((Map<String, String>) meta.get("packageInfo"));
@ -262,28 +272,28 @@ public class Androlib {
} }
new File(appDir, APK_DIRNAME).mkdirs(); new File(appDir, APK_DIRNAME).mkdirs();
buildSources(appDir, flags); buildSources(appDir);
buildNonDefaultSources(appDir, flags); buildNonDefaultSources(appDir);
buildResources(appDir, flags, (Map<String, Object>) meta.get("usesFramework")); buildResources(appDir, (Map<String, Object>) meta.get("usesFramework"));
buildLib(appDir, flags); buildLib(appDir);
buildCopyOriginalFiles(appDir, flags); buildCopyOriginalFiles(appDir);
buildApk(appDir, outFile, flags); buildApk(appDir, outFile);
// we must go after the Apk is built, and copy the files in via Zip // 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) // this is because Aapt won't add files it doesn't know (ex unknown files)
buildUnknownFiles(appDir, outFile, meta); buildUnknownFiles(appDir, outFile, meta);
} }
public void buildSources(File appDir, HashMap<String, Boolean> flags) public void buildSources(File appDir)
throws AndrolibException { throws AndrolibException {
if (!buildSourcesRaw(appDir, "classes.dex", flags) if (!buildSourcesRaw(appDir, "classes.dex")
&& !buildSourcesSmali(appDir, "smali", "classes.dex", flags) && !buildSourcesSmali(appDir, "smali", "classes.dex")
&& !buildSourcesJava(appDir, flags)) { && !buildSourcesJava(appDir)) {
LOGGER.warning("Could not find sources"); LOGGER.warning("Could not find sources");
} }
} }
public void buildNonDefaultSources(ExtFile appDir, HashMap<String, Boolean> flags) public void buildNonDefaultSources(ExtFile appDir)
throws AndrolibException { throws AndrolibException {
try { try {
Map<String, Directory> dirs = appDir.getDirectory().getDirs(); Map<String, Directory> dirs = appDir.getDirectory().getDirs();
@ -292,9 +302,9 @@ public class Androlib {
if (name.startsWith("smali_")) { if (name.startsWith("smali_")) {
String filename = name.substring(name.indexOf("_") + 1) + ".dex"; String filename = name.substring(name.indexOf("_") + 1) + ".dex";
if (!buildSourcesRaw(appDir, filename, flags) if (!buildSourcesRaw(appDir, filename)
&& !buildSourcesSmali(appDir, name, filename, flags) && !buildSourcesSmali(appDir, name, filename)
&& !buildSourcesJava(appDir, flags)) { && !buildSourcesJava(appDir)) {
LOGGER.warning("Could not find sources"); LOGGER.warning("Could not find sources");
} }
} }
@ -304,14 +314,14 @@ public class Androlib {
} }
} }
public boolean buildSourcesRaw(File appDir, String filename, HashMap<String, Boolean> flags) public boolean buildSourcesRaw(File appDir, String filename)
throws AndrolibException { throws AndrolibException {
File working = new File(appDir, filename); File working = new File(appDir, filename);
if (!working.exists()) { if (!working.exists()) {
return false; return false;
} }
File stored = new File(appDir, APK_DIRNAME + "/" + filename); File stored = new File(appDir, APK_DIRNAME + "/" + filename);
if (flags.get("forceBuildAll") || isModified(working, stored)) { if (apkOptions.forceBuildAll || isModified(working, stored)) {
LOGGER.info("Copying " + appDir.toString() + " " + filename + " file..."); LOGGER.info("Copying " + appDir.toString() + " " + filename + " file...");
try { try {
BrutIO.copyAndClose(new FileInputStream(working), new FileOutputStream(stored)); BrutIO.copyAndClose(new FileInputStream(working), new FileOutputStream(stored));
@ -323,35 +333,35 @@ public class Androlib {
return true; return true;
} }
public boolean buildSourcesSmali(File appDir, String folder, String filename, HashMap<String, Boolean> flags) public boolean buildSourcesSmali(File appDir, String folder, String filename)
throws AndrolibException { throws AndrolibException {
ExtFile smaliDir = new ExtFile(appDir, folder); ExtFile smaliDir = new ExtFile(appDir, folder);
if (!smaliDir.exists()) { if (!smaliDir.exists()) {
return false; return false;
} }
File dex = new File(appDir, APK_DIRNAME + "/" + filename); File dex = new File(appDir, APK_DIRNAME + "/" + filename);
if (!flags.get("forceBuildAll")) { if (! apkOptions.forceBuildAll) {
LOGGER.info("Checking whether sources has changed..."); LOGGER.info("Checking whether sources has changed...");
} }
if (flags.get("forceBuildAll") || isModified(smaliDir, dex)) { if (apkOptions.forceBuildAll || isModified(smaliDir, dex)) {
LOGGER.info("Smaling " + folder + " folder into " + filename +"..."); LOGGER.info("Smaling " + folder + " folder into " + filename +"...");
dex.delete(); dex.delete();
SmaliBuilder.build(smaliDir, dex, flags); SmaliBuilder.build(smaliDir, dex, apkOptions.debugMode);
} }
return true; return true;
} }
public boolean buildSourcesJava(File appDir, HashMap<String, Boolean> flags) public boolean buildSourcesJava(File appDir)
throws AndrolibException { throws AndrolibException {
File javaDir = new File(appDir, "src"); File javaDir = new File(appDir, "src");
if (!javaDir.exists()) { if (!javaDir.exists()) {
return false; return false;
} }
File dex = new File(appDir, APK_DIRNAME + "/classes.dex"); File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
if (!flags.get("forceBuildAll")) { if (! apkOptions.forceBuildAll) {
LOGGER.info("Checking whether sources has changed..."); LOGGER.info("Checking whether sources has changed...");
} }
if (flags.get("forceBuildAll") || isModified(javaDir, dex)) { if (apkOptions.forceBuildAll || isModified(javaDir, dex)) {
LOGGER.info("Building java sources..."); LOGGER.info("Building java sources...");
dex.delete(); dex.delete();
new AndrolibJava().build(javaDir, dex); new AndrolibJava().build(javaDir, dex);
@ -359,26 +369,25 @@ public class Androlib {
return true; return true;
} }
public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework) public void buildResources(ExtFile appDir, Map<String, Object> usesFramework)
throws BrutException { throws BrutException {
if (!buildResourcesRaw(appDir, flags) && !buildResourcesFull(appDir, flags, usesFramework) if (!buildResourcesRaw(appDir) && !buildResourcesFull(appDir, usesFramework)
&& !buildManifest(appDir, flags, usesFramework)) { && !buildManifest(appDir, usesFramework)) {
LOGGER.warning("Could not find resources"); LOGGER.warning("Could not find resources");
} }
} }
public boolean buildResourcesRaw(ExtFile appDir, HashMap<String, Boolean> flags) public boolean buildResourcesRaw(ExtFile appDir)
throws AndrolibException { throws AndrolibException {
try { try {
if (!new File(appDir, "resources.arsc").exists()) { if (!new File(appDir, "resources.arsc").exists()) {
return false; return false;
} }
File apkDir = new File(appDir, APK_DIRNAME); File apkDir = new File(appDir, APK_DIRNAME);
if (!flags.get("forceBuildAll")) { if (! apkOptions.forceBuildAll) {
LOGGER.info("Checking whether resources has changed..."); LOGGER.info("Checking whether resources has changed...");
} }
if (flags.get("forceBuildAll") if (apkOptions.forceBuildAll || isModified(newFiles(APK_RESOURCES_FILENAMES, appDir),
|| isModified(newFiles(APK_RESOURCES_FILENAMES, appDir),
newFiles(APK_RESOURCES_FILENAMES, apkDir))) { newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
LOGGER.info("Copying raw resources..."); LOGGER.info("Copying raw resources...");
appDir.getDirectory() appDir.getDirectory()
@ -390,17 +399,17 @@ public class Androlib {
} }
} }
public boolean buildResourcesFull(File appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework) public boolean buildResourcesFull(File appDir, Map<String, Object> usesFramework)
throws AndrolibException { throws AndrolibException {
try { try {
if (!new File(appDir, "res").exists()) { if (!new File(appDir, "res").exists()) {
return false; return false;
} }
if (!flags.get("forceBuildAll")) { if (! apkOptions.forceBuildAll) {
LOGGER.info("Checking whether resources has changed..."); LOGGER.info("Checking whether resources has changed...");
} }
File apkDir = new File(appDir, APK_DIRNAME); File apkDir = new File(appDir, APK_DIRNAME);
if (flags.get("forceBuildAll") || isModified(newFiles(APP_RESOURCES_FILENAMES, appDir), if (apkOptions.forceBuildAll || isModified(newFiles(APP_RESOURCES_FILENAMES, appDir),
newFiles(APK_RESOURCES_FILENAMES, apkDir))) { newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
LOGGER.info("Building resources..."); LOGGER.info("Building resources...");
@ -413,8 +422,7 @@ public class Androlib {
} }
mAndRes.aaptPackage(apkFile, new File(appDir, mAndRes.aaptPackage(apkFile, new File(appDir,
"AndroidManifest.xml"), new File(appDir, "res"), "AndroidManifest.xml"), new File(appDir, "res"),
ninePatch, null, parseUsesFramework(usesFramework), ninePatch, null, parseUsesFramework(usesFramework));
flags, mAaptPath);
Directory tmpDir = new ExtFile(apkFile).getDirectory(); Directory tmpDir = new ExtFile(apkFile).getDirectory();
tmpDir.copyToDir(apkDir, tmpDir.copyToDir(apkDir,
@ -430,7 +438,7 @@ public class Androlib {
} }
} }
public boolean buildManifestRaw(ExtFile appDir, HashMap<String, Boolean> flags) public boolean buildManifestRaw(ExtFile appDir)
throws AndrolibException { throws AndrolibException {
try { try {
File apkDir = new File(appDir, APK_DIRNAME); File apkDir = new File(appDir, APK_DIRNAME);
@ -442,23 +450,23 @@ public class Androlib {
} }
} }
public boolean buildManifest(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework) public boolean buildManifest(ExtFile appDir, Map<String, Object> usesFramework)
throws BrutException { throws BrutException {
try { try {
if (!new File(appDir, "AndroidManifest.xml").exists()) { if (!new File(appDir, "AndroidManifest.xml").exists()) {
return false; return false;
} }
if (!flags.get("forceBuildAll")) { if (! apkOptions.forceBuildAll) {
LOGGER.info("Checking whether resources has changed..."); LOGGER.info("Checking whether resources has changed...");
} }
File apkDir = new File(appDir, APK_DIRNAME); File apkDir = new File(appDir, APK_DIRNAME);
if (flags.get("debug")) { if (apkOptions.debugMode) {
mAndRes.remove_application_debug(new File(apkDir,"AndroidManifest.xml").getAbsolutePath()); mAndRes.remove_application_debug(new File(apkDir,"AndroidManifest.xml").getAbsolutePath());
} }
if (flags.get("forceBuildAll") || isModified(newFiles(APK_MANIFEST_FILENAMES, appDir), if (apkOptions.forceBuildAll || isModified(newFiles(APK_MANIFEST_FILENAMES, appDir),
newFiles(APK_MANIFEST_FILENAMES, apkDir))) { newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
LOGGER.info("Building AndroidManifest.xml..."); LOGGER.info("Building AndroidManifest.xml...");
@ -472,7 +480,7 @@ public class Androlib {
mAndRes.aaptPackage(apkFile, new File(appDir, mAndRes.aaptPackage(apkFile, new File(appDir,
"AndroidManifest.xml"), null, ninePatch, null, "AndroidManifest.xml"), null, ninePatch, null,
parseUsesFramework(usesFramework), flags, mAaptPath); parseUsesFramework(usesFramework));
Directory tmpDir = new ExtFile(apkFile).getDirectory(); Directory tmpDir = new ExtFile(apkFile).getDirectory();
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES); tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
@ -483,18 +491,18 @@ public class Androlib {
throw new AndrolibException(ex); throw new AndrolibException(ex);
} catch (AndrolibException ex) { } catch (AndrolibException ex) {
LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file."); LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file.");
return buildManifestRaw(appDir, flags); return buildManifestRaw(appDir);
} }
} }
public void buildLib(File appDir, HashMap<String, Boolean> flags) public void buildLib(File appDir)
throws AndrolibException { throws AndrolibException {
File working = new File(appDir, "lib"); File working = new File(appDir, "lib");
if (!working.exists()) { if (!working.exists()) {
return; return;
} }
File stored = new File(appDir, APK_DIRNAME + "/lib"); File stored = new File(appDir, APK_DIRNAME + "/lib");
if (flags.get("forceBuildAll") || isModified(working, stored)) { if (apkOptions.forceBuildAll || isModified(working, stored)) {
LOGGER.info("Copying libs..."); LOGGER.info("Copying libs...");
try { try {
OS.rmdir(stored); OS.rmdir(stored);
@ -505,9 +513,9 @@ public class Androlib {
} }
} }
public void buildCopyOriginalFiles(File appDir, HashMap<String, Boolean> flags) public void buildCopyOriginalFiles(File appDir)
throws AndrolibException { throws AndrolibException {
if (flags.get("copyOriginal")) { if (apkOptions.copyOriginalFiles) {
File originalDir = new File(appDir, "original"); File originalDir = new File(appDir, "original");
if(originalDir.exists()) { if(originalDir.exists()) {
try { try {
@ -531,7 +539,7 @@ public class Androlib {
public void buildUnknownFiles(File appDir, File outFile, Map<String, Object> meta) public void buildUnknownFiles(File appDir, File outFile, Map<String, Object> meta)
throws AndrolibException { throws AndrolibException {
File file; File file;
mPath = Paths.get(appDir.getPath() + File.separatorChar + UNK_DIRNAME); Path globalPath = Paths.get(appDir.getPath() + File.separatorChar + UNK_DIRNAME);
if (meta.containsKey("unknownFiles")) { if (meta.containsKey("unknownFiles")) {
LOGGER.info("Copying unknown files/dir..."); LOGGER.info("Copying unknown files/dir...");
@ -550,10 +558,13 @@ public class Androlib {
// loop through files inside // loop through files inside
for (Map.Entry<String,String> entry : files.entrySet()) { for (Map.Entry<String,String> entry : files.entrySet()) {
file = new File(mPath.toFile(), entry.getKey()); file = new File(globalPath.toFile(), entry.getKey());
if (file.isFile() && file.exists()) { if (file.isFile() && file.exists()) {
insertFolder(path, zip_properties, file.getParentFile(), entry.getValue(), mPath.toAbsolutePath()); insertFolder(path, zip_properties, file.getParentFile(), entry.getValue(),
insertFile(path, zip_properties, file, entry.getValue(), mPath.toAbsolutePath()); globalPath.toAbsolutePath());
insertFile(path, zip_properties, file, entry.getValue(),
globalPath.toAbsolutePath());
} }
} }
} catch (IOException ex) { } catch (IOException ex) {
@ -599,8 +610,7 @@ public class Androlib {
} }
} }
public void buildApk(File appDir, File outApk, public void buildApk(File appDir, File outApk) throws AndrolibException {
HashMap<String, Boolean> flags) throws AndrolibException {
LOGGER.info("Building apk file..."); LOGGER.info("Building apk file...");
if (outApk.exists()) { if (outApk.exists()) {
outApk.delete(); outApk.delete();
@ -614,17 +624,16 @@ public class Androlib {
if (!assetDir.exists()) { if (!assetDir.exists()) {
assetDir = null; assetDir = null;
} }
mAndRes.aaptPackage(outApk, null, null, new File(appDir, APK_DIRNAME), assetDir, null, flags, mAaptPath); mAndRes.aaptPackage(outApk, null, null, new File(appDir, APK_DIRNAME), assetDir, null);
} }
public void publicizeResources(File arscFile) throws AndrolibException { public void publicizeResources(File arscFile) throws AndrolibException {
mAndRes.publicizeResources(arscFile); mAndRes.publicizeResources(arscFile);
} }
public void installFramework(File frameFile, String tag, String frame_path) public void installFramework(File frameFile)
throws AndrolibException { throws AndrolibException {
mAndRes.setFrameworkFolder(frame_path); mAndRes.installFramework(frameFile);
mAndRes.installFramework(frameFile, tag);
} }
public boolean isFrameworkApk(ResTable resTable) { public boolean isFrameworkApk(ResTable resTable) {
@ -681,13 +690,6 @@ public class Androlib {
return files; return files;
} }
public void setFrameworkFolder(String path) {
mAndRes.setFrameworkFolder(path);
}
private String mAaptPath = null;
private Path mPath = null;
private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName()); private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName());
private final static String SMALI_DIRNAME = "smali"; private final static String SMALI_DIRNAME = "smali";

View File

@ -202,7 +202,11 @@ public class ApkDecoder {
} }
public void setTargetSdkVersion() throws AndrolibException, IOException { public void setTargetSdkVersion() throws AndrolibException, IOException {
Map<String, String> sdkInfo = mAndrolib.getResTable(mApkFile).getSdkInfo(); if (mResTable == null) {
mResTable = mAndrolib.getResTable(mApkFile);
}
Map<String, String> sdkInfo = mResTable.getSdkInfo();
if (sdkInfo.get("targetSdkVersion") != null) { if (sdkInfo.get("targetSdkVersion") != null) {
mApi = Integer.parseInt(sdkInfo.get("targetSdkVersion")); mApi = Integer.parseInt(sdkInfo.get("targetSdkVersion"));
} }
@ -232,6 +236,7 @@ public class ApkDecoder {
} }
public void setFrameworkDir(String dir) { public void setFrameworkDir(String dir) {
mAndrolib.apkOptions.frameworkFolderLocation = dir;
mFrameworkDir = dir; mFrameworkDir = dir;
} }
@ -244,7 +249,6 @@ public class ApkDecoder {
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file"); "Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
} }
AndrolibResources.sKeepBroken = mKeepBrokenResources; AndrolibResources.sKeepBroken = mKeepBrokenResources;
AndrolibResources.sFrameworkFolder = mFrameworkDir;
mResTable = mAndrolib.getResTable(mApkFile, hasResources); mResTable = mAndrolib.getResTable(mApkFile, hasResources);
mResTable.setFrameTag(mFrameTag); mResTable.setFrameTag(mFrameTag);
} }

View File

@ -0,0 +1,29 @@
package brut.androlib; /**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class ApkOptions {
public boolean forceBuildAll = false;
public boolean debugMode = false;
public boolean verbose = false;
public boolean copyOriginalFiles = false;
public boolean updateFiles = false;
public boolean isFramework = false;
public boolean resourcesAreCompressed = false;
public String frameworkFolderLocation = null;
public String frameworkTag = null;
public String aaptPath = "";
}

View File

@ -17,6 +17,7 @@
package brut.androlib.res; package brut.androlib.res;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
import brut.androlib.ApkOptions;
import brut.androlib.err.CantFindFrameworkResException; import brut.androlib.err.CantFindFrameworkResException;
import brut.androlib.res.data.*; import brut.androlib.res.data.*;
import brut.androlib.res.decoder.*; import brut.androlib.res.decoder.*;
@ -362,11 +363,11 @@ final public class AndrolibResources {
} }
} }
public void aaptPackage(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include, public void aaptPackage(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include)
HashMap<String, Boolean> flags, String aaptPath)
throws AndrolibException { throws AndrolibException {
boolean customAapt = false; boolean customAapt = false;
String aaptPath = apkOptions.aaptPath;
List<String> cmd = new ArrayList<String>(); List<String> cmd = new ArrayList<String>();
// path for aapt binary // path for aapt binary
@ -377,7 +378,7 @@ final public class AndrolibResources {
cmd.add(aaptFile.getPath()); cmd.add(aaptFile.getPath());
customAapt = true; customAapt = true;
if (flags.get("verbose")) { if (apkOptions.verbose) {
LOGGER.info(aaptFile.getPath() + " being used as aapt location."); LOGGER.info(aaptFile.getPath() + " being used as aapt location.");
} }
} else { } else {
@ -399,19 +400,19 @@ final public class AndrolibResources {
cmd.add("p"); cmd.add("p");
if (flags.get("verbose")) { // output aapt verbose if (apkOptions.verbose) { // output aapt verbose
cmd.add("-v"); cmd.add("-v");
} }
if (flags.get("update")) { if (apkOptions.updateFiles) {
cmd.add("-u"); cmd.add("-u");
} }
if (flags.get("debug")) { // inject debuggable="true" into manifest if (apkOptions.debugMode) { // inject debuggable="true" into manifest
cmd.add("--debug-mode"); cmd.add("--debug-mode");
} }
// force package id so that some frameworks build with correct id // force package id so that some frameworks build with correct id
// disable if user adds own aapt (can't know if they have this feature) // disable if user adds own aapt (can't know if they have this feature)
if (mPackageId != null && customAapt == false) { if (mPackageId != null && ! customAapt) {
cmd.add("--forced-package-id"); cmd.add("--forced-package-id");
cmd.add(mPackageId); cmd.add(mPackageId);
} }
@ -447,11 +448,11 @@ final public class AndrolibResources {
cmd.add("-F"); cmd.add("-F");
cmd.add(apkFile.getAbsolutePath()); cmd.add(apkFile.getAbsolutePath());
if (flags.get("framework")) { if (apkOptions.isFramework) {
cmd.add("-x"); cmd.add("-x");
} }
if (!(flags.get("compression"))) { if (! apkOptions.resourcesAreCompressed) {
cmd.add("-0"); cmd.add("-0");
cmd.add("arsc"); cmd.add("arsc");
} }
@ -479,7 +480,7 @@ final public class AndrolibResources {
} }
try { try {
OS.exec(cmd.toArray(new String[0])); OS.exec(cmd.toArray(new String[0]));
if (flags.get("verbose")) { if (apkOptions.verbose) {
LOGGER.info("command ran: "); LOGGER.info("command ran: ");
LOGGER.info(cmd.toString()); LOGGER.info(cmd.toString());
} }
@ -639,6 +640,10 @@ final public class AndrolibResources {
throw new CantFindFrameworkResException(id); throw new CantFindFrameworkResException(id);
} }
public void installFramework(File frameFile) throws AndrolibException {
installFramework(frameFile, apkOptions.frameworkTag);
}
public void installFramework(File frameFile, String tag) public void installFramework(File frameFile, String tag)
throws AndrolibException { throws AndrolibException {
InputStream in = null; InputStream in = null;
@ -728,8 +733,8 @@ final public class AndrolibResources {
String path; String path;
// if a framework path was specified on the command line, use it // if a framework path was specified on the command line, use it
if (sFrameworkFolder != null) { if (apkOptions.frameworkFolderLocation != null) {
path = sFrameworkFolder; path = apkOptions.frameworkFolderLocation;
} else if (OSDetection.isMacOSX()) { } else if (OSDetection.isMacOSX()) {
path = System.getProperty("user.home") + File.separatorChar + "Library" + File.separatorChar + path = System.getProperty("user.home") + File.separatorChar + "Library" + File.separatorChar +
"apktool" + File.separatorChar + "framework"; "apktool" + File.separatorChar + "framework";
@ -739,14 +744,14 @@ final public class AndrolibResources {
File dir = new File(path); File dir = new File(path);
if (dir.getParentFile().isFile()) { if (dir.getParentFile() != null && dir.getParentFile().isFile()) {
System.err.println("Please remove file at " + dir.getParentFile()); System.err.println("Please remove file at " + dir.getParentFile());
System.exit(1); System.exit(1);
} }
if (! dir.exists()) { if (! dir.exists()) {
if (! dir.mkdirs()) { if (! dir.mkdirs()) {
if (sFrameworkFolder != null) { if (apkOptions.frameworkFolderLocation != null) {
System.err.println("Can't create Framework directory: " + dir); System.err.println("Can't create Framework directory: " + dir);
} }
throw new AndrolibException("Can't create directory: " + dir); throw new AndrolibException("Can't create directory: " + dir);
@ -796,13 +801,10 @@ final public class AndrolibResources {
} }
} }
public void setFrameworkFolder(String path) { public ApkOptions apkOptions;
sFrameworkFolder = path;
}
// TODO: dirty static hack. I have to refactor decoding mechanisms. // TODO: dirty static hack. I have to refactor decoding mechanisms.
public static boolean sKeepBroken = false; public static boolean sKeepBroken = false;
public static String sFrameworkFolder = null;
private final static Logger LOGGER = Logger.getLogger(AndrolibResources.class.getName()); private final static Logger LOGGER = Logger.getLogger(AndrolibResources.class.getName());

View File

@ -36,15 +36,15 @@ import org.jf.dexlib2.writer.io.FileDataStore;
*/ */
public class SmaliBuilder { public class SmaliBuilder {
public static void build(ExtFile smaliDir, File dexFile, HashMap<String, Boolean> flags) public static void build(ExtFile smaliDir, File dexFile, boolean debug)
throws AndrolibException { throws AndrolibException {
new SmaliBuilder(smaliDir, dexFile, flags).build(); new SmaliBuilder(smaliDir, dexFile, debug).build();
} }
private SmaliBuilder(ExtFile smaliDir, File dexFile, HashMap<String, Boolean> flags) { private SmaliBuilder(ExtFile smaliDir, File dexFile, boolean debug) {
mSmaliDir = smaliDir; mSmaliDir = smaliDir;
mDexFile = dexFile; mDexFile = dexFile;
mFlags = flags; mDebug = debug;
} }
private void build() throws AndrolibException { private void build() throws AndrolibException {
@ -83,7 +83,7 @@ public class SmaliBuilder {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
List<String> lines = IOUtils.readLines(inStream); List<String> lines = IOUtils.readLines(inStream);
if (!mFlags.get("debug")) { if (! mDebug) {
final String[] linesArray = lines.toArray(new String[0]); final String[] linesArray = lines.toArray(new String[0]);
for (int i = 1; i < linesArray.length - 1; i++) { for (int i = 1; i < linesArray.length - 1; i++) {
out.append(linesArray[i].split("//", 2)[1]).append('\n'); out.append(linesArray[i].split("//", 2)[1]).append('\n');
@ -119,7 +119,7 @@ public class SmaliBuilder {
private final ExtFile mSmaliDir; private final ExtFile mSmaliDir;
private final File mDexFile; private final File mDexFile;
private final HashMap<String, Boolean> mFlags; private final boolean mDebug;
private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName()); private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName());
} }

View File

@ -42,7 +42,7 @@ public class BuildAndDecodeJarTest {
LOGGER.info("Building testjar.jar..."); LOGGER.info("Building testjar.jar...");
File testJar = new File(sTmpDir, "testjar.jar"); File testJar = new File(sTmpDir, "testjar.jar");
new Androlib().build(sTestOrigDir, testJar, TestUtils.returnStockHashMap(),""); new Androlib().build(sTestOrigDir, testJar);
LOGGER.info("Decoding testjar.jar..."); LOGGER.info("Decoding testjar.jar...");
ApkDecoder apkDecoder = new ApkDecoder(testJar); ApkDecoder apkDecoder = new ApkDecoder(testJar);

View File

@ -44,7 +44,7 @@ public class BuildAndDecodeTest {
LOGGER.info("Building testapp.apk..."); LOGGER.info("Building testapp.apk...");
File testApk = new File(sTmpDir, "testapp.apk"); File testApk = new File(sTmpDir, "testapp.apk");
new Androlib().build(sTestOrigDir, testApk, TestUtils.returnStockHashMap(),""); new Androlib().build(sTestOrigDir, testApk);
LOGGER.info("Decoding testapp.apk..."); LOGGER.info("Decoding testapp.apk...");
ApkDecoder apkDecoder = new ApkDecoder(testApk); ApkDecoder apkDecoder = new ApkDecoder(testApk);

View File

@ -76,18 +76,6 @@ public abstract class TestUtils {
} }
} }
public static HashMap<String, Boolean> returnStockHashMap() throws BrutException {
HashMap<String, Boolean> tmp = new HashMap<String, Boolean>();
tmp.put("forceBuildAll", false);
tmp.put("debug", false);
tmp.put("verbose", false);
tmp.put("framework", false);
tmp.put("update", false);
tmp.put("copyOriginal", false);
return tmp;
}
/* /*
* TODO: move to brut.util.Jar - it's not possible for now, because below * TODO: move to brut.util.Jar - it's not possible for now, because below
* implementation uses brut.dir. I think I should merge all my projects to * implementation uses brut.dir. I think I should merge all my projects to