OSDN Git Service

Make the Ant script sign and zipalign release builds.
authorXavier Ducrohet <xav@android.com>
Thu, 13 Aug 2009 23:49:40 +0000 (16:49 -0700)
committerXavier Ducrohet <xav@android.com>
Fri, 14 Aug 2009 04:13:53 +0000 (21:13 -0700)
It will also align debug builds.
BUG: 2052744

anttasks/src/com/android/ant/ApkBuilderTask.java
scripts/android_rules.xml
sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java

index af87c78..3a15368 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.tools.ant.Project;
 import org.apache.tools.ant.ProjectComponent;
 import org.apache.tools.ant.Task;
 import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Path.PathElement;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -39,6 +40,9 @@ import java.util.Map.Entry;
 
 public class ApkBuilderTask extends Task {
 
+    // ref id to the <path> object containing all the boot classpaths.
+    private final static String REF_APK_PATH = "android.apks.path";
+
     /**
      * Class to represent nested elements. Since they all have only one attribute ('path'), the
      * same class can be used for all the nested elements (zip, file, sourcefolder, jarfolder,
@@ -152,7 +156,7 @@ public class ApkBuilderTask extends Task {
 
     @Override
     public void execute() throws BuildException {
-        Project taskProject = getProject();
+        Project antProject = getProject();
 
         ApkBuilderImpl apkBuilder = new ApkBuilderImpl();
         apkBuilder.setVerbose(mVerbose);
@@ -197,13 +201,16 @@ public class ApkBuilderTask extends Task {
                 ApkBuilderImpl.processNativeFolder(offset, f, mNativeLibraries);
             }
 
+            // create the Path item that will contain all the generated APKs
+            // for reuse by other targets (signing/zipaligning)
+            Path path = new Path(antProject);
 
             // first do a full resource package
-            createApk(apkBuilder, null /*configName*/, null /*resourceFilter*/);
+            createApk(apkBuilder, null /*configName*/, null /*resourceFilter*/, path);
 
             // now see if we need to create file with filtered resources.
             // Get the project base directory.
-            File baseDir = taskProject.getBaseDir();
+            File baseDir = antProject.getBaseDir();
             ProjectProperties properties = ProjectProperties.load(baseDir.getAbsolutePath(),
                     PropertyType.DEFAULT);
 
@@ -211,9 +218,13 @@ public class ApkBuilderTask extends Task {
             if (apkConfigs.size() > 0) {
                 Set<Entry<String, String>> entrySet = apkConfigs.entrySet();
                 for (Entry<String, String> entry : entrySet) {
-                    createApk(apkBuilder, entry.getKey(), entry.getValue());
+                    createApk(apkBuilder, entry.getKey(), entry.getValue(), path);
                 }
             }
+
+            // finally sets the path in the project with a reference
+            antProject.addReference(REF_APK_PATH, path);
+
         } catch (FileNotFoundException e) {
             throw new BuildException(e);
         } catch (IllegalArgumentException e) {
@@ -230,10 +241,12 @@ public class ApkBuilderTask extends Task {
      * package will be generated.
      * @param resourceFilter the resource configuration filter to pass to aapt (if configName is
      * non null)
+     * @param path Ant {@link Path} to which add the generated APKs as {@link PathElement}
      * @throws FileNotFoundException
      * @throws ApkCreationException
      */
-    private void createApk(ApkBuilderImpl apkBuilder, String configName, String resourceFilter)
+    private void createApk(ApkBuilderImpl apkBuilder, String configName, String resourceFilter,
+            Path path)
             throws FileNotFoundException, ApkCreationException {
         // All the files to be included in the archive have already been prep'ed up, except
         // the resource package.
@@ -259,7 +272,7 @@ public class ApkBuilderTask extends Task {
         }
 
         if (mSigned) {
-            filename = filename + "-debug.apk";
+            filename = filename + "-debug-unaligned.apk";
         } else {
             filename = filename + "-unsigned.apk";
         }
@@ -284,8 +297,13 @@ public class ApkBuilderTask extends Task {
             }
         }
 
+        // out File
         File f = new File(mOutFolder, filename);
 
+        // add it to the Path object
+        PathElement element = path.createPathElement();
+        element.setLocation(f);
+
         // and generate the apk
         apkBuilder.createPackage(f.getAbsoluteFile(), mZipArchives,
                 mArchiveFiles, mJavaResources, mResourcesJars, mNativeLibraries);
index be53264..c8880c8 100644 (file)
     </condition>
 
     <!-- The final package file to generate -->
+    <property name="out-debug-unaligned-package" value="${out-folder}/${ant.project.name}-debug-unaligned.apk"/>
     <property name="out-debug-package" value="${out-folder}/${ant.project.name}-debug.apk"/>
+    <property name="out-unsigned-package" value="${out-folder}/${ant.project.name}-unsigned.apk"/>
+    <property name="out-unaligned-package" value="${out-folder}/${ant.project.name}-unaligned.apk"/>
+    <property name="out-release-package" value="${out-folder}/${ant.project.name}-release.apk"/>
 
     <!-- Tools -->
     <condition property="exe" value=".exe" else=""><os family="windows"/></condition>
     <property name="adb" value="${android-tools}/adb${exe}"/>
+    <property name="zipalign" value="${android-tools}/zipalign${exe}" />
 
     <!-- rules -->
 
                 basename="${ant.project.name}" />
     </target>
 
-    <!-- Package the application and sign it with a debug key.
-         This is the default target when building. It is used for debug. -->
-    <target name="debug" depends="dex, package-resources">
+    <!-- Package the application and (maybe) sign it with a debug key.
+         This requires the property sign.package to be set to true or false. -->
+    <target name="package">
         <apkbuilder
                 outfolder="${out-folder}"
                 basename="${ant.project.name}"
-                signed="true"
-                verbose="false">
+                signed="${sign.package}"
+                verbose="true">
             <file path="${intermediate-dex}" />
             <sourcefolder path="${source-folder}" />
             <jarfolder path="${external-libs-folder}" />
         </apkbuilder>
     </target>
 
-    <!-- Package the application without signing it.
-         This allows for the application to be signed later with an official publishing key. -->
-    <target name="release" depends="dex, package-resources">
-        <apkbuilder
-                outfolder="${out-folder}"
-                basename="${ant.project.name}"
-                signed="false"
-                verbose="false">
-            <file path="${intermediate-dex}" />
-            <sourcefolder path="${source-folder}" />
-            <jarfolder path="${external-libs-folder}" />
-            <nativefolder path="${native-libs-folder}" />
-        </apkbuilder>
-        <echo>All generated packages need to be signed with jarsigner before they are published.</echo>
+    <target name="no-sign">
+       <property name="sign.package" value="false" />
+    </target>
+
+    <target name="debug-sign">
+       <property name="sign.package" value="true" />
+    </target>
+
+    <target name="debug" depends="dex, package-resources, debug-sign, package">
+        <exec executable="${zipalign}" failonerror="true">
+            <arg value="-f" />
+            <arg value="4" />
+            <arg path="${out-debug-unaligned-package}" />
+            <arg path="${out-debug-package}" />
+        </exec>
+        <echo>Debug Package: ${out-debug-package}</echo>
+    </target>
+
+    <target name="release-package" depends="dex, package-resources, no-sign, package">
+    </target>
+
+    <target name="release.check">
+        <condition property="release.sign">
+            <and>
+                <isset property="key.store" />
+                <isset property="key.alias" />
+            </and>
+        </condition>
+    </target>
+    <target name="release.nosign" depends="release.check" unless="release.sign">
+        <echo>No key.store and key.alias properties found in build.properties.</echo>
+        <echo>Please sign ${out-unsigned-package} manually</echo>
+        <echo>and run zipalign from the Android SDK tools.</echo>
+    </target>
+
+    <target name="release" depends="release-package, release.nosign" if="release.sign">
+        <!-- get passwords -->
+        <input
+                message="Please enter keystore password (store:${key.store}):"
+                addproperty="key.store.password"/>
+        <input
+                message="Please enter password for alias '${key.alias}':"
+                addproperty="key.alias.password"/>
+        <!-- sign the APK -->
+        <signjar
+                jar="${out-unsigned-package}"
+                signedjar="${out-unaligned-package}"
+                keystore="${key.store}"
+                storepass="${key.store.password}"
+                alias="${key.alias}"
+                keypass="${key.alias.password}"/>
+        <!-- zip align the APK -->
+        <exec executable="${zipalign}" failonerror="true">
+            <arg value="-f" />
+            <arg value="4" />
+            <arg path="${out-unaligned-package}" />
+            <arg path="${out-release-package}" />
+        </exec>
+        <echo>Release Package: ${out-release-package}</echo>
     </target>
 
     <!-- Install the package on the default emulator -->
index d71491c..f2b73c0 100644 (file)
@@ -85,9 +85,17 @@ public final class ProjectProperties {
            "# This file must be checked in Version Control Systems, as it is\n" +
            "# integral to the build system of your project.\n" +
            "\n" +
+           "# This file is only used by the Ant script.\n" +
+           "\n" +
            "# You can use this to override default values such as\n" +
            "#  'source-folder' for the location of your java source folder and\n" +
            "#  'out-folder' for the location of your output folder.\n" +
+           "\n" +
+           "# You can also use it define how the release builds are signed by declaring\n" +
+           "# the following properties:\n" +
+           "#  'key.store' for the location of your keystore and\n" +
+           "#  'key.alias' for the name of the key to use.\n" +
+           "# The password will be asked during the build when you use the 'release' target.\n" +
            "\n";
 
     private final static Map<String, String> COMMENT_MAP = new HashMap<String, String>();