1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.sdklib.build; 18 19 20import java.io.File; 21import java.io.FilenameFilter; 22import java.util.ArrayList; 23import java.util.regex.Pattern; 24 25 26/** 27 * Command line APK builder with signing support. 28 */ 29public final class ApkBuilderMain { 30 31 private final static Pattern PATTERN_JAR_EXT = Pattern.compile("^.+\\.jar$", 32 Pattern.CASE_INSENSITIVE); 33 34 /** 35 * Main method. This is meant to be called from the command line through an exec. 36 * <p/>WARNING: this will call {@link System#exit(int)} if anything goes wrong. 37 * @param args command line arguments. 38 */ 39 public static void main(String[] args) { 40 if (args.length < 1) { 41 printUsageAndQuit(); 42 } 43 44 System.err.println("\nTHIS TOOL IS DEPRECATED. See --help for more information.\n"); 45 46 try { 47 File outApk = new File(args[0]); 48 49 File dexFile = null; 50 ArrayList<File> zipArchives = new ArrayList<File>(); 51 ArrayList<File> sourceFolders = new ArrayList<File>(); 52 ArrayList<File> jarFiles = new ArrayList<File>(); 53 ArrayList<File> nativeFolders = new ArrayList<File>(); 54 55 boolean verbose = false; 56 boolean signed = true; 57 boolean debug = false; 58 59 int index = 1; 60 do { 61 String argument = args[index++]; 62 63 if ("-v".equals(argument)) { 64 verbose = true; 65 66 } else if ("-d".equals(argument)) { 67 debug = true; 68 69 } else if ("-u".equals(argument)) { 70 signed = false; 71 72 } else if ("-z".equals(argument)) { 73 // quick check on the next argument. 74 if (index == args.length) { 75 printAndExit("Missing value for -z"); 76 } 77 78 zipArchives.add(new File(args[index++])); 79 } else if ("-f". equals(argument)) { 80 if (dexFile != null) { 81 // can't have more than one dex file. 82 printAndExit("Can't have more than one dex file (-f)"); 83 } 84 // quick check on the next argument. 85 if (index == args.length) { 86 printAndExit("Missing value for -f"); 87 } 88 89 dexFile = new File(args[index++]); 90 } else if ("-rf". equals(argument)) { 91 // quick check on the next argument. 92 if (index == args.length) { 93 printAndExit("Missing value for -rf"); 94 } 95 96 sourceFolders.add(new File(args[index++])); 97 } else if ("-rj". equals(argument)) { 98 // quick check on the next argument. 99 if (index == args.length) { 100 printAndExit("Missing value for -rj"); 101 } 102 103 jarFiles.add(new File(args[index++])); 104 } else if ("-nf".equals(argument)) { 105 // quick check on the next argument. 106 if (index == args.length) { 107 printAndExit("Missing value for -nf"); 108 } 109 110 nativeFolders.add(new File(args[index++])); 111 } else if ("-storetype".equals(argument)) { 112 // quick check on the next argument. 113 if (index == args.length) { 114 printAndExit("Missing value for -storetype"); 115 } 116 117 // FIXME 118 } else { 119 printAndExit("Unknown argument: " + argument); 120 } 121 } while (index < args.length); 122 123 if (zipArchives.size() == 0) { 124 printAndExit("No zip archive, there must be one for the resources"); 125 } 126 127 // create the builder with the basic files. 128 ApkBuilder builder = new ApkBuilder(outApk, zipArchives.get(0), dexFile, 129 signed ? ApkBuilder.getDebugKeystore() : null, 130 verbose ? System.out : null); 131 builder.setDebugMode(debug); 132 133 // add the rest of the files. 134 // first zip Archive was used in the constructor. 135 for (int i = 1 ; i < zipArchives.size() ; i++) { 136 builder.addZipFile(zipArchives.get(i)); 137 } 138 139 for (File sourceFolder : sourceFolders) { 140 builder.addSourceFolder(sourceFolder); 141 } 142 143 for (File jarFile : jarFiles) { 144 if (jarFile.isDirectory()) { 145 String[] filenames = jarFile.list(new FilenameFilter() { 146 @Override 147 public boolean accept(File dir, String name) { 148 return PATTERN_JAR_EXT.matcher(name).matches(); 149 } 150 }); 151 152 for (String filename : filenames) { 153 builder.addResourcesFromJar(new File(jarFile, filename)); 154 } 155 } else { 156 builder.addResourcesFromJar(jarFile); 157 } 158 } 159 160 for (File nativeFolder : nativeFolders) { 161 builder.addNativeLibraries(nativeFolder); 162 } 163 164 // seal the apk 165 builder.sealApk(); 166 167 168 } catch (ApkCreationException e) { 169 printAndExit(e.getMessage()); 170 } catch (DuplicateFileException e) { 171 printAndExit(String.format( 172 "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s", 173 e.getArchivePath(), e.getFile1(), e.getFile2())); 174 } catch (SealedApkException e) { 175 printAndExit(e.getMessage()); 176 } catch (Exception e) { 177 e.printStackTrace(); 178 } 179 } 180 181 private static void printUsageAndQuit() { 182 // 80 cols marker: 01234567890123456789012345678901234567890123456789012345678901234567890123456789 183 System.err.println("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); 184 System.err.println("THIS TOOL IS DEPRECATED and may stop working at any time!\n"); 185 System.err.println("If you wish to use apkbuilder for a custom build system, please look at the"); 186 System.err.println("com.android.sdklib.build.ApkBuilder which provides support for"); 187 System.err.println("recent build improvements including library projects."); 188 System.err.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n"); 189 System.err.println("A command line tool to package an Android application from various sources."); 190 System.err.println("Usage: apkbuilder <out archive> [-v][-u][-storetype STORE_TYPE] [-z inputzip]"); 191 System.err.println(" [-f inputfile] [-rf input-folder] [-rj -input-path]"); 192 System.err.println(""); 193 System.err.println(" -v Verbose."); 194 System.err.println(" -d Debug Mode: Includes debug files in the APK file."); 195 System.err.println(" -u Creates an unsigned package."); 196 System.err.println(" -storetype Forces the KeyStore type. If ommited the default is used."); 197 System.err.println(""); 198 System.err.println(" -z Followed by the path to a zip archive."); 199 System.err.println(" Adds the content of the application package."); 200 System.err.println(""); 201 System.err.println(" -f Followed by the path to a file."); 202 System.err.println(" Adds the file to the application package."); 203 System.err.println(""); 204 System.err.println(" -rf Followed by the path to a source folder."); 205 System.err.println(" Adds the java resources found in that folder to the application"); 206 System.err.println(" package, while keeping their path relative to the source folder."); 207 System.err.println(""); 208 System.err.println(" -rj Followed by the path to a jar file or a folder containing"); 209 System.err.println(" jar files."); 210 System.err.println(" Adds the java resources found in the jar file(s) to the application"); 211 System.err.println(" package."); 212 System.err.println(""); 213 System.err.println(" -nf Followed by the root folder containing native libraries to"); 214 System.err.println(" include in the application package."); 215 216 System.exit(1); 217 } 218 219 private static void printAndExit(String... messages) { 220 for (String message : messages) { 221 System.err.println(message); 222 } 223 System.exit(1); 224 } 225 226 private ApkBuilderMain() { 227 } 228} 229