OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / sdk / anttasks / src / com / android / ant / ApkBuilderTask.java
diff --git a/sdk/anttasks/src/com/android/ant/ApkBuilderTask.java b/sdk/anttasks/src/com/android/ant/ApkBuilderTask.java
new file mode 100644 (file)
index 0000000..3f8dec1
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.android.ant;
+
+import com.android.sdklib.build.ApkBuilder;
+import com.android.sdklib.build.ApkCreationException;
+import com.android.sdklib.build.DuplicateFileException;
+import com.android.sdklib.build.SealedApkException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+public class ApkBuilderTask extends Task {
+
+    private final static Pattern PATTERN_JAR_EXT = Pattern.compile("^.+\\.jar$",
+            Pattern.CASE_INSENSITIVE);
+
+    private String mOutFolder;
+    private String mApkFilepath;
+    private String mResourceFile;
+    private boolean mVerbose = false;
+    private boolean mDebugPackaging = false;
+    private boolean mDebugSigning = false;
+    private boolean mHasCode = true;
+    private String mAbiFilter = null;
+
+    private Path mDexPath;
+
+    private final ArrayList<Path> mZipList = new ArrayList<Path>();
+    private final ArrayList<Path> mFileList = new ArrayList<Path>();
+    private final ArrayList<Path> mSourceList = new ArrayList<Path>();
+    private final ArrayList<Path> mJarfolderList = new ArrayList<Path>();
+    private final ArrayList<Path> mJarfileList = new ArrayList<Path>();
+    private final ArrayList<Path> mNativeList = new ArrayList<Path>();
+
+    /**
+     * Sets the value of the "outfolder" attribute.
+     * @param outFolder the value.
+     */
+    public void setOutfolder(Path outFolder) {
+        mOutFolder = TaskHelper.checkSinglePath("outfolder", outFolder);
+    }
+
+    /**
+     * Sets the full filepath to the apk to generate.
+     * @param filepath
+     */
+    public void setApkfilepath(String filepath) {
+        mApkFilepath = filepath;
+    }
+
+    /**
+     * Sets the resourcefile attribute
+     * @param resourceFile
+     */
+    public void setResourcefile(String resourceFile) {
+        mResourceFile = resourceFile;
+    }
+
+    /**
+     * Sets the value of the "verbose" attribute.
+     * @param verbose the value.
+     */
+    public void setVerbose(boolean verbose) {
+        mVerbose = verbose;
+    }
+
+    /**
+     * Sets the value of the "debug" attribute.
+     * @param debug the debug mode value.
+     */
+    public void setDebug(boolean debug) {
+        System.out.println("WARNNG: Using deprecated 'debug' attribute in ApkBuilderTask." +
+        "Use 'debugpackaging' and 'debugsigning' instead.");
+        mDebugPackaging = debug;
+        mDebugSigning = debug;
+    }
+
+    /**
+     * Sets the value of the "debugpackaging" attribute.
+     * @param debug the debug mode value.
+     */
+    public void setDebugpackaging(boolean debug) {
+        mDebugPackaging = debug;
+    }
+
+    /**
+     * Sets the value of the "debugsigning" attribute.
+     * @param debug the debug mode value.
+     */
+    public void setDebugsigning(boolean debug) {
+        mDebugSigning = debug;
+    }
+
+    /**
+     * Sets an ABI filter. If non <code>null</code>, then only native libraries matching the given
+     * ABI will be packaged with the APK.
+     * @param abiFilter the ABI to accept (and reject all other). If null or empty string, no ABIs
+     * are rejected. This must be a single ABI name as defined by the Android NDK. For a list
+     * of valid ABI names, see $NDK/docs/CPU-ARCH-ABIS.TXT
+     */
+    public void setAbifilter(String abiFilter) {
+        if (abiFilter != null && abiFilter.length() > 0) {
+            mAbiFilter = abiFilter.trim();
+        } else {
+            mAbiFilter = null;
+        }
+    }
+
+    /**
+     * Sets the hascode attribute. Default is true.
+     * If set to false, then <dex> and <sourcefolder> nodes are ignored and not processed.
+     * @param hasCode the value of the attribute.
+     */
+    public void setHascode(boolean hasCode) {
+        mHasCode   = hasCode;
+    }
+
+    /**
+     * Returns an object representing a nested <var>zip</var> element.
+     */
+    public Object createZip() {
+        Path path = new Path(getProject());
+        mZipList.add(path);
+        return path;
+    }
+
+    /**
+     * Returns an object representing a nested <var>dex</var> element.
+     * This is similar to a nested <var>file</var> element, except when {@link #mHasCode}
+     * is <code>false</code> in which case it's ignored.
+     */
+    public Object createDex() {
+        if (mDexPath == null) {
+            return mDexPath = new Path(getProject());
+        } else {
+            throw new BuildException("Only one <dex> inner element can be provided");
+        }
+    }
+
+    /**
+     * Returns an object representing a nested <var>file</var> element.
+     */
+    public Object createFile() {
+        System.out.println("WARNING: Using deprecated <file> inner element in ApkBuilderTask." +
+        "Use <dex path=...> instead.");
+        Path path = new Path(getProject());
+        mFileList.add(path);
+        return path;
+    }
+
+    /**
+     * Returns an object representing a nested <var>sourcefolder</var> element.
+     */
+    public Object createSourcefolder() {
+        Path path = new Path(getProject());
+        mSourceList.add(path);
+        return path;
+    }
+
+    /**
+     * Returns an object representing a nested <var>jarfolder</var> element.
+     */
+    public Object createJarfolder() {
+        Path path = new Path(getProject());
+        mJarfolderList.add(path);
+        return path;
+    }
+
+    /**
+     * Returns an object representing a nested <var>jarfile</var> element.
+     */
+    public Object createJarfile() {
+        Path path = new Path(getProject());
+        mJarfileList.add(path);
+        return path;
+    }
+
+    /**
+     * Returns an object representing a nested <var>nativefolder</var> element.
+     */
+    public Object createNativefolder() {
+        Path path = new Path(getProject());
+        mNativeList.add(path);
+        return path;
+    }
+
+    @Override
+    public void execute() throws BuildException {
+
+        File outputFile;
+        if (mApkFilepath != null) {
+            outputFile = new File(mApkFilepath);
+        } else {
+            throw new BuildException("missing attribute 'apkFilepath'");
+        }
+
+        if (mResourceFile == null) {
+            throw new BuildException("missing attribute 'resourcefile'");
+        }
+
+        if (mOutFolder == null) {
+            throw new BuildException("missing attribute 'outfolder'");
+        }
+
+        // check dexPath is only one file.
+        File dexFile = null;
+        if (mHasCode) {
+            String[] dexFiles = mDexPath.list();
+            if (dexFiles.length != 1) {
+                throw new BuildException(String.format(
+                        "Expected one dex file but path value resolve to %d files.",
+                        dexFiles.length));
+            }
+            dexFile = new File(dexFiles[0]);
+        }
+
+        try {
+            if (mDebugSigning) {
+                System.out.println(String.format(
+                        "Creating %s and signing it with a debug key...", outputFile.getName()));
+            } else {
+                System.out.println(String.format(
+                        "Creating %s for release...", outputFile.getName()));
+            }
+
+            ApkBuilder apkBuilder = new ApkBuilder(
+                    outputFile,
+                    new File(mOutFolder, mResourceFile),
+                    dexFile,
+                    mDebugSigning ? ApkBuilder.getDebugKeystore() : null,
+                    mVerbose ? System.out : null);
+            apkBuilder.setDebugMode(mDebugPackaging);
+
+
+            // add the content of the zip files.
+            for (Path pathList : mZipList) {
+                for (String path : pathList.list()) {
+                    apkBuilder.addZipFile(new File(path));
+                }
+            }
+
+            // add the files that go to the root of the archive (this is deprecated)
+            for (Path pathList : mFileList) {
+                for (String path : pathList.list()) {
+                    File f = new File(path);
+                    apkBuilder.addFile(f, f.getName());
+                }
+            }
+
+            // now go through the list of file to directly add the to the list.
+            if (mHasCode) {
+                for (Path pathList : mSourceList) {
+                    for (String path : pathList.list()) {
+                        apkBuilder.addSourceFolder(new File(path));
+                    }
+                }
+            }
+
+            // now go through the list of jar folders.
+            for (Path pathList : mJarfolderList) {
+                for (String path : pathList.list()) {
+                    // it's ok if top level folders are missing
+                    File folder = new File(path);
+                    if (folder.isDirectory()) {
+                        String[] filenames = folder.list(new FilenameFilter() {
+                            public boolean accept(File dir, String name) {
+                                return PATTERN_JAR_EXT.matcher(name).matches();
+                            }
+                        });
+
+                        for (String filename : filenames) {
+                            apkBuilder.addResourcesFromJar(new File(folder, filename));
+                        }
+                    }
+                }
+            }
+
+            // now go through the list of jar files.
+            for (Path pathList : mJarfileList) {
+                for (String path : pathList.list()) {
+                    apkBuilder.addResourcesFromJar(new File(path));
+                }
+            }
+
+            // now the native lib folder.
+            for (Path pathList : mNativeList) {
+                for (String path : pathList.list()) {
+                    // it's ok if top level folders are missing
+                    File folder = new File(path);
+                    if (folder.isDirectory()) {
+                        apkBuilder.addNativeLibraries(folder, mAbiFilter);
+                    }
+                }
+            }
+
+
+            // close the archive
+            apkBuilder.sealApk();
+
+        } catch (DuplicateFileException e) {
+            System.err.println(String.format(
+                    "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s",
+                    e.getArchivePath(), e.getFile1(), e.getFile2()));
+            throw new BuildException(e);
+        } catch (ApkCreationException e) {
+            throw new BuildException(e);
+        } catch (SealedApkException e) {
+            throw new BuildException(e);
+        } catch (IllegalArgumentException e) {
+            throw new BuildException(e);
+        }
+    }
+}