When you start a new project, the first task is to define the output. For example, is your application going to run in browsers, iOS, Android, or Blackberry devices or all four? This would be your output device list.
A build script or "build scripts" can define your output device list.
Apache ANT is a cross platform open source build script manager and free to download. It allows us to define repeatable steps which results in less mistakes for each release. It is available at ant.apache.org/. MAC computers with OSX already have ANT pre-installed on their computer.
Note: You need to install ANT extensions for FTP or email support.
Start by building three main deployment "build scripts" for:
- Internal deployment - testing server deployment.
- Beta Release - public server deployment testing.
- Release Build - public release.
Inside ANT, The build tasks (called targets) are defined by the project (top element).
Example: <target name="BuildAndPackage1" >
The default target (or, the entire goal of the project) is defined inside the project as the default attribute.
<project name="Build Internal" default="BuildAndPackage10" >
The default target is usually the last target. Since each target has a dependency, the tasks (targets) run in order, backwards until the final (default) is ran.
The end result is all 10 targets running in order from 1 to 10.
Each of the 10 targets have a simple task.
In this example, I update, compile and deploy a web, iPhone and Android version of the app using the internal server for data.
- Delete temp folder used in previous build then create directories for building into.
- Copy default values used inside application to use internal server(s) for data.
- Compile Model data file into an .swc. This will be explained later.
- Update Version files.
- Compile css files into .swc files. These contain the style libraries.
- Compile the Main application into SWF file.
- Package iPhone app file.
- Package Android app file.
- FTP files to server.
- Send out email with version deployed.
Here is the source for the internal build:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Build Internal" default="BuildAndPackage10" >
<target name="BuildAndPackage1" >
<ant antfile="Build_MakeDirectories.xml" target="BuildDirectories" inheritall="false" />
</target>
<target name="BuildAndPackage2" depends="BuildAndPackage1" >
<!-- USE TESTING SERVER DATABASE FOR INTERNAL BUILDS -->
<ant antfile="Build_InternalBuildApplicationConfig.xml" target="CopyTesingServerForBuild" inheritall="false" />
</target>
<target name="BuildAndPackage3" depends="BuildAndPackage2" >
<ant antfile="Build_ModelSWC.xml" target="CompileModel" inheritall="false" />
</target>
<target name="BuildAndPackage4" depends="BuildAndPackage3" >
<ant antfile="Build_UpdateVersion.xml" target="UpdateVersionBeta" inheritall="false" />
</target>
<target name="BuildAndPackage5" depends="BuildAndPackage4" >
<ant antfile="Build_CSSFiles.xml" target="CompileCSS" inheritall="false" />
</target>
<target name="BuildAndPackage6" depends="BuildAndPackage5" >
<ant antfile="Build_CompileSWF.xml" target="CompileSWF" inheritall="false" />
</target>
<target name="BuildAndPackage7" depends="BuildAndPackage6" >
<ant antfile="Build_PackageIPA.xml" target="CompileIPA" inheritall="false" />
</target>
<target name="BuildAndPackage8" depends="BuildAndPackage7" >
<ant antfile="Build_PackageAPK.xml" target="CompileAPK" inheritall="false" />
</target>
<target name="BuildAndPackage9" depends="BuildAndPackage8"
<ant antfile="Build_FTPFilesToServer.xml" target="UploadInternalRelease" inheritall="false" />
</target>
<target name="BuildAndPackage10" depends="BuildAndPackage9" >
<ant antfile="Build_EmailComplete.xml" target="EmailCompleteInternal" inheritall="false" />
<echo>Internal built and uploaded.. version ${Version.MajorNumber}.${Version.BetaNumber}.${build.number} </echo>
</target>
</project>
Here is the source for the beta build:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Build beta" default="BuildAndPackage10" >
<target name="BuildAndPackage1" >
<ant antfile="Build_MakeDirectories.xml" target="BuildDirectories" inheritall="false" />
</target>
<target name="BuildAndPackage2" depends="BuildAndPackage1" >
<!-- USE RELEASE SERVER DATABASE FOR BETA -->
<ant antfile="Build_InternalBuildApplicationConfig.xml" target="CopyReleaseServerForBuild" inheritall="false" />
</target>
<target name="BuildAndPackage3" depends="BuildAndPackage2" >
<ant antfile="Build_ModelSWC.xml" target="CompileModel" inheritall="false" />
</target>
<target name="BuildAndPackage4" depends="BuildAndPackage3" >
<ant antfile="Build_UpdateVersion.xml" target="UpdateVersionBeta" inheritall="false" />
</target>
<target name="BuildAndPackage5" depends="BuildAndPackage4" >
<ant antfile="Build_CSSFiles.xml" target="CompileCSS" inheritall="false" />
</target>
<target name="BuildAndPackage6" depends="BuildAndPackage5" >
<ant antfile="Build_CompileSWF.xml" target="CompileSWF" inheritall="false" />
</target>
<target name="BuildAndPackage7" depends="BuildAndPackage6" >
<ant antfile="Build_PackageIPA.xml" target="CompileIPA" inheritall="false" />
</target>
<target name="BuildAndPackage8" depends="BuildAndPackage7" >
<ant antfile="Build_PackageAPK.xml" target="CompileAPK" inheritall="false" />
</target>
<target name="BuildAndPackage9" depends="BuildAndPackage8"
<ant antfile="Build_FTPFilesToServer.xml" target="UploadInternalRelease" inheritall="false" />
</target>
<target name="BuildAndPackage10" depends="BuildAndPackage9" >
<ant antfile="Build_EmailComplete.xml" target="EmailCompleteInternal" inheritall="false" />
<echo>Internal built and uploaded.. version ${Version.MajorNumber}.${Version.BetaNumber}.${build.number} </echo>
</target>
</project>
Here is the source for the release build:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Build release" default="BuildAndPackage10" >
<target name="BuildAndPackage1" >
<ant antfile="Build_MakeDirectories.xml" target="BuildDirectories" inheritall="false" />
</target>
<target name="BuildAndPackage2" depends="BuildAndPackage1" >
<!-- USE RELEASE SERVER DATABASE FOR RELEASE -->
<ant antfile="Build_InternalBuildApplicationConfig.xml" target="CopyReleaseServerForBuild" inheritall="false" />
</target>
<target name="BuildAndPackage3" depends="BuildAndPackage2" >
<ant antfile="Build_ModelSWC.xml" target="CompileModel" inheritall="false" />
</target>
<target name="BuildAndPackage4" depends="BuildAndPackage3" >
<ant antfile="Build_UpdateVersion.xml" target="UpdateVersionBeta" inheritall="false" />
</target>
<target name="BuildAndPackage5" depends="BuildAndPackage4" >
<ant antfile="Build_CSSFiles.xml" target="CompileCSS" inheritall="false" />
</target>
<target name="BuildAndPackage6" depends="BuildAndPackage5" >
<ant antfile="Build_CompileSWF.xml" target="CompileSWF" inheritall="false" />
</target>
<target name="BuildAndPackage7" depends="BuildAndPackage6" >
<ant antfile="Build_PackageIPA.xml" target="CompileIPA" inheritall="false" />
</target>
<target name="BuildAndPackage8" depends="BuildAndPackage7" >
<ant antfile="Build_PackageAPK.xml" target="CompileAPK" inheritall="false" />
</target>
<target name="BuildAndPackage9" depends="BuildAndPackage8"
<ant antfile="Build_FTPFilesToServer.xml" target="UploadInternalRelease" inheritall="false" />
</target>
<target name="BuildAndPackage10" depends="BuildAndPackage9" >
<ant antfile="Build_EmailComplete.xml" target="EmailCompleteInternal" inheritall="false" />
<echo>Internal built and uploaded.. version ${Version.MajorNumber}.${Version.BetaNumber}.${build.number} </echo>
</target>
</project>
Here is the source for the make directories:
<project name="BuildDirectories" default="BuildDirectories" >
<!-- 0. Setup properties -->
<property file="build.properties_version" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<property name="build_dir" location="${app_root_dir}/build" />
<property name="debug_dir" location="${app_root_dir}/build/internal" />
<property name="publish_dir" location="${app_root_dir}/build/public" />
<property name="assets_dir" location="${class_path}/${assets_dir_name}" />
<property name="output_loc" location="${publish_dir}/${swf_file}" />
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<!-- 1.0 Clean and create directories. -->
<!-- Clean existing directories -->
<target name="CleanupDirectories" description="clean up">
<delete dir="${temp_dir}" />
</target>
<!-- Create required directories -->
<target name="BuildDirectories" depends="CleanupDirectories">
<mkdir dir="${build_dir}" />
<mkdir dir="${temp_dir}" />
<mkdir dir="${debug_dir}" />
<mkdir dir="${publish_dir}" />
</target>
</project>
Here is the source for the build.properties:
Replace items identified by [], for example [project]. So, in my case,
[developer name] would be replaced with John Molinari.
######################################
## Project information
######################################
author=[developer name]
project.owner=[company]
project.owner.url=http\://www.[website].com
project.name=[project]
project.fullname=[project]
application.name=[project]
app_name=[project]
app_type=mxml
# Where flex is installed:
FLEX_HOME=C\:/Program Files/Adobe/Adobe Flash Builder 4.7 (64 Bit)/sdks/4.6.0
LOCALE=en_US
######################################
## tools
######################################
### FlexTask
FLEX_TASKS=${FLEX_HOME}/ant/lib/flexTasks.jar
ADT=${FLEX_HOME}/lib/adt.jar
PFI=${FLEX_HOME}/lib/pfi.jar
ADL=${FLEX_HOME}/bin/adl
AIR_GLOBAL=${FLEX_HOME}/frameworks/libs/air/airglobal.swc
######################################
## Properties
######################################
app_root_dir=.
app_descriptor=${class_path}/${app_name}-app.xml
MOBILE_DIR=W\:/[productname]/htdocs/[project]
MODEL_DIR=W\:/[productname]/htdocs/[project]
MODEL_PLUGINS_DIR=C\:/Program Files/Adobe/Adobe Flash Builder 4.7 (64 Bit)/eclipse/plugins/com.adobe.flexbuilder.project_4.7.0.349722
SOFTWARE_FOLDER=W\:/[website].com/public_html/software
class_path=${MOBILE_DIR}/src
lib_path=${MOBILE_DIR}/libs
view_path=${MOBILE_DIR}/src/com/[project] /view
enum_path=${MODEL_DIR}/src/com/[project] /model/enum
### File names
swf_file=${app_name}.swf
air_file=${app_name}.air
ipa_file=${app_name}.ipa
apk_file=${app_name}.apk
### iOS Configuration
ios_provisioning=${cert_loc}/Provisional.mobileprovision
ios_pass=[enter password here]
android_keystore=${cert_loc}/[name] Android.p12
ios_keystore=${cert_loc}/[name].p12
cert_loc=W\:/Certificates
assets_dir_name=${class_path}/icons
main_class=${class_path}/${app_name}.${app_type}
splash_path=${class_path}/Default.png
### FTP [enter ftp address]
ftp-server= [enter ftp address]
ftp-userid= [enter ftp login name]
ftp-password=[enter ftp password]
ftp-remotedir=public_html/software
Here is the source for the CopyApplicationConfig:
<project name="CopyApplicationConfig" default="CopyTesingServerForBuild" >
<!-- 0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="MASTER_build.properties" />
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<target name="CopyReleaseServerForBuild" >
<copy file="${enum_path}/ApplicationValues_LiveServer.as" tofile="${enum_path}/ApplicationValues.as" overwrite="true" />
<replaceregexp file="${enum_path}/ApplicationValues.as"
match="ApplicationValues_LiveServer"
replace="ApplicationValues"
byline="true"
/>
</target>
<target name="CopyTesingServerForBuild" >
<copy file="${enum_path}/ApplicationValues_TestingServer.as" tofile="${enum_path}/ApplicationValues.as" overwrite="true" />
<replaceregexp file="${enum_path}/ApplicationValues.as"
match="ApplicationValues_TestingServer"
replace="ApplicationValues"
byline="true"
/>
</target>
</project>
Here is the source for the UpdateVersion:
<project name="UpdateVersion" default="UpdateVersionInternal" >
<!-- 0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="build.properties_Versions" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<!-- Use the Flex ANT tasks for easier compilation - DONE -->
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<!-- build.number will increment each time it is ran.. use it to add to end of file using wildcard.. -->
<target name="UpdateVersionInternal" depends="UpdateProperties" >
<!-- store into new file via wildcard. -->
<!-- increment Build number -->
<buildnumber file="build.properties_NEW" />
<echo>Build Number: ${build.number} </echo>
<echo>Major Version ${Version.MajorNumber} </echo>
<echo>Beta Version ${Version.BetaNumber} </echo>
<replaceregexp file="${temp_dir}/eMEApp-app_ForBuilds.xml"
match="%%versionNumber%%"
replace="${Version.MajorNumber}.${Version.BetaNumber}.${build.number}"
byline="true"
/>
<echo>Internal Version: ${Version.MajorNumber}.${Version.BetaNumber}.${build.number} </echo>
<echo>Build: ${build.number}</echo>
</target>
<target name="UpdateVersionPublic" >
<!-- increment first, set middle and last number to 0 -->
<!-- store into new file via wildcard. -->
<!-- increment Build number -->
<buildnumber file="build.properties_NEW" />
<echo>Build Number: ${build.number} </echo>
<!-- CHANG PROPERTIES FILE VALUES -->
<propertyfile file="build.properties_Versions" >
<entry key="Version.MajorNumber" operation="+" type="int" value="1" />
</propertyfile>
<echo>Major Version ${Version.MajorNumber} </echo>
<echo>Beta Version ${Version.BetaNumber} </echo>
<replaceregexp file="${temp_dir}/eMEApp-app_ForBuilds.xml"
match="%%versionNumber%%"
replace="${Version.MajorNumber}.0.0"
byline="true"
/>
<echo>Public Version: ${Version.MajorNumber}.0.0 </echo>
<echo>Build: ${build.number}</echo>
</target>
<target name="UpdateVersionBeta" >
<!-- increment middle number, set last to 0 -->
<!-- store into new file via wildcard. -->
<!-- increment Build number -->
<buildnumber file="build.properties_NEW" />
<echo>Build Number: ${build.number} </echo>
<propertyfile file="build.properties_Versions" >
<entry key="Version.BetaNumber" operation="+" type="int" value="1" />
</propertyfile>
<echo>Major Version ${Version.MajorNumber} </echo>
<echo>Beta Version ${Version.BetaNumber} </echo>
<replaceregexp file="${temp_dir}/eMEApp-app_ForBuilds.xml"
match="%%versionNumber%%"
replace="${Version.MajorNumber}.${Version.BetaNumber}.0"
byline="true"
/>
<echo>Beta Version: ${Version.MajorNumber}.${Version.BetaNumber}.0 </echo>
<echo>Build: ${build.number}</echo>
</target>
</project>
Here is the source for the CompileCSS:
<project name="CompileCSS" default="CompileCSS" >
<!--0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<property name="build_dir" location="${app_root_dir}/build" />
<property name="debug_dir" location="${app_root_dir}/build/internal" />
<property name="publish_dir" location="${app_root_dir}/build/public" />
<property name="assets_dir" location="${class_path}/${assets_dir_name}" />
<property name="output_loc" location="${publish_dir}/${swf_file}" />
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<!-- 2.0 Compile css files into swc files. (libraries) - -->
<target name="CompileCSS" >
<compc output="${temp_dir}/AppNameTheme.swc" defaults-css-url="./default_components.css" >
<include-file name="default_components.css" path="./default_components.css" />
<include-file name="default_fonts.css" path="./default_fonts.css" />
<include-file name="default_colors.css" path="./default_colors.css" />
</compc>
</target>
</project>
Here is the source for the CompileSWF:
<project name="CompileSWF" default="CompileSWF" >
<!-- 0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<property name="build_dir" location="${app_root_dir}/build" />
<property name="debug_dir" location="${app_root_dir}/build/internal" />
<property name="publish_dir" location="${app_root_dir}/build/public" />
<property name="assets_dir" location="${class_path}/${assets_dir_name}" />
<property name="output_loc" location="${temp_dir}/${swf_file}" />
<!-- Use the Flex ANT tasks for easier compilation - DONE -->
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<!-- 2.0 Compile css files into swc files. (libraries) - -->
<target name="CompileSWF" >
<mxmlc
file="${main_class}"
output="${output_loc}"
locale="${LOCALE}"
static-rsls="false"
accessible="false"
configname="airmobile"
debug="${debug_mode}"
failonerror="true"
fork="true"
maxmemory="1024m">
<source-path path-element="${class_path}"/>
<compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
<include name="libs/*" />
</compiler.library-path>
<theme dir="${temp_dir}" append="true" >
<include name="AppnameTheme.swc" />
</theme>
<!-- <defaults-css-files >
<include filename="default_fonts.css" />
</defaults-css-files>
<library-path dir="${MOBILE_DIR}/src" includes="*" append="true" /> -->
<library-path dir="${temp_dir}" includes="AppName_Model.swc" append="true" />
<library-path file="${FLEX_HOME}/frameworks/locale/${LOCALE}" append="true"/>
<library-path dir="${lib_path}" includes="*.swc" append="true"/>
<external-library-path file="${AIR_GLOBAL}" append="true"/>
</mxmlc>
</target>
</project>
Here is the source for the CompileIPA:
<project name="CompileIPA" default="MoveToPublic" >
<!-- 0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<property name="build_dir" location="${app_root_dir}/build" />
<property name="debug_dir" location="${app_root_dir}/build/internal" />
<property name="publish_dir" location="${app_root_dir}/build/public" />
<property name="assets_dir" location="${class_path}/${assets_dir_name}" />
<property name="output_loc" location="${publish_dir}/${swf_file}" />
<!-- Use the Flex ANT tasks for easier compilation - DONE -->
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<property name="app_descriptor_forbuilding" location="${temp_dir}/${app_name}-app_ForBuilds.xml"/>
<target name="MoveToPublic" depends="CompileIPA">
<move file="${temp_dir}/${ipa_file}" tofile="${publish_dir}/${ipa_file}"/>
</target>
<!-- Package the application to an ipa file & save it in the publish directory -->
<target name="CompileIPA" >
<echo>IPA Start - BE PATIENT!!!! - THIS CAN TAKE 10 TO 15 MINUTES TO GENERATE IPA (IPHONE APP)</echo>
<java jar="${ADT}" fork="true" failonerror="true">
<arg value="-package"/>
<arg value="-target"/>
<arg value="ipa-test"/>
<arg value="-provisioning-profile"/>
<arg value="${ios_provisioning}"/>
<arg value="-storetype"/>
<arg value="pkcs12"/>
<arg value="-keystore"/>
<arg value="${ios_keystore}"/>
<arg value="-storepass"/>
<arg value="${ios_pass}"/>
<arg value="${temp_dir}/${ipa_file}"/>
<arg value="${app_descriptor_forbuilding}"/>
<arg value="-C" />
<arg value="${temp_dir}"/>
<arg value="${swf_file}"/>
<!-- Include icons -->
<arg value="-C" />
<arg value="${class_path}"/>
<arg value="/icons" />
</java>
<echo>IPA Built</echo>
</target>
</project>
Here is the source for the CompileAPK:
<project name="CompileAPK" default="CompileAPK" >
<!-- 0. Setup properties - DONE -->
<property file="build.properties_NEW" />
<property file="MASTER_build.properties" />
<property name="temp_dir" location="${app_root_dir}/build/temp" />
<property name="build_dir" location="${app_root_dir}/build" />
<property name="debug_dir" location="${app_root_dir}/build/internal" />
<property name="publish_dir" location="${app_root_dir}/build/public" />
<property name="assets_dir" location="${class_path}/${assets_dir_name}" />
<property name="output_loc" location="${publish_dir}/${swf_file}" />
<!-- Use the Flex ANT tasks for easier compilation - DONE -->
<taskdef name="mxmlc" classname="flex.ant.MxmlcTask" classpath="${FLEX_TASKS}"/>
<taskdef name="compc" classname="flex.ant.CompcTask" classpath="${FLEX_TASKS}"/>
<property name="app_descriptor_forbuilding" location="${temp_dir}/${app_name}-app_ForBuilds.xml"/>
<!-- Package the application to an ipa file & save it in the publish directory -->
<target name="CompileAPK" >
<echo>APK Start</echo>
<java jar="${ADT}" fork="true" failonerror="true">
<arg value="-package"/>
<arg value="-target"/>
<arg value="apk"/>
<arg value="-storetype"/>
<arg value="pkcs12"/>
<arg value="-keystore"/>
<arg value="${android_keystore}"/>
<arg value="-storepass"/>
<arg value="${ios_pass}"/>
<arg value="${temp_dir}/${apk_file}"/>
<arg value="${app_descriptor_forbuilding}"/>
<arg value="-C" />
<arg value="${temp_dir}"/>
<arg value="${swf_file}"/>
<!-- Include icons -->
<arg value="-C" />
<arg value="${class_path}"/>
<arg value="/icons" />
</java>
<echo>APK END</echo>
</target>
</project>
In future blogs I will go over the details of writing Actionscript and MXML. I will also explain the details of a Model, View, Controller (MVC) system and how you should use it in your development.
PREVIOUS POST