***Update: Use package.blackberry OR install.blackberry when running the ANT task, using both will overwrite the BAR file and remove signing. Verify your BAR is signed by renaming it from app.bar to app.zip, extract and ensure you have META-INF/AUTHOR.EC and META-INF/RDK.EC included in the zip.***

Create your market ready AIR apps for iOS, Android and the BlackBerry PlayBook in a single click using the same code. This ANT task compiles, signs and pushes out to attached devices (iOS requires dragging into iTunes). All of the signed apps created with this ANT task can be published to the market.

Overview:
The AIR 2.6 SDK is great but doesn’t have full Flash Builder support yet. This ANT task can be used in Flash Builder, Flash Develop, FDT or even the command line. Using Flash Develop, you can create apps for all devices without paying for expensive software!

Pre-requisites:
You will need to install Flash Builder Burrito, the BlackBerry PlayBook SDK, the AIR 2.6 SDK and acquire signing keys for all three devices. If using Flash Develop, you will need to follow some additional steps for ANT integration. You’ll also want to download the base project from Google Code: http://code.google.com/p/air-mobile-tools/

Video Tutorial:

Wiki:
The wiki on Google code contains more information on getting started with this base project: http://code.google.com/p/air-mobile-tools/wiki/BaseMobileActionScriptProject

ANT Task:

<?xml version="1.0" encoding="UTF-8"?>
<!--
MIT License:
Copyright (c) 2010 Christopher Black

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Resources:

http://www.terrenceryan.com/blog/post.cfm/using-ant-to-package-the-same-air-app-to-multiple-devices


http://technophi.com/2011/03/08/using-ant-to-compile-a-flex-mobile-project-for-ios/


http://www.adobe.com/devnet/flex/articles/flex_ant_pt1.html


http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-5d0f4f25128cc9cd0cb-7ffb.html

-->
<project name="Box2D" default="main" basedir="."><property name="environment" value="local" /><property file="settings.properties"/>

<!-- Path to the Flex task libraries. -->
<path id="flextasks.classpath">
  <fileset dir="${FLEX_HOME}/ant/lib">
    <include name="*.jar"/>
  </fileset>
</path>
<typedef resource="flexTasks.tasks" classpathref="flextasks.classpath" />

<!-- Add dependencies here (android, blackberry, apple) or uninstall.blackberry -->
<target name="main" depends="android, blackberry, apple" />
<target name="android" depends="prepPackage, package.android, install.android" />
<!-- Use package.blackberry OR install.blackberry, using both will overwrite the .bar file and remove signing. -->
<target name="blackberry" depends="prepPackage, package.blackberry" />
<target name="apple" depends="prepPackage, package.apple" />
<target name="clean">
  <echo message="Cleaning Build Space"/>
  <delete dir="${build.dir}"/>
</target>
<target name="prepPackage" depends="compile,handleDevices" />
<target name="compile" depends="clean">
  <echo message="Compiling swf"/>
  <mxmlc file="${projectFile}" output="${swfFile}" optimize="true" configname="airmobile" debug="false">
    <load-config filename="${FLEX_HOME}/frameworks/airmobile-config.xml"/>
    <source-path path-element="${FLEX_HOME}/frameworks"/>
    <static-link-runtime-shared-libraries />
    <compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
      <include name="libs/*" />
    </compiler.library-path>
    <compiler.library-path dir="${basedir}/libs" append="true">
      <include name="*" />
    </compiler.library-path>
  </mxmlc>
</target>

<!-- Create Android directory. -->
<target name="collect.android">
  <echo message="Creating device folder for Android"/>
  <mkdir dir="${build.dir}/android"/>
  <echo message="Copying SWF for Android"/>
  <copy file="${cert.dir}/androidcert.p12" todir="${build.dir}/android" />
  <copy file="${swfFile}" todir="${build.dir}/android" />
  <echo message="Copying Application Description File for Android"/>
  <copy file="${dev.dir}/${app.name}-app.xml" todir="${build.dir}/android" preservelastmodified="true" />
  <copy todir="${build.dir}/android/assets">
    <fileset dir="${dev.dir}/assets" />
  </copy>
  <echo message="Modifying application description file"/>
  <replace file="${build.dir}/android/${app.name}-app.xml">
    <replacefilter token="${contentText}" value="${app.name}.swf" />
  </replace>
</target>
	
<!-- Create BlackBerry directory. -->
<target name="collect.blackberry">
  <echo message="Creating Device Folder for BlackBerry"/>
  <mkdir dir="${build.dir}/blackberry"/>
  <echo message="Copying SWF for BlackBerry"/>
  <copy file="${swfFile}" todir="${build.dir}/blackberry" />
  <copy file="${cert.dir}/${bb.cert}" todir="${build.dir}/blackberry" />
  <echo message="Copying Application Description File for BlackBerry"/>
  <copy file="${dev.dir}/${app.name}BlackBerry-app.xml" todir="${build.dir}/blackberry" preservelastmodified="true" />
  <copy file="${dev.dir}/blackberry-tablet.xml"
  	todir="${build.dir}/blackberry" preservelastmodified="true" />
  <copy todir="${build.dir}/blackberry/assets">
    <fileset dir="${dev.dir}/assets" />
  </copy>
  <echo message="Modifying application description file"/>
  <replace file="${build.dir}/blackberry/${app.name}BlackBerry-app.xml">
    <replacefilter token="${contentText}" value="${app.name}.swf" />
  </replace>
</target>
	
<!-- Create Apple directory. -->
<target name="collect.apple">
  <echo message="Creating device folder for apple"/>
  <mkdir dir="${build.dir}/apple"/>
  <echo message="Copying SWF for Apple"/>
  <copy file="${swfFile}" todir="${build.dir}/apple" />
  <copy file="${cert.dir}/${apple.cert}" todir="${build.dir}/apple" />
  <copy file="${cert.dir}/${apple.provision}" todir="${build.dir}/apple" />
  <echo message="Copying Application Description File for Apple"/>
  <copy file="${dev.dir}/${app.name}Apple-app.xml" todir="${build.dir}/apple" preservelastmodified="true" />
  <copy todir="${build.dir}/apple/assets">
    <fileset dir="${dev.dir}/assets" />
  </copy>
  <echo message="Modifying Application Description File"/>
  <replace file="${build.dir}/apple/${app.name}Apple-app.xml">
    <replacefilter token="${contentText}" value="${app.name}.swf" />
  </replace>
</target>
	
<target name="handleDevices" depends="collect.android, collect.blackberry, collect.apple"/>
<target name="package.android">
  <echo message="Packaging for Android ${cert}"/>
  <exec executable="${ADT}" dir="${build.dir}/android">
    <arg value="-package"/>
    <arg line="-target apk"/>
    <arg line="-storetype pkcs12"/>
    <arg line="-keystore ${cert}" />
    <arg line="-storepass ${cert.password}" />
    <arg value="${app.name}"/>
    <arg value="${app.name}-app.xml"/>
    <arg value="${app.name}.swf"/>
    <arg line="assets" />
  </exec>
</target>
<target name="package.blackberry">
  <echo message="Packaging for BlackBerry"/>
  <exec executable="${BBPackager}" dir="${build.dir}/blackberry">
    <arg value="-package"/>
    <arg value="${app.name}.bar"/>
    <arg value="${app.name}BlackBerry-app.xml"/>
    <arg value="blackberry-tablet.xml"/>
    <arg value="${app.name}.swf"/>
    <arg line="assets" />
  </exec>
  <exec executable="${BBSigner}" dir="${build.dir}/blackberry"> 
  	<arg value="-verbose"/>
  	<arg line="-cskpass ${bb.cert.password}"/>
  	<arg line="-keystore ${bb.cert}"/>
  	<arg line="-storepass ${bb.store.password}"/>
  	<arg value="${app.name}.bar"/>
  	<arg value="RDK" />
  </exec>
  <exec executable="${BBSigner}" dir="${build.dir}/blackberry"> 
	<arg line="-keystore ${bb.cert}"/>
	<arg line="-storepass ${bb.store.password}"/>
	<arg value="${app.name}.bar"/>
	<arg value="author" />
  </exec>
</target>
<target name="package.apple">
  <exec executable="${ADT}" dir="${build.dir}/apple">
    <arg line="-package -target '${apple.target}'" />
    <arg line="-provisioning-profile '${apple.provision}'" />
    <arg line="-storetype pkcs12" />
    <arg line="-keystore '${apple.cert}'" />
    <arg line="-storepass '${apple.cert.password}'" />
    <arg line="'${app.name}.ipa'" />
    <arg line="'${apple.descriptor}'" />
    <arg line="'${app.name}.swf'" />
    <arg line="assets" />
  </exec>
</target>
<target name="install.android">
	  <echo message="Uninstalling attached Android Device"/>
	  <exec executable="${ADT}">
	    <arg line="-uninstallApp"/>
	    <arg line="-platform android"/>
	  	<arg line="-appid '${app.name}'"/>
	  </exec>
  <echo message="Installing onto attached Android Device"/>
  <exec executable="${ADT}">
    <arg line="-installApp"/>
    <arg line="-platform android"/>
    <arg line="-package '${build.dir}/android/${app.name}.apk'"/>
  </exec>
  <echo message="Launching on attached Android Device"/>
  <exec executable="${ADT}">
    <arg line="-launchApp"/>
    <arg line="-platform android"/>
    <arg line="-appid '${app.name}'"/>
  </exec>
</target>
<target name="uninstall.blackberry">
  <echo message="Uninstalling from Blackberry VM"/>
  <exec executable="${BBDeploy}" dir="${build.dir}/blackberry">
    <arg value="-uninstallApp"/>
    <arg value="-device"/>
    <arg value="${bb.ip}"/>
    <arg value="-password"/>
    <arg value="${bb.password}"/>
    <arg value="-package"/>
    <arg value="${app.name}.bar"/>
  </exec>
</target>
<target name="install.blackberry">
  <echo message="Installing onto Blackberry VM"/>
  <exec executable="${BBPackager}" dir="${build.dir}/blackberry">
    <arg value="-package"/>
    <arg value="${app.name}.bar"/>
    <arg value="-installApp"/>
    <arg value="-launchApp"/>
    <arg value="${app.name}BlackBerry-app.xml"/>
    <arg value="blackberry-tablet.xml"/>
    <arg value="${app.name}.swf"/>
    <arg value="-device"/>
    <arg value="${bb.ip}"/>
    <arg value="-password"/>
    <arg value="${bb.password}"/>
    <arg value="assets"/>
  </exec>
</target>
</project>
flex.path = C:/Program Files (x86)/Adobe/Flash Builder Burrito/Adobe Flash Builder Burrito/sdks
flex.sdkVersion= 4.5.0_air
flex.sdkPath= ${flex.path}/${flex.sdkVersion}
FLEX_HOME= ${flex.sdkPath}
BB_HOME = ${flex.path}/blackberry-tablet-sdk-0.9.4
contentText = [This value will be overwritten by Flash Builder in the output app.xml]

ADB = C:/Users/Chris/Desktop/Froyo/android-sdk-windows/platform-tools/adb.exe
ADT = ${flex.sdkPath}/bin/adt.bat
adt.path = ${flex.sdkPath}/bin/
IPHONE_PACKAGER = adt

BBDeploy = ${flex.path}/blackberry-tablet-sdk-0.9.4/bin/blackberry-deploy.bat
BBPackager = ${flex.path}/blackberry-tablet-sdk-0.9.4/bin/blackberry-airpackager.bat
BBSigner = ${flex.path}/blackberry-tablet-sdk-0.9.4/bin/blackberry-signer.bat
bb.ip = [PLAYBOOK_IP]
bb.password = [YOUR_PASSWORD]

## Directories
build.dir = bin-release
dev.dir = ${basedir}/src
cert.dir = ${basedir}/certs
app.name = BaseMobileActionScriptProject

## mxml or as
app.type = as

## Apple cert info: ipa-test | ipa-debug | ipa-app-store | ipa-ad-hoc
apple.target = ipa-ad-hoc
apple.cert = [APPLE_CERT_NAME].p12
apple.cert.password = [CERT_PASSWORD]
apple.provision = [PROVISION_NAME].mobileprovision
apple.descriptor = ${dev.dir}/${app.name}Apple-app.xml

## Android cert info
cert = [ANDROID_CERT_NAME].p12
cert.password = [YOUR_PASSWORD]

## PlayBook cert info
bb.cert = [BB_CERT_NAME].p12
bb.cert.password = [YOUR_PASSWORD]
bb.store.password = [YOUR_STORE_PASSWORD]
bb.descriptor = ${dev.dir}/${app.name}BlackBerry-app.xml

## General
swfFile=${build.dir}/${app.name}.swf
projectFile=${dev.dir}/${app.name}.${app.type}

Resources:
http://www.terrenceryan.com/blog/post.cfm/using-ant-to-package-the-same-air-app-to-multiple-devices
http://technophi.com/2011/03/08/using-ant-to-compile-a-flex-mobile-project-for-ios/
http://www.adobe.com/devnet/flex/articles/flex_ant_pt1.html
http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-5d0f4f25128cc9cd0cb-7ffb.html

14 thoughts on “iOS, Android and BlackBerry in a Single Click with ANT

  1. Very nice!, thanks for this, already have ant script for publishing to Android and was about to write one for iOS and now I don’t have to ! :)

  2. This looks great – thanks! Instructions seem clear too, I’m going to give it a go in a bit :)

  3. Hey Chris,

    This has saved me lots of time :)

    I noticed that the Android Certifcate name is hardcoded in the “package.android” target:
    <copy file="${cert.dir}/androidcert.p12" …

    Also the path to ADB in your properties is on your desktop, but it is available in the AIR and Blackberry SDKs.

  4. Nice article.

    I tried to run your “BaseMobileActionScriptProject”, but my Burrito gave me this error when imported:

    Unknown Flex SDK: “Flex 4.5 AIR 2.6″
    Resource(BaseMobileActionScriptProject)

  5. You’ll need to make a copy of your Flex 4.5 SDK folder and add in AIR 2.6. Add that new SDK location into Flash Builder Burrito and you should be good to go. The new version of Flash Builder will ship with the latest version of AIR making this process much easier.

  6. Thanks for posting the video. It’s possible that Flex builder isn’t updating the properties file correctly. You could try creating a new project and copying the files (minus the FB specific settings) into that project. The ANT script should actually still work regardless if the settings.properties file has been filled out correctly.

  7. Thanks Nilsh. I’m working on some updates to this script to improve device testing for the PlayBook (now that I actually have a device) and will include your feedback as well.

Comments are closed.