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;
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,
@Override
public void execute() throws BuildException {
- Project taskProject = getProject();
+ Project antProject = getProject();
ApkBuilderImpl apkBuilder = new ApkBuilderImpl();
apkBuilder.setVerbose(mVerbose);
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);
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) {
* 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.
}
if (mSigned) {
- filename = filename + "-debug.apk";
+ filename = filename + "-debug-unaligned.apk";
} else {
filename = filename + "-unsigned.apk";
}
}
}
+ // 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);
</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 -->
"# 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>();