Java tutorial
package com.apkTool; import com.libs.brut.androlib.Androlib; import com.libs.brut.androlib.AndrolibException; import com.libs.brut.androlib.ApkDecoder; import com.libs.brut.androlib.ApkOptions; import com.libs.brut.androlib.ApktoolProperties; import com.libs.brut.androlib.err.CantFindFrameworkResException; import com.libs.brut.androlib.err.InFileNotFoundException; import com.libs.brut.androlib.err.OutDirExistsException; import J.common.BrutException; import J.dir.DirectoryException; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import java.io.File; import java.io.IOException; import java.util.logging.*; public class Main { public static void main(String[] args) throws IOException, InterruptedException, BrutException { /** * ?apk * ?.apk * + ExtDataInput.javaskipCheckChunkTypeInt 73 * * .apk * qq.apk * + ResTypeSpec.javaaddResSpec78 * * .apk * ?.apk */ // ?? args = new String[] { "d", "-f", "ApkTool/apk/qq.apk", "-o", "ApkTool/out" }; // // args = new String[]{"b", "out", "-o", "apk/zhifubao_build.apk"}; // set verbosity default Verbosity verbosity = Verbosity.NORMAL; // cli parser CommandLineParser parser = new PosixParser(); CommandLine commandLine; // load options _Options(); try { commandLine = parser.parse(allOptions, args, false); } catch (ParseException ex) { System.err.println(ex.getMessage()); usage(); return; } // check for verbose / quiet if (commandLine.hasOption("-v") || commandLine.hasOption("--verbose")) { verbosity = Verbosity.VERBOSE; } else if (commandLine.hasOption("-q") || commandLine.hasOption("--quiet")) { verbosity = Verbosity.QUIET; } setupLogging(verbosity); // check for advance mode if (commandLine.hasOption("advance") || commandLine.hasOption("advanced")) { setAdvanceMode(true); } // @todo use new ability of apache-commons-cli to check hasOption for non-prefixed items boolean cmdFound = false; for (String opt : commandLine.getArgs()) { if (opt.equalsIgnoreCase("d") || opt.equalsIgnoreCase("decode")) { cmdDecode(commandLine); cmdFound = true; } else if (opt.equalsIgnoreCase("b") || opt.equalsIgnoreCase("build")) { cmdBuild(commandLine); cmdFound = true; } else if (opt.equalsIgnoreCase("if") || opt.equalsIgnoreCase("install-framework")) { cmdInstallFramework(commandLine); cmdFound = true; } else if (opt.equalsIgnoreCase("empty-framework-dir")) { cmdEmptyFrameworkDirectory(commandLine); cmdFound = true; } else if (opt.equalsIgnoreCase("publicize-resources")) { cmdPublicizeResources(commandLine); cmdFound = true; } } // if no commands ran, run the version / usage check. if (!cmdFound) { if (commandLine.hasOption("version")) { _version(); } else { usage(); } } } @SuppressWarnings("static-access") private static void _Options() { // create options Option versionOption = OptionBuilder.withLongOpt("version").withDescription("prints the version then exits") .create("version"); Option advanceOption = OptionBuilder.withLongOpt("advanced").withDescription("prints advance information.") .create("advance"); Option noSrcOption = OptionBuilder.withLongOpt("no-src").withDescription("Do not decode sources.") .create("s"); Option noResOption = OptionBuilder.withLongOpt("no-res").withDescription("Do not decode resources.") .create("r"); Option debugDecOption = OptionBuilder.withLongOpt("debug") .withDescription("REMOVED (DOES NOT WORK): Decode in debug mode.").create("d"); Option analysisOption = OptionBuilder.withLongOpt("match-original") .withDescription("Keeps files to closest to original as possible. Prevents rebuild.").create("m"); Option apiLevelOption = OptionBuilder.withLongOpt("api") .withDescription("The numeric api-level of the file to generate, e.g. 14 for ICS.").hasArg(true) .withArgName("API").create(); Option debugBuiOption = OptionBuilder.withLongOpt("debug") .withDescription("Sets android:debuggable to \"true\" in the APK's compiled manifest").create("d"); Option noDbgOption = OptionBuilder.withLongOpt("no-debug-info") .withDescription("don't write out debug info (.local, .param, .line, etc.)").create("b"); Option forceDecOption = OptionBuilder.withLongOpt("force") .withDescription("Force delete destination directory.").create("f"); Option frameTagOption = OptionBuilder.withLongOpt("frame-tag") .withDescription("Uses framework files tagged by <tag>.").hasArg(true).withArgName("tag") .create("t"); Option frameDirOption = OptionBuilder.withLongOpt("frame-path") .withDescription("Uses framework files located in <dir>.").hasArg(true).withArgName("dir") .create("p"); Option frameIfDirOption = OptionBuilder.withLongOpt("frame-path") .withDescription("Stores framework files into <dir>.").hasArg(true).withArgName("dir").create("p"); Option keepResOption = OptionBuilder.withLongOpt("keep-broken-res") .withDescription("Use if there was an error and some resources were dropped, e.g.\n" + " \"Invalid config flags detected. Dropping resources\", but you\n" + " want to decode them anyway, even with errors. You will have to\n" + " fix them manually before building.") .create("k"); Option forceBuiOption = OptionBuilder.withLongOpt("force-all") .withDescription("Skip changes detection and build all files.").create("f"); Option aaptOption = OptionBuilder.withLongOpt("aapt").hasArg(true).withArgName("loc") .withDescription("Loads aapt from specified location.").create("a"); Option originalOption = OptionBuilder.withLongOpt("copy-original") .withDescription( "Copies original AndroidManifest.xml and META-INF. See project page for more info.") .create("c"); Option tagOption = OptionBuilder.withLongOpt("tag").withDescription("Tag frameworks using <tag>.") .hasArg(true).withArgName("tag").create("t"); Option outputBuiOption = OptionBuilder.withLongOpt("output") .withDescription("The name of apk that gets written. Default is dist/name.apk").hasArg(true) .withArgName("dir").create("o"); Option outputDecOption = OptionBuilder.withLongOpt("output") .withDescription("The name of folder that gets written. Default is apk.out").hasArg(true) .withArgName("dir").create("o"); Option quietOption = OptionBuilder.withLongOpt("quiet").create("q"); Option verboseOption = OptionBuilder.withLongOpt("verbose").create("v"); // check for advance mode if (isAdvanceMode()) { DecodeOptions.addOption(noDbgOption); DecodeOptions.addOption(keepResOption); DecodeOptions.addOption(analysisOption); DecodeOptions.addOption(apiLevelOption); BuildOptions.addOption(debugBuiOption); BuildOptions.addOption(aaptOption); BuildOptions.addOption(originalOption); } // add global options normalOptions.addOption(versionOption); normalOptions.addOption(advanceOption); // add basic decode options DecodeOptions.addOption(frameTagOption); DecodeOptions.addOption(outputDecOption); DecodeOptions.addOption(frameDirOption); DecodeOptions.addOption(forceDecOption); DecodeOptions.addOption(noSrcOption); DecodeOptions.addOption(noResOption); // add basic build options BuildOptions.addOption(outputBuiOption); BuildOptions.addOption(frameDirOption); BuildOptions.addOption(forceBuiOption); // add basic framework options frameOptions.addOption(tagOption); frameOptions.addOption(frameIfDirOption); // add empty framework options emptyFrameworkOptions.addOption(forceDecOption); emptyFrameworkOptions.addOption(frameIfDirOption); // add all, loop existing cats then manually add advance for (Object op : normalOptions.getOptions()) { allOptions.addOption((Option) op); } for (Object op : DecodeOptions.getOptions()) { allOptions.addOption((Option) op); } for (Object op : BuildOptions.getOptions()) { allOptions.addOption((Option) op); } for (Object op : frameOptions.getOptions()) { allOptions.addOption((Option) op); } allOptions.addOption(analysisOption); allOptions.addOption(debugDecOption); allOptions.addOption(noDbgOption); allOptions.addOption(keepResOption); allOptions.addOption(debugBuiOption); allOptions.addOption(aaptOption); allOptions.addOption(originalOption); allOptions.addOption(verboseOption); allOptions.addOption(quietOption); } private static void usage() { // load basicOptions _Options(); HelpFormatter formatter = new HelpFormatter(); formatter.setWidth(120); // print out license info prior to formatter. System.out.println("Apktool v" + Androlib.getVersion() + " - a tool for reengineering Android apk files\n" + "with smali v" + ApktoolProperties.get("smaliVersion") + " and baksmali v" + ApktoolProperties.get("baksmaliVersion") + "\n" + "Copyright 2014 Ryszard Winiewski <brut.alll@gmail.com>\n" + "Updated by Connor Tumbleson <connor.tumbleson@gmail.com>"); if (isAdvanceMode()) { System.out.println("Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n"); } else { System.out.println(""); } // 4 usage outputs (general, frameworks, decode, build) formatter.printHelp("apktool " + verbosityHelp(), normalOptions); formatter.printHelp("apktool " + verbosityHelp() + "if|install-framework [options] <framework.apk>", frameOptions); formatter.printHelp("apktool " + verbosityHelp() + "d[ecode] [options] <file_apk>", DecodeOptions); formatter.printHelp("apktool " + verbosityHelp() + "b[uild] [options] <app_path>", BuildOptions); if (isAdvanceMode()) { formatter.printHelp("apktool " + verbosityHelp() + "publicize-resources <file_path>", emptyOptions); formatter.printHelp("apktool " + verbosityHelp() + "empty-framework-dir [options]", emptyFrameworkOptions); System.out.println(""); } else { System.out.println(""); } // print out more information System.out.println("For additional info, see: http://ibotpeaches.github.io/Apktool/ \n" + "For smali/baksmali info, see: https://github.com/JesusFreke/smali"); } private static String verbosityHelp() { if (isAdvanceMode()) { return "[-q|--quiet OR -v|--verbose] "; } else { return ""; } } private static void setupLogging(Verbosity verbosity) { Logger logger = Logger.getLogger(""); for (Handler handler : logger.getHandlers()) { logger.removeHandler(handler); } LogManager.getLogManager().reset(); if (verbosity == Verbosity.QUIET) { return; } Handler handler = new Handler() { @Override public void publish(LogRecord record) { if (getFormatter() == null) { setFormatter(new SimpleFormatter()); } try { String message = getFormatter().format(record); if (record.getLevel().intValue() >= Level.WARNING.intValue()) { System.err.write(message.getBytes()); } else { System.out.write(message.getBytes()); } } catch (Exception exception) { reportError(null, exception, ErrorManager.FORMAT_FAILURE); } } @Override public void close() throws SecurityException { } @Override public void flush() { } }; logger.addHandler(handler); if (verbosity == Verbosity.VERBOSE) { handler.setLevel(Level.ALL); logger.setLevel(Level.ALL); } else { handler.setFormatter(new Formatter() { @Override public String format(LogRecord record) { return record.getLevel().toString().charAt(0) + ": " + record.getMessage() + System.getProperty("line.separator"); } }); } } private static void cmdDecode(CommandLine cli) throws AndrolibException { // ?? ApkDecoder decoder = new ApkDecoder(); int paraCount = cli.getArgList().size(); String apkName = (String) cli.getArgList().get(paraCount - 1); File outDir; // check for options if (cli.hasOption("s") || cli.hasOption("no-src")) { decoder.setDecodeSources(ApkDecoder.DECODE_SOURCES_NONE); } if (cli.hasOption("d") || cli.hasOption("debug")) { System.err.println( "SmaliDebugging has been removed in 2.1.0 onward. Please see: https://github.com/iBotPeaches/Apktool/issues/1061"); System.exit(1); } if (cli.hasOption("b") || cli.hasOption("no-debug-info")) { decoder.setBaksmaliDebugMode(false); } if (cli.hasOption("t") || cli.hasOption("frame-tag")) { decoder.setFrameworkTag(cli.getOptionValue("t")); } if (cli.hasOption("f") || cli.hasOption("force")) { decoder.setForceDelete(true); } if (cli.hasOption("r") || cli.hasOption("no-res")) { decoder.setDecodeResources(ApkDecoder.DECODE_RESOURCES_NONE); } if (cli.hasOption("k") || cli.hasOption("keep-broken-res")) { decoder.setKeepBrokenResources(true); } if (cli.hasOption("p") || cli.hasOption("frame-path")) { decoder.setFrameworkDir(cli.getOptionValue("p")); } if (cli.hasOption("m") || cli.hasOption("match-original")) { decoder.setAnalysisMode(true, false); } if (cli.hasOption("api")) { decoder.setApi(Integer.parseInt(cli.getOptionValue("api"))); } if (cli.hasOption("o") || cli.hasOption("output")) { outDir = new File(cli.getOptionValue("o")); decoder.setOutDir(outDir); } else { // make out folder manually using name of apk String outName = apkName; outName = outName.endsWith(".apk") ? outName.substring(0, outName.length() - 4).trim() : outName + ".out"; // make file from path outName = new File(outName).getName(); outDir = new File(outName); decoder.setOutDir(outDir); } decoder.setApkFile(new File(apkName)); try { decoder.decode(); } catch (OutDirExistsException ex) { System.err.println("Destination directory (" + outDir.getAbsolutePath() + ") " + "already exists. Use -f switch if you want to overwrite it."); System.exit(1); } catch (InFileNotFoundException ex) { System.err.println("Input file (" + apkName + ") " + "was not found or was not readable."); System.exit(1); } catch (CantFindFrameworkResException ex) { System.err.println("Can't find framework resources for package of id: " + String.valueOf(ex.getPkgId()) + ". You must install proper " + "framework files, see project website for more info."); System.exit(1); } catch (IOException ex) { System.err.println("Could not modify file. Please ensure you have permission."); System.exit(1); } catch (DirectoryException ex) { System.err.println("Could not modify internal dex files. Please ensure you have permission."); System.exit(1); } } private static void cmdBuild(CommandLine cli) throws BrutException { String[] args = cli.getArgs(); String appDirName = args.length < 2 ? "." : args[1]; File outFile; ApkOptions apkOptions = new ApkOptions(); // check for build options if (cli.hasOption("f") || cli.hasOption("force-all")) { apkOptions.forceBuildAll = true; } if (cli.hasOption("d") || cli.hasOption("debug")) { System.out.println( "SmaliDebugging has been removed in 2.1.0 onward. Please see: https://github.com/iBotPeaches/Apktool/issues/1061"); apkOptions.debugMode = true; } if (cli.hasOption("v") || cli.hasOption("verbose")) { apkOptions.verbose = true; } if (cli.hasOption("a") || cli.hasOption("aapt")) { apkOptions.aaptPath = cli.getOptionValue("a"); } if (cli.hasOption("c") || cli.hasOption("copy-original")) { apkOptions.copyOriginalFiles = true; } if (cli.hasOption("p") || cli.hasOption("frame-path")) { apkOptions.frameworkFolderLocation = cli.getOptionValue("p"); } if (cli.hasOption("o") || cli.hasOption("output")) { outFile = new File(cli.getOptionValue("o")); } else { outFile = null; } // try and build apk new Androlib(apkOptions).build(new File(appDirName), outFile); } private static void cmdInstallFramework(CommandLine cli) throws AndrolibException { int paraCount = cli.getArgList().size(); String apkName = (String) cli.getArgList().get(paraCount - 1); ApkOptions apkOptions = new ApkOptions(); if (cli.hasOption("p") || cli.hasOption("frame-path")) { apkOptions.frameworkFolderLocation = cli.getOptionValue("p"); } if (cli.hasOption("t") || cli.hasOption("tag")) { apkOptions.frameworkTag = cli.getOptionValue("t"); } new Androlib(apkOptions).installFramework(new File(apkName)); } private static void cmdEmptyFrameworkDirectory(CommandLine cli) throws AndrolibException { ApkOptions apkOptions = new ApkOptions(); if (cli.hasOption("f") || cli.hasOption("force")) { apkOptions.forceDeleteFramework = true; } if (cli.hasOption("p") || cli.hasOption("frame-path")) { apkOptions.frameworkFolderLocation = cli.getOptionValue("p"); } new Androlib(apkOptions).emptyFrameworkDirectory(); } private static void cmdPublicizeResources(CommandLine cli) throws AndrolibException { int paraCount = cli.getArgList().size(); String apkName = (String) cli.getArgList().get(paraCount - 1); new Androlib().publicizeResources(new File(apkName)); } private static void _version() { System.out.println(Androlib.getVersion()); } public static boolean isAdvanceMode() { return advanceMode; } public static void setAdvanceMode(boolean advanceMode) { Main.advanceMode = advanceMode; } private static boolean advanceMode = false; private final static Options normalOptions; private final static Options DecodeOptions; private final static Options BuildOptions; private final static Options frameOptions; private final static Options allOptions; private final static Options emptyOptions; private final static Options emptyFrameworkOptions; static { // normal and advance usage output normalOptions = new Options(); BuildOptions = new Options(); DecodeOptions = new Options(); frameOptions = new Options(); allOptions = new Options(); emptyOptions = new Options(); emptyFrameworkOptions = new Options(); } private enum Verbosity { NORMAL, VERBOSE, QUIET } }