Automatic ANE packaging

Opt In Image
Early bird offer on the ANE eBooks

 

Buy any Easy Native Extensions 2nd Edition package and get our $99 iOS + Android ANE Template completely free before the end of June 2015.

 

 

  • step-by-step guide to making your iOS extension in under an hour
  • library for data conversion between ActionScript and native code
  • tutorials
  • infographics
  • code included

Let me ask you a question. Let’s say you’ve written the code for your AIR Native Extension, native library, AIR library and all that. How many steps does it take to build and package this in an .ANE file?

Let’s count:

  1. Build your native library or libraries: one per platform that your ANE supports.
  2. Build your AIR library.
  3. If your ANE needs to support the AIR Simulator, build your default implementation.
  4. Extract library.swf from your AIR library:
    • make a copy of your AIR library’s SWF file;
    • rename that to .ZIP;
    • unzip it;
    • keep library.swf that came out of the .ZIP;
    • delete the .ZIP and catalog.xml that came out of the .ZIP.
  5. Repeat step 4 for your default implementation.
  6. Copy all ANE ingredients to the same folder.
  7. Run Adobe’s ADT tool on the command line to package all of the above into an .ANE file.

I’m known for passionately hating any build process that involves more than one mouse click… So I say let’s scrap all that and replace it with clicking Build Project in Flash Builder.

Want to see a tutorial for doing steps 4, 6 and 7 by hand? Check out Recipe for packaging an ANE.

In this article we’ll build a template build script that you can customize and use to package any of your ANEs. Let’s get started.

1. Create a build script file

We will be using an Ant script, which can be nicely integrated with Flash Builder and other Eclipse-based IDEs. 

If you are new to Ant, here is a gentle introduction to how it works: 7 things you need to know about Ant scripts.

1. 1. Add a folder to the root of the AIR Library project for your native extension and call it build_scripts. It’s actually OK to have space in the name and call the folder ‘build scripts’, but let’s keep things simple.

1.2. Inside build_scripts create a new file and call it local.properties. Here you’ll define the paths to Adobe’s compc and adt tools. compc is the compiler that will build your AIR library and adt is the tool that you’ll use for packaging it into an ANE. Change the paths below to match where things are on your machine:

1.3. Add another file and call it build.properties. This file will contain parameters that are specific to your project. Having the project-specific stuff separate from the actual build script means you can reuse the build script in all of your ANE projects by replicating and customizing build.properties.

Let’s start the file with a couple of helpful comments. We’ll add some meat to that later:

1.4. In the same folder add a new XML, called build.xml, and have it import the two .properties files. In this file we will put together the Ant script that will do a clean build of your ANE and package it. Start with the following shell:

<?xml version=“1.0” encoding=“UTF-8”?>

<project name=“ANE Build Script” default=“package ane”>

    <!– Configuration files: –>
    <property file=“local.properties”/>
    <property file=“build.properties”/>

         <!– Add property definitions here –>

    <!– Add build targets here –>

</project>

In the next steps we’ll add Ant build targets and configure them.

2. Add a way of choosing between debug and release builds

When you build a native library for iOS, Mac OS or Windows, your library binary file ends up in a different folder, depending on whether you do a debug or a release build. We’ll need to be able to build the binary we want and find it, so it can be packaged with the ANE.

2.1. Add a parameter to help you kick off a debug or a release build.

Open build.properties and add the following:

2.2. Add targets for checking build.debug‘s value.

Add this inside the <project> entity in build.xml, in place of the highlighted
 <!– Add build targets here –>:

<!– ************************************************************ 
         Helper targets
     ************************************************************ –>

<!– Set up the build type: debug or release –>
<target name=“set build type” depends=“check debug, check release”>
    <!–Ant doesn’t do if/else very well, so we do both checks: is ${build.debug} true? is ${build.debug} false?–>
</target> 

<target name=“check debug” if=“${build.debug}” depends=“check release” description=“Check if ${debug} is true and if it is, set the properties below for a debug build”>
    <!– iOS.library.build.type defines the folder where our iOS library will be, depending ont the build –>
    <!– You can set up similar properties for Windows and Mac OS. You don’t need one for Android. –>
    <property name=“iOS.library.build.type” value=“Debug”/>
</target> 

<target name=“check release” unless=“${build.debug}” description=“Check if ${debug} is false and if it is, set the properties below for a release build”>
    <!– iOS.library.build.type defines the folder where our iOS library will be, depending ont the build –>
    <!– You can set up similar properties for Windows and Mac OS. You don’t need one for Android. –>
    <property name=“iOS.library.build.type” value=“Release”/>
</target>

iOS.library.build.type is a property that helps you with two things:

  • it determines whether you request a debug or a release build from Xcode;
  • it helps you find the folder in your Xcode project where the built library ends up: Debug-iphoneos/ or Release-iphoneos/.

You can add similar properties for Mac OS and Windows. On Android your native .jar lib normally ends up in the same place.

3. Add targets for building your native library

3.1. Let’s start with a target that will clean your native library project. Again, the example here is for iOS and you can extend it to include other platforms:

<!– ************************************************************ 
     Native Library Targets
     ************************************************************ –>

<!– Clean the Xcode project –>
<target name=“clean ios” depends=“set build type” description=“Clean the iOS Library”>
    <exec executable=“xcodebuild” failonerror=“true” dir=“${iOS.project.root}”>
        <arg line=clean -configuration ${iOS.library.build.type}/>
    </exec>
</target>

All this does is call Xcode’s xcodebuild tool with a command line like this:

xcodebuild -configuration Debug

Note: This relies on Xcode being in your path. It normally is. Relax. 

Note also that this target depends on the “set build type” target that we configured earlier. This means that “set build type” will be executed before “clean ios”, which will ensure that iOS.library.build.type is set to Debug or to Release.

3.2. Next, add a target that will build the native library:

<!– Build the XCode project –>

<target name=“build ios” depends=“set build type” description=“Build the iOS Library”>
    <property name=”iOS.project.builddir” value=“build”/>
        <exec executable=“xcodebuild” failonerror=“true” dir=“${iOS.project.root}”>
            <arg line=-project ${iOS.project.name}.xcodeproj
                       -target ${iOS.project.name}
                       -configuration ${iOS.library.build.type}
                       SYMROOT=${iOS.project.builddir}

            /> 
            <!– Note: the SYMROOT path is relative to {dir}. –>
        </exec>
        <copy file=“${iOS.project.buildroot}/${iOS.project.builddir}/${iOS.library.build.type}-iphoneos/${iOS.library}” todir=“${iOS.project.outputdir}” overwrite=“true”/>
</target>

You can add similar targets to build your native libraries for other platforms: set executable to the name of the compiler or tool you use for building and replace the string in <arg line/> with the command line parameters that you need to pass to that compiler or tool.

3.3. And, for convenience, add a target that will let you execute the clean and build step in one go:

<!– Rebuild the XCode project –>
<target name=“rebuild ios” depends=“clean ios,build ios” description=“Do a clean build of the XCode project”/>

3.4. Add the properties that will configure these targets:

You have probably noticed that the targets you just added use a few properties that haven’t been defined yet. Let’s add them to build.properties:

Make sure you set these to your actual project name and path.

3.5. Set up a folder where build products will be collected for the ANE packaging:

There is one property we haven’t defined yet: iOS.project.outputdir. This is where your script will copy the iOS library when it gets built, so that it’s available for the next part of the script which will package the ANE. I tend to use a temporary folder for that. The structure is the same for every project I develop, so isn’t project-specific, so let’s define this directly in our build script. Add the definitions to the top of build.xml, in place of <!– Add property definitions here –>

 <!– Building of the projects and gathering of the files for packaging an ANE  happens in a temporary folder structure, which is cleaned up at the end: –>
<property name=“tempdir” value=“../temp”/>
<property name=“iOS.project.outputdir” value=“${tempdir}/ios”/>
<property name=“temp.packagedir” value=“${tempdir}/package”/>
 

4. Add a target for building your AIR Library

Native library built, it’s the AIR library’s turn.

4.1. The build swc target will build an AIR library that you point it to by calling Adobe’s compc compiler.

 <!– ************************************************************
      Adobe AIR Library Generic Targets
     ************************************************************ –>

<!– Generic target: it builds the AIR library that {library.name} and {library.root} point to. –>
<target name=“build swc” description=“Build an AIR library SWC file”>
    <fileset dir=“${library.root}/src” casesensitive=“yes” id=“classfiles”>
        <include name=“**/*.as”/>
    </fileset>
    <pathconvert property=“classlist” refid=“classfiles” pathsep=” “ dirsep=“.”>
        <regexpmapper from=“.*src.(.*)\.as” to=”\1″/>
    </pathconvert>
    <exec executable=“${COMPC}” failonerror=“true”>
        <arg line=“+configname=airmobile 
                   -source-path ${library.root}/src
                   -output ${library.outputdir}/${library.name}.swc
                   -include-classes ${classlist}

        />
    </exec>
</target>

 
In most of your projects you will probably want to build two AIR libraries: a SWC that takes care of calling native code and a default SWC with simulator support. I bet that you love code repetition as much as I do… which is to say about as much as a dentist appointment. So, instead of having to make the same target for each SWC you want to build, you are going to add smaller targets that just configure and execute this one (steps 4.3. and 4.4.). 

4.2. Add another generic target to extract library.swf from a given SWC file. See Recipe for packaging an ANE if you want a reminder for why we do this.

 <!– This is a generic target, which works with the AIR library that {library.name} is set to. –>
<target name=“extract swf library” depends=“build swc” description=“Extract library.swf from the SWC file”>
    <property name=“library.extractdir” value=“${library.outputdir}/content”/>
    <mkdir dir=“${library.extractdir}”/>
    <unzip src=“${library.outputdir}/${library.name}.swc” dest=“${library.extractdir}” overwrite=“true”/>
    <copy file=“${library.extractdir}/library.swf” todir=“${library.outputdir}” overwrite=“true”/>
    <delete dir=“${library.extractdir}”/>
</target>

4.3. Add a target that will build your main SWC, by configuring and executing the “extract swf library” generic target, which in turn will cause “build swc” to be executed first:

 
<!– ************************************************************ 
             Adobe AIR Library Targets
     ************************************************************ –>
<!– This target sets {library.name} and {library.root} and executes the generic target “build swc” for their values. –>
<target name=“build air library”>
    <subant target=“extract swf library”>
        <property name=“library.name” value=“${air.library.name}”/>
        <property name=“library.root” value=“${air.library.root}”/>
        <property name=“library.outputdir”  value=“${tempdir}/${air.library.name}/swc”/>
        <fileset dir=“.” includes=“build.xml”/>
    </subant>
    <property name=“air.library.outputdir”  value=“${tempdir}/${air.library.name}/swc”/>
</target>
 
Here you’ll need to configure the parameters that tell Ant where your AIR library is and what it’s called. Add these to build.properties:

4.4. Do you have a default implementation for your ANE?

If you answered ‘I do’, repeat step 4.3. to build your default implementation SWC. Come on, you don’t expect me to do copy and paste here, right?

5. Add targets for collecting the files we’ll need to package the ANE

Are you still with me? That’s probably the most tedious bit of the whole exercise, so if you decide to abandon the article at this point, I won’t blame you.

For the three people still reading, let’s roll up our sleeves and get on with it. Mum, dad, I’ll explain what Ant is when I next speak with you on Skype…

5.1. The following two targets will make sure you have a temporary folder for packaging to copy files into. Unless it exists already.

<target name=“does package dir exist” description=“Check if the temporary package folder has already been created” >
    <available property=“temp.packagedir.exists” file=“${temp.packagedir}”/>
</target>

<target name=“create package folder” depends=“does package dir exist” unless=“temp.packagedir.exists” description=“Create temporary folder for the package ingredients”>
    <mkdir  dir=“${temp.packagedir}”/>
</target> 

5.2. The next target automates what you did by hand in steps 1.a. to 1.d. in Recipe for packaging an ANE.

 <!– Copy all of the files needed for packaging an ANE for iOS: –>
<target name=“copy ios files for packaging” depends=“rebuild ios, build air library, create package folder”>
    <copy file=“${air.library.sourcedir}/${air.extension.descriptor}” todir=“${temp.packagedir}”/>
    <copy file=“${air.library.sourcedir}/${air.platform.descriptor}”  todir=“${temp.packagedir}”/>
    <copy file=“${iOS.project.outputdir}/${iOS.library}” todir=“${temp.packagedir}”/>
    <copy file=“${air.library.outputdir}/${air.library.name}.swc” todir=“${temp.packagedir}”/>
    <copy file=“${air.library.outputdir}/library.swf” todir=“${temp.packagedir}”/>
</target>

6. Add a target to package your ANE

Finally. Let us now automate the command line that you would normally have to run by hand. Like the rest of this example, the following will package an ANE for iOS. You can extend that to cover other platforms. 

Have a look at Recipe for packaging an ANE for command lines you can run on iOSAndroidMac OS and Windows.
<!– Create the ANE package for iOS –>
<target name=“package ane” depends=“copy ios files for packaging” description=“Package the extension into an ANE file”>
    <mkdir  dir=“${temp.packagedir}/ane”/>
    <exec executable=“${ADT}” failonerror=“true” dir=“${temp.packagedir}”>
        <arg line=“-package 
                   -target ane ane/${ane.name}.ane
                   ${air.extension.descriptor} 
                   -swc ../${air.library.name}/swc/${air.library.name}.swc
                   -platform iPhone-ARM 
                   -C . .
                   -platformoptions ${air.platform.descriptor}”
        />
    </exec>
    <mkdir dir=“${ane.destination}”/>
    <move file=“${temp.packagedir}/ane/${ane.name}.ane” todir=“${ane.destination}” overwrite=“true”/>
    <delete dir=“${tempdir}”/>
</target>

Add these last two properties to build.properties to tell Ant what your .ANE file should be called and where you want it to end up and you are done:

7. Run the script

Are you ready? 

Open a Terminal window and navigate to your build.xml file, then run

ant

If all went to plan, you should see something like this at the end of the long log that ADT spits out:

BUILD SUCCESSFUL
Total time: 10 seconds

If there were build or packaging errors instead, give us a shout in the comments below. We want to help.

Hey, didn’t we say a single click build?

That’s so far a single command-line build… Don’t worry, it doesn’t end here. Being a man, well, a woman of my word, I’ll take you along that last mile, should you like to join me. 

You have so far done the hard work, the rest is quick and easy: head over to Package your ANE in Flash Builder.

In a hurry?

We have created a set of template build scripts which you can use to automatically build and package native extensions for iOSAndroidMac OS and Windows. Leave a comment below and let us know if you want one e-mailed to you and which platform(s) you need it to support.

Comments

  1. I need a build script for an Android ane build.
    I bought your excellent eBook and have successfully built and tested my ane for iOS. It is for mobile printing for the Star SM220 printer.

    Thanks very much.

  2. Quinn

    Hi DiaDraw,
    great tutorials. I actually need a set of script for all the platforms – iOS, Android, Mac OS, and Windows for one of the projects I am working on. Thank you so much for putting all this together :-)
    -Quinn

      • Radoslava

        Glad that you find these useful. I’m e-mailing you a set of build script files for iOS, Mac OS, Android and Windows + a readme file on how to use them. Keep us posted on how these are working for you.

        Radoslava

  3. Federico

    Great tutorial!! if you could send me a couple of sample scripts fo iOS and Android that would be great. Looking forward to read your books.
    Thank you!!

    • Radoslava

      Federico, thank you for the kind feedback.
      I’m glad that you have found the automation tutorial useful and that you are looking to put it in practice. Those build scripts have saved me sooo many hours of frustration… :)

      I have just e-mailed you a set of scripts for iOS and for Android, as you requested.
      Please let us know how they worked for you.

      Greetings,
      Radoslava
      The DiaDraw Team

  4. Eric Zwar

    Hi Radoslava, I used the Windows build script that you sent me – thanks.

    I found two traps for me in my Windows 7 64 bit environment:
    1) ANT needs a 32 bit version of the Java JDK – previously I had the 64 bit JDK installed.
    2) in the local.properties file I had to add “.bat” to the adt directive – i.e. adt.bat instead of just adt.

    This is the first time I have used ANT but I have to admit it is a great tool in this context!

    Cheers.

  5. b

    I am getting an Error for:

    “The extension NameSpace requires the SWF version 17” while compile ant. I believe it has to do w -platformoptions.xml and -extension.xml

    Any thoughts?

    -B

    • Radoslava

      Hi B,

      What namespaces are you using in your platformoptions.xml and extension.xml?
      You can get the Adobe compiler to use a specific SWF version in two ways:
      – if you are using the build scripts we sent you, open build.xml and add -swf-version=17 to the argument line for COMPC in the “build swc” target;
      – if you aren’t using build sciprt, open your project’s properties, go to Flex Library Compiler and add this to Additional Compiler Arguments: -swf-version=17

      Radoslava

    • Radoslava

      Hi Emad,

      I have just emailed you the build scripts which you can use to build and package ANEs for iOS, Mac OS, Android and Windows. There is a readme file in the package that explains how to use them.
      Let us know how they are working for you and if any clarification is needed.

      You can package a single ANE for all four platforms. For that you will need to do the following:
      – list all the platforms in your extension descriptor file;
      – if you package your ANE using the build scripts I have sent you, you will need to add another package target, which calls ADT for all platforms at the same time; for example, if you wanted to do iOS, Android and simulator support together, the arg line for ADT in the target may look like this:

      -package
      -target ane
      ane/${ane.name}.ane
      ${air.extension.descriptor}
      -swc ../${air.library.name}/swc/${air.library.name}.swc
      -platform iPhone-ARM
      -C . .
      -platformoptions ${air.platform.descriptor}
      -platform Android-ARM
      -C . .

      -platform default -C ${default.swcdir} library.swf
      Cheers,
      Radoslava

    • Hristo

      Hi sa,

      I’ve just emailed you build scripts which you can use to build and package ANEs for iOS, Mac OS, Android and Windows. There is a readme file in the package that explains how to use them.

      Let us know how the scripts are working for you and if any clarification is needed.

      Cheers,
      Hristo

        • Hristo

          Hi Sohel,

          I’ve just emailed you build scripts which you can use to build and package ANEs for iOS, Mac OS, Android and Windows. There is a readme file in the package that explains how to use them.

          Let us know how the scripts are working for you and if any clarification is needed.

          Cheers,
          Hristo

    • Hristo

      Hi Tom,

      I’ve just emailed you the scripts. Let us know how they are working for you.
      Happy festive season!

      Cheers,
      Hristo

    • Hristo

      Hi Sergio,

      I have just e-mailed you the build scripts. I hope they do a good job for you.
      Get in touch if you have questions.

      Cheers,
      Hristo

  6. Hi, Hristo
    thanks you for your job, it is really nice tutorial.
    Im not able to build it in FlashDevelop, that I use.
    Im not able to link adobe libraries that leads to missing
    ExtensionContext definition. Anyway in FB I did it successfully.

    Please, can I ask you for script for Windows.
    I would like to see how ant can do the job.
    I have no experience with it. So it time to change it :)
    thanks in advance

    • Radoslava

      Hi Kirill,

      I’ve just emailed you the scripts for Android and a README file with instructions for how to customise them for your projects. Let us know how they are working for you.

      Cheers,
      Radoslava

    • Hristo

      Hi Collin,

      I have just emailed you the build scripts for iOS.
      Let us know how they are working for you.

      Best,
      Hristo

Trackbacks

  1. […] Reposted from EasyNativeExtensions.com […]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">