Requirements

Prerequisite knowledge

Experience with ActionScript, Flash Builder, Java, Eclipse, Android and using native extensions will help you make the most of this article.

Additional required other products

User level

Intermediate

Adobe AIR is by design cross-platform and device-independent, but AIR applications can still access the capabilities and APIs of native platforms through AIR native extensions.  A native extension enables you to use platform-specific features, reuse existing native libraries, and achieve native-level speed for performance-sensitive code.  This tutorial addresses the first two capabilities with a focus on developing for the Google Android platform.
 
This tutorial covers the implementation, application, and debugging of a simple native extension that uses an Android activity to enable browsing through a selected set of web sites.  Some of the pitfalls particular to native extensions on the Android platform, such as referencing native resources and assets, will be presented in detail.  To complete the steps outlined here, you’ll use some of the latest tools available for Adobe ActionScript development, Flash Builder 4.7 and AIR SDK 3.6, along with the Eclipse IDE and the Android Developer Tools (ADT) plugin for the native Java code.
 
This is a hands-on tutorial, so be sure to  download the sample files, which include the Flash Builder and Eclipse projects with which you will be working.
 
You will also find it useful to refer to other tutorials such as the Building a native extension for iOS and Android series at the Adobe AIR Developer Center to explore aspects of native extension development other than the Android-centric issues addressed here.  The Developing Native Extensions for Adobe AIR PDF document available at the Adobe help center is also a good resource.
 

 
Setting up the AIR SDK and native development tools

Steps detailing the installation of Flash Builder 4.7 are not covered here; refer to the Flash Builder product page for information on trial versions and purchasing the software.
Installation of the SDKs currently requires some additional steps in order to use the new ActionScript compiler, ASC 2.0.  This new compiler ships with Flash Builder 4.7 and provides several new features and performance enhancements such as multi-threading, faster compilation times, and inlining, making it highly recommended for game development.  However, due to release engineering constraints, Flash Builder 4.7 initially ships with a special version of the older AIR SDK 3.4 that includes the new compiler.
 
 
AIR SDK 3.6 (and newer) with ASC 2.0 and Flash Builder 4.7
To use the current AIR SDK 3.6 with its latest features and bug fixes, you must (for now) separately download AIR SDK 3.6 with ASC 2.0 and install it manually.  These instructions also apply to newer versions of the AIR SDK. Future releases of Flash Builder 4.7 may ship with newer versions of the AIR SDK, so if the shipped version is adequate for your needs, you may choose to skip this step.
 
  1. Download the AIR SDK 3.6 with ASC 2.0 from Adobe Labs or from Adobe Developer Connection. Newer versions of the AIR SDK may also be found at Adobe Labs, but I've only tested AIR SDK 3.6 with this tutorial.
The default locations of the AIR SDK in Flash Builder 4.7 are:
 
  • Mac OS X: /Applications/Adobe Flash Builder 4.7/eclipse/plugins/com.adobe.flash.compiler_4.7.0.349722/AIRSDK
  • Windows 7 (64-Bit): C:\Program Files\Adobe\Adobe Flash Builder 4.7 (64 Bit)\eclipse\plugins\com.adobe.flash.compiler_4.7.0.349722\AIRSDK
The trailing version numbers may differ from your installation of Flash Builder 4.7 depending upon the exact build that you installed.  Note that these locations are different from older versions of Flash Builder, which required the AIR SDK to be overlaid in the sdks directory of the top level of the application.
 
  1. Exit Flash Builder if it is running. 
  2. Copy the AIRSDK folder to a different name for backup. 
  3. Delete the contents of the original AIRSDK directory.
  4. Unpack the contents of the AIR SDK 3.6 with ASC 2.0 into the original folder, keeping the AIRSDK name.  To do this, copy the AIR SDK 3.6 download package to the original AIRSDK folder, and then from a terminal, type tar jxvf package.tbz2 to create the new SDK, replacing package with the actual basename. 
  5. Copy the contents of the lib/aot folder from the backup AIRSDK folder into the newly created AIRSDK folder at lib/aot.
  6. Finally, create an empty folder named strip and put it into the lib/aot/bin directory if it doesn't already exist. This will work around packaging issues if you need to deploy on iOS. 
For further information on this procedure, see Update the AIR SDK in Flash Builder 4.7.
 
 
Adobe Flex application support with AIR SDK 3.6 and Flash Builder 4.7
The distribution of the AIR SDK with ASC 2.0 is for pure ActionScript development only. It should not be combined with an existing Flex SDK.  To support Flex application development with newer versions of the AIR SDK, an AIR SDK overlay distribution that does not include ASC 2.0 needs to be overlaid over the Flex SDK bundled with Flash Builder 4.7.  Since you will be using a test application that uses the Flex framework to supply UI elements, you will need to perform the manual overlay as follows in order to use AIR SDK 3.6.
 
  1. Download the AIR SDK 3.6 without ASC 2.0 from Adobe Developer Connection. Make sure you select one of the alternative links intended for Flex users (for Mac or for Windows), not the main "Download Now" links that include the new compiler.
  2. Exit Flash Builder if it is running.
  3. Copy the entire existing Flex SDK folder to a different folder.  The default locations for the Flex SDK are:
    • Mac OS: /Applications/Adobe Flash Builder 4.7/sdks/4.6.0
    • Windows: C:\Program Files\Adobe\Flash Builder 4.7\sdks\4.6.0
The instructions below for using the native extension in an AIR application assume you've copied the Flex SDK to a folder named 4.6.0-air3.6 in the same sdks directory. 
 
  1. Copy or move the downloaded SDK package to the copied directory and unpack it there directly over the existing contents to update the Flex SDK with AIR 3.6.  Later, when configuring the Flex mobile project for the test application, you'll be able to choose your updated Flex SDK for building the project.
  2. If you are updating existing Flex applications to the new SDK, you may need to check the -target-player configuration option and the corresponding location of playerglobal.swc; for example:
    • AIR 3.4 SDK contains frameworks/libs/player/11.4/playerglobal.swc
    • AIR 3.6 SDK contains frameworks/libs/player/11.6/playerglobal.swc
  3. For Flex development, the default -external-library-path should point to the correct version of playerglobal.swc.
     
  4. Check your frameworks/flex-config.xml to make sure this version information matches.
 
Java version
At this point Adobe tooling is not quite compatible with Java 7 and you may run into errors at linking and packaging time.  If you have Java 7 installed and run into such issues, try using the latest version of Java 6.  You should be able to use either the 32-bit or 64-bit variants, but the steps below assume that you are using the 64-bit version of Java 6.
 
 
Eclipse and the Android Developer Tools (ADT) plugin
Eclipse is an integrated development environment (IDE) for developing Java applications.  In this tutorial, you will use Eclipse to build the Java native code in the native extension (this tutorial does not cover C language native coding).
 
If you don't already have the Eclipse IDE installed, you can download the complete Android development environment including Eclipse and the Android Developer Tools plugin at the Android Developers page.  If you already have the Eclipse IDE installed, you can just download and install the Android SDK tools on that page instead.  Make sure that you install the ADT plugin into Eclipse according to the instructions provided by Google.
 
This tutorial assumes that you are using Eclipse 4.2 Classic.  The Android Developers site now points you to the mobile version of Eclipse and that should be fine as well.  Either the 32-bit or 64-bit variants will work.
 
Don't confuse the Android Developer Tools with the AIR Developer Tool.  Unfortunately they are both referred to as ADT in their respective developer communities.  The AIR Developer Tool is a command-line utility for packaging, signing, installing, and running AIR applications and consists of a shell script and a Java library.  The executable shell script can be found in the sdks/{version}/bin folder at the root of Flash Builder installation folder, and also at eclipse/plugins/com.adobe.flash.compiler_{version}/AIRSDK/bin.  Either will work and you may want to put the adt executable in your path for convenience, as you will be invoking it directly to package your native extension into an ANE file.
 

 
Developing the ActionScript library

In this section you will create the ActionScript library that serves as the interface between the native Android Java code and the AIR application.  The code in this sample is very simple and does little more than creating and initializing the ExtensionContext instance bridging AIR and the native platform.  Two functions are provided to the sample application:  getVersion(), which retrieves the Android version numbers of the application and the AIR runtime; and showBrowser(), which presents a native Android activity to the user.
 
The sample files include ANESample.fxpl, a Flash Builder project that can be imported directly into Flash Builder.  The archived project is mostly ready to build, except that it may refer to libraries in the AIR SDK with slightly different file system paths depending upon how you've installed the AIR SDK. 
This tutorial steps through the process as though you were developing from scratch so that it can illustrate some points of interest.
To get started, rename the .fxpl file with a .zip extension and then unzip the file into the directory of your choice.
 
 
Project initialization
  1. Open Flash Builder 4.7 and choose File > New > ActionScript Library Project. 
  2. For the project name, type ANESample.  (In general, you can use any name you like.)  Use the default location unless you have a good reason to change it.
  3. Since you have installed AIR SDK 3.6 in Flash Builder's Eclipse plugin folder, the project creation dialog box will display "This project will use AIR SDK 3.6" (see Figure 1). If it does not, then review the installation procedure above. 
  4. Select Include Adobe AIR Libraries, and then click Next.
  1. In the next dialog box you should see "AIR SDK 3.6" under Build Path Libraries on the Library Path tab, with the location of AIRSDK according to the SDK installation instructions above.
  2.  Click Finish to complete the project initialization. 
  3. You will see the new project in the Package Explorer area to the left. Click the reveal triangle to see the initial components of the project.
  4. Right-click the project name in the Package Explorer and select Properties. 
  5. Select ActionScript Library Compiler on the left to see the compiler settings, which should have the following options selected: Include Adobe AIR Libraries, Use Version Specified By The AIR SDK, Enable Strict Type Checking, and Enable Warnings. 
  6. Type –locale en_US as an additional compiler argument (see Figure 2).
  7. Click OK.
  1. Flash Builder by default will build projects automatically.  This can be a little distracting, so for now choose Project > Build Automatically and ensure that that this option is not checked.  This will enable the Project > Build menu item.
 
Add the source code
Now you are ready to add the ANESample library source code to the project. 
 
  1. Choose File > New > ActionScript Class in Flash Builder.
  2. For Package, type com.adobe.sampleasextension. For Name, type SampleASExtension.
  3. Click Finish.
    You will see the generated skeleton code in the code editor. 
     
  1. Copy and paste the source code from src/com/adobe/sampleasextension/SampleASExtension.as (included in the ANESample.zip archive) into the code editor, replacing the skeleton code.
 
The extension context
At line 13 you can see the call to the createExtensionContext() method of the static flash.external.ExtensionContext class that was imported. The ExtensionContext instance will be created when SampleASExtension is instantiated through its constructor. 
The first parameter is the identifier of the native extension; you use this identifier when packaging the native extension (in the <id> node of the extension.xml file you will create later), and when packaging the application that uses the native extension (in the <extensionID> node of the ANESampleTest-app.xml file).  It should always be in reverse DNS notation to avoid conflicts since all extensions share the same namespace.  If any of this is set up incorrectly, then createExtensionContext() will fail and return null at runtime.
 
The second parameter is the context type, which gives more information to the native extension about what it should do. For example, the same extension context could be used to manipulate either a brightness level or a contrast level for a display depending upon whether the string "bright" or "contrast" was provided here.  This simple sample extension supplies the string "SampleASExtension", but it is not examined in the native code, so you could set it to an empty string if you want to.
 
After creating the extension context you should do any appropriate initialization of the context on the native side.  This is performed here by invoking the call() method of the extension context with a string that indicates what code to invoke on the native side ("initMe").
 
 
The extension API
This extension provides a minimal API with two methods: getVersion() and showBrowser().  The former method will display the version numbers of the application and the AIR runtime installed on the Android device, while the latter will start the Android activity.
As with the native context initializer, these are implemented with the call() method of the extension context:
 
public function getVersion():void { extContext.call("getVersion"); } public function showBrowser():void { extContext.call("showBrowser"); }
When you proceed to developing the native Java code, you will see how the string parameters of the call() methods are mapped to the appropriate native methods. 
 
 
Build it!
  1. Save the code that you pasted into the code viewer.
  2. Build it by choosing Project > Build Project.  Alternatively, you can right-click the project name in the Package Explorer and choose Build Project. 
If all goes well, you will see a result file named ANESample.swc in the project's bin directory in the Package Explorer (click the reveal triangles to right of any component in the Package Explorer to see the contents).  This is the compiled ActionScript library that you will later package with the native library to create an ANE file.  You can find its location in the file system by right-clicking the file and choosing Properties (see Figure 3).
 

 
Developing the native project

The sample file ANESample_java.zip contains the Eclipse project and Java source code needed for this section. As before, this project can easily be imported into Eclipse (by choosing File > Import > General > Existing Project Into Workspace), but the following steps cover the process mostly from scratch.
 
 
Project initialization
  1. Open Eclipse and choose File > New > Other > Android Application Project.
  2. Click Next. 
  3. Type ANESample_java as the application name and project name.  (You can use other names if you want.)
  4. The package name should be com.adobe.sampleasextension. 
  5. Click Next several times through all the remaining dialog boxes, and then click Finish.
  6. Next, right-click the project name and select Properties. 
  7. In the Properties dialog box, select Java Build Path. 
    You need to link the FlashRuntimeExtensions library into your native code.
     
  8. Select the Libraries Tab and click Add External Jars. 
  9. Browse to the Flash Builder 4.7 installation folder and down through Eclipse > plugins > com.adobe.flash.compiler_4.7.x.xxxxxx > AIRSDK > lib > android, select FlashRuntimeExtensions.jar, and then click OK (see Figure 4).
 
The Android layout
A main goal of this tutorial is to demonstrate how to access and use Android resources from AIR native extensions.  For this purpose you will first set up the layout for an Android activity and its associated resources, since you will be referring to those resources later in the Java source code.  (Note that it is entirely possible to develop an Android native extension without accessing native resources directly, as demonstrated by the Volume control native extension tutorial available in the AIR Developer Center).   Instructions for using the ADT Graphical Layout editor are beyond the scope of this tutorial, so you will just use a pre-arranged layout from the ANESample_java.zip project archive, located at res/layout/anesample.xml.
 
  1. Choose File > New > Other > Android > Android Layout file and click Next. 
  2. Type anesample.xml for the name, choose LinearLayout, and then click Finish. 
    The new layout file will appear in res/layout/anesample.xml in the Package Explorer.
     
  3. You can delete the activity_main.xml file there since you won't be using it, and you might as well delete the res/menu folder too. 
  4. Double-click anesample.xml to open it in the Graphical Layout editor. 
  5. Click the anesample.xml tab to see the XML; paste the contents of the anesample.xml file from the ANESample_java.zip archive there, replacing the original contents. 
  6. Save the file.
  7. Click the Graphical Layout tab again to see how the layout will appear. 
    There will be two errors: "Couldn't resolve resource @string/cnn" and "Couldn't resolve resource @string/yahoo." 
    To resolve these errors and provide a proper app name, you will need to update the res/values/strings.xml file. 
     
  8. Double-click it in the Package Explorer, choose the strings.xml tab, and paste the contents of the strings.xml file from res/values in the ANESample_java.zip archive, replacing the original contents.
  9.  Save the file. 
  10. Double-click the anesample.xml file in the Package Explorer and you should see the layout rendered without errors (see Figure 5).
 
ANESample.java and the FREExtension interface
You are now ready to implement the FREExtension interface, which is the initial entry point for the native Java code. The name of this class is significant, as you will use it in the <initializer> and <finalizer> nodes of the extension.xml file that you will use to package the native extension.
 
  1. Choose File > New > Class to create a new Java class in the project.
  2. Type com.adobe.sampleasextension as the Package, ANESample for the Name, and com.adobe.fre.FREExtension for the Interface.
  3. Click Finish.
    The new file will show up in the Package Explorer under src/com.adobe.sampleasextension.
     
  4. You can delete MainActivity.java since you won't be using it.
  5. Double-click ANESample.java to display the stub code in the editor. Then copy and paste the contents of ANESample.java from the ANESample_java.zip archive, replacing the stub code.
For now Eclipse will flag an error on the call to the ANESampleContext() constructor at line 16. You will resolve that by importing the source code in the next sections.
 
The most important part of this class is the createContext() method at line 15. This method is called by the AIR runtime when ExtensionContext.createExtensionContext() is invoked on the ActionScript side; it must return a FREContext class instance. The String parameter here is the second argument passed to createExtensionContext() on the ActionScript side ("SampleASExtension" in the code) and can be used to create different FREContext instances depending on what is needed. The sample uses only one context, so the parameter is ignored here.
 
The initialize() and dispose() methods are called by the AIR runtime on extension initialization and destruction respectively. They can be used to create and recover any persistent resources that you need; in this instance, you don't need to do anything special with them so they are empty. A constructor, if provided, must not take any parameters.
 
The complete initialization sequence when createExtensionContext() is called is:
 
  • the FREExtension implementation's constructor
  • initialize()
  • createContext()
 
ANESampleContext.java and the FREContext class
  1. As before, choose File > New > Class to create a new Java class in the project.
  2. Type com.adobe.sampleasextension as the Package and ANESampleContext as the Name, but this time type com.adobe.fre.FREContext as the superclass that you will extend.
  3. Click Finish.
  4. Double-click ANESampleContext.java in the Package Explorer to display the stub code in the editor, and then copy and paste the contents of ANESampleContext.java from the ANESample_java.zip archive, replacing the stub code.
The ANESampleContext class is created when the createContext() implementation in ANESample is called. The function keys used in the ExtensionContext.call() method invocations in the SampleASExtension ActionScript code get mapped into calls to the Java methods on the native side. The getFunctions() method at line 19 is an abstract method defined in FREContext that must be implemented by returning a Map that associates the extension function keys to the native FREFunction implementations. At first, the Eclipse code editor shows errors for the put() calls at lines 22, 23, and 24, since you have yet to provide implementations for the FREFunction interfaces.
 
The only other required method implementation for this class is the dispose() method. Calling the ActionScript dispose() method on the associated ExtensionContext causes AIR to call the Java dispose() method defined here at line 15. If dispose() is not explicitly called on the ActionScript side then it will be called by the AIR garbage collector when no more references to the extension context exist. For this example, you can leave the dispose implementation empty, and you don't need a non-default constructor.
 
 
FREFunction implementations: initFunction.java and getVersion.java
Create the initFunction and getVersion Java classes as you did previously, this time using com.adobe.fre.FREFunction as the interface to implement.
 
The initFunction() method is mapped to the "initMe" function key. You don't need any special initialization in this extension, so this is a stub that merely prints out that it was called.
 
The getVersion() method is mapped to the function key of the same name. In this method you can see how to get the Android activity and the PackageManager from the FREContext object passed as the first parameter to the call() method at line 11.
 
Additional ActionScript arguments to the FREFunction implementations are passed as FREObject instances to the Java code. They are not used here, but if needed, the FREObject class provides methods to obtain the types and the Java values of the arguments wrapped into them. ActionScript objects as well as primitive types can be passed through an FREObject; there are FREObject methods on the ActionScript side to create them and methods on the Java side to get and set properties and call their methods.  Some ActionScript objects that hold large amounts of data (Array, Vector, ByteArray, and BitmapData) also have special support in the Java API in order to manipulate data efficiently on the native side.
 
There are a number of restrictions on accessing FREObjects that are not covered in detail here. Primarily, you can only access an FREObject instance from the same thread in which the owning FREFunction is running. An FREObject instance is only valid until the first FREFunction instance on the call stack returns; this is the one that AIR calls when the ActionScript side calls ExtensionContext.call(). FREObject instances can't be shared between extensions, and you can't save their references in global data between calls to FREFunctions and get valid access. The recommended way to synchronize data transfer between asynchronous ActionScript and Java threads is through the dispatchStatusEventAsync() method of an FREContext instance; the corresponding ExtensionContext instance on the ActionScript side will dispatch a Status event to which listeners can respond.
 
 
Accessing Android resources: showBrowser.java
Create the showBrowser class using the same procedure used for the initFunction and getVersion classes. With this class you will see the special handling required to access native Android resources such as layouts and buttons.
 
Like in any conventional Android Java project, you can use the R* mechanism to access resources in AIR native extensions. To learn more about using the R* mechanism, see the Developing Native Extensions Guide.
 
The Android resources are included in the res folder of the project and can be viewed with the Package Explorer in Eclipse. To make these available to the native extension, you must copy this entire folder into the ANE file when you package the extension (this process is covered in more detail later in this tutorial).  When you finally package the entire ActionScript application, the resources from all extensions will be merged into one resource directory for Android. For this reason it is important to ensure that there are no name conflicts across extensions.
 
You can access a resource using R.id.buttonName, or the getResourceId() method of the FREContext instance to retrieve it as id.buttonName. In the showBrowser class you can see three examples of this call for the layout.anesample, id.CNNButton, and id.YahooButton resources, at lines 17 – 19:
 
layoutID = ctx.getResourceId("layout.anesample"); CNNButtonID = ctx.getResourceId("id.CNNButton"); YahooButtonID = ctx.getResourceId("id.YahooButton");
These resources were defined when you set up the layout for the Android activity in res/layout/anesample.xml.
 
The showBrowser class sets up the Android Intent used to start the actual Activity, defined by the WebViewActivity class, that you want to present to the user.  The activity runs in a separate thread, however, and you need some way to pass these resource identifiers over to that thread, since the FREContext instance is created, and only available, in the main thread.  The Intent class provides the putExtra() method for associating a map of extra information with the Intent. This is exploited at lines 32 – 34 to marshal the needed resource identifiers into the activity thread:
 
i.putExtra("layoutID", layoutID); i.putExtra("CNNButtonID", CNNButtonID); i.putExtra("YahooButtonID", YahooButtonID);
 
WebViewActivity.java
Create this class in the usual way, this time as a class extending android.app.Activity.  This class is mostly standard Android code, except that you will get the resource identifiers that you need from the extra data that you associated with the Intent.  You do this by calling the getIntExtra() method of the Intent that the Activity was created with, at lines 18, 23, and 26, and passing it the key for the integer resource identifier retrieved in the showBrowser class.
 
With these resource identifiers now available to use, you can finally call setContentView() at line 21 with the layout defined at the beginning of this tutorial section, and create Buttons at lines 29 and 30, which will launch the Intents that will browse to the URLs associated with the Buttons:
 
int layoutID = getIntent().getIntExtra("layoutID", -1); System.out.printf("layout ID: %d\n", layoutID); setContentView(layoutID); int CNNButtonID = getIntent().getIntExtra("CNNButtonID", -1); System.out.printf("CNNButton ID: %d\n", CNNButtonID); int YahooButtonID = getIntent().getIntExtra("YahooButtonID", -1); System.out.printf("YahooButton ID: %d\n", YahooButtonID ); Button CNNButton = (Button)findViewById(CNNButtonID); Button YahooButton = (Button)findViewById(YahooButtonID);
 
Build it!
At this point Eclipse should not be presenting any errors and you should be able to build the project without a problem. 
To generate the library that you will package with your native extension file, follow these steps:
 
  1. Right-click the project and select Export.
  2. Select Java > JAR file, and then click Next. 
  3. Leave the default settings.  Under Select The Export Destination, select the root of the project as the folder and specify ANESample.jar as the name (see Figure 6). 
    You will use this path to retrieve the library when you package the extension.
     
  4. Click Finish.
 
Accessing third-party native libraries
The original purpose of native extensions was to provide access to native platform features that were not currently covered by the ActionScript API. However, many ActionScript developers targeting Android have expressed a strong interest in taking advantage of available third-party Android libraries that package together a number of popular Android-specific functions, so that they need not reimplement those functions in ActionScript. To use any third party library jar in your project you can use the R* mechanism. For more information, see Developing Native Extensions Guide.
 
 
Working with arbitrary assets
In addition to accessing Android native resources, developers often need to access arbitrary resources for assets such as drawables and sound files. These assets are frequently found packaged in arbitrary dependent JAR files instead of a central location, especially for third-party native libraries. To use such assets in your project you can use the R* mechanism. For more information, see Developing Native Extensions Guide.
 

 
Packaging the ANE file

Now that you have both the ActionScript code and the native Java code built, you are ready to package the resulting libraries into a native extension ANE file that can be linked into an ActionScript application.  This workflow is not integrated into Flash Builder and must be performed manually on the command line using the AIR Developer Tool, adt.  As described in the SDK installation section, this tool can be found in the sdks/{version}/bin folder at the root Flash Builder installation folder, and also at eclipse/plugins/com.adobe.flash.compiler_{version}/AIRSDK/bin.
 
The ANESampleBuild.zip archive contains a Bash shell script, buildANE.sh, that automates the commands needed to package the native extension for the sample code, and also provides a sample folder structure for the packaging steps (see Figure 7). 
 
This folder structure is only provided as an example; adt is quite flexible in where it can pick up all its components (using the –C option).  To use this script as is, you will need to modify the setting of the file paths for the adt and nativedir variables at the top, and also unzip the entire folder structure of the ZIP file as a peer to the ANESample and ANESample_test folders in your Flash Builder project directory.
 
adt="/Applications/Adobe Flash Builder 4.7/eclipse/plugins/com.adobe.flash.compiler_4.7.0.349722/AIRSDK/bin/adt" nativedir="/Users/markhood/Documents/Eclipse64/ANESample_java" rm -rf Android-ARM/* rm -f SampleASExtension.ane library.swf mkdir -p Android-ARM unzip ../ANESample/bin/ANESample.swc library.swf cp library.swf Android-ARM cp "$nativedir"/ANESample.jar Android-ARM cp -r "$nativedir"/res Android-ARM "$adt" package target ane SampleASExtension.ane extension.xml swc ../ANESample/bin/ANESample.swc -platform Android-ARM -C Android-ARM .
 
extension.xml
The extension.xml descriptor file provides the information necessary for adt to link the native extension libraries into the ActionScript application. An example version is provided that will work for the sample code.
 
<extension xmlns="http://ns.adobe.com/air/extension/3.6"> <id>com.adobe.sampleasextension</id> <versionNumber>1</versionNumber> <platforms> <platform name="Android-ARM"> <applicationDeployment> <nativeLibrary>ANESample.jar</nativeLibrary> <initializer>com.adobe.sampleasextension.ANESample</initializer> <finalizer>com.adobe.sampleasextension.ANESample</finalizer> </applicationDeployment> </platform> </platforms> </extension>
The essential structure is as follows:
 
  • namespace: use "http://ns.adobe.com/air/extension/3.6" since you are using AIR SDK 3.6
  • id: this must be the same reverse-DNS identifier that is used in the call to createExtensionContext()
  • platform name: must be "Android-ARM" for Android native extensions
  • nativeLibrary: the JAR file exported from the Eclipse project
  • initialize and finalizer: the Java class that implements FREExtension
Multiple platforms may be supported by a native extension, and if so, they must be listed in the <platforms> node of the XML.  It is also a good idea to provide a default platform implementation that is pure ActionScript in case an implementation is not provided for a given platform; this implementation might not be very functional but can be useful for debugging the ActionScript side.  The details of multiplatform implementations are beyond the scope of this article, but the volume control tutorial provides a good example.
 
 
library.swf
The library.swf file is the compiled ActionScript code.  It is retrieved by uncompressing the ANESample.swc file that results from building the ActionScript implementation.  The SWC file is located in the ANESample project directory in the bin folder.  The buildANE.sh script performs this task and also copies it to the Android-ARM folder, where its presence is also required.
 
 
The Android-ARM folder
The Android-ARM folder must contain the JAR file exported from the Android native code project (ANESample.jar in this tutorial), along with the library.swf file from the ActionScript library and the entire res folder hierarchy from the Android project.  The buildANE.sh script also performs this task.
 
 
Code signing
The ANE file can be signed with standard cryptographic methods, but this won't be necessary for this sample project.  An example certificate, cer.p12, with password "password", is provided. The -keystore and -storepass options of adt are used for code signing.
 
 
The adt command line
Many variations of adt options will result in a successful package.  The buildANE.sh script demonstrates a typical command line that will work with the folder arrangement provided.  A second variation, commented out, shows how to use the –keyword and –storepass options to sign the package with the given certificate. 
The essential options of the command line are:
 
  • package: indicates that you're doing a packaging operation
  • target: specifies that you are packaging an ANE (with the "ane" keyword) and that the name of the package will be SampleASExtension.ane, according to the structure specified by extension.xml
  • swc: specifies the location of the SWC file generated by the ActionScript build; this is required in addition to the library.swf file
  • platform: specifies a platform implemented by the native extension (Android-ARM) and that all the required native elements are in the directory Android-ARM ("-C Android-ARM .")
If you have all the required elements in place, then running the buildANE.sh script should result in a SampleASExtension.ane library that you can link into the test application in the next section.  If you're curious, you can decompress the .ane file (as a ZIP) and examine the contents. 
 
Make sure that whenever you modify the ActionScript or Android projects that you also rerun the script that will create the ANE, as you won't get any errors until runtime.  This is a pitfall of the lack of integration into a Flash Builder workflow.  The process can be automated as an Ant script for better integration into Flash Builder, so if you have expertise with Ant you may want to use the Bash script as a basis for writing one.
 

 
Using the native extension in an AIR application

This section covers the process of developing and linking an application that will use the ANE file you just created.  You will create a Flex application so that you can set up a user interface with a minimum of code. For new projects, however, you may want to develop the application entirely with the ActionScript API.  The Flex test project is included in the ANESampleTest.zip archive, in the archive file ANESampleTest.fxp.  This is an archived Flex project that can be directly imported into Flash Builder, but the steps below will go through the project creation from scratch.  Rename the .fxp archive to .zip and unpack it into a directory of your choice.
 
 
Project initialization
  1. Choose File > New > Flex mobile project from the Flash Builder menu bar. 
    Make sure you choose the mobile project or you won't have access to the features and libraries that you'll need for deployment on Android, and you won't be able to convert your desktop application to a mobile one.
     
  2. Type ANESampleTest for the project name. 
  3. Click Configure Flex SDKs.
  4. You need to select the Flex SDK in which you overlaid the version of AIR SDK 3.6 without the ASC 2.0 compiler.  Click Add, add the SDK to the list, and then ensure that it is selected (see Figure 8).
  1. Click OK.
  2. Verify that the New Flex Mobile Project dialog box shows that the SDK you picked will be used.  The dialog box should also note that your SDK requires Adobe AIR 3.6 (see Figure 9).
  3. Click Next.
  1. Deselect Apple iOS if it is checked and make sure that only the Google Android box is checked.
  2. Under Application Template select View-Based Application (see Figure 10).
  3. Click Next twice.
In the Build Paths dialog box, you can see the path to the Flex SDK you configured in the Library Path section.  
 
  1. Select the Native Extensions section, click Add ANE, and then browse to the ANESampleBuild folder that you set up when packaging the ANE.
  2.  Select SampleASExtension.ane, ensure that Update AIR Application Descriptor is selected, and then click OK.
In the current release of Flash Builder 4.7, you will notice that there is red "X" next to the SampleASExtension.ane entry in the Build Paths dialog box (see Figure 11). If you click the triangle you'll see the error "This ANE does not support Apple iOS-device , Desktop(Mac) platforms" (if you're using a Mac; otherwise a similar message appears for the Windows desktop platform).  This is a quirk in Flash Builder 4.7; if you click the triangle next to Targets you'll see that Google Android is supported by the ANE, and that is all you're concerned with for now.
 
  1. Click Finish to complete the project initialization. 
You should see a few new files in the Package Explorer under the src directory:
 
  • default/ANESampleTest.mxml The main stub; mostly empty for this sample application.
  • views/ANESampleTestHomeView.mxml  This is where you'll put your application code.
  • ANESampleTest-app.xml  The application descriptor file. You'll need to make a few edits to it later.
 
Handling updates to the ActionScript code and native libraries
In the course of developing and debugging a project with native extensions you will naturally have to make revisions to both the native and ActionScript libraries.  Because the process of packaging the ANE file is decoupled from Flash Builder, you must always remember to recreate the ANE file every time you make a revision to either library (which is why putting the process in a script is recommended), and then you must tell Flash Builder to use the new ANE.
 
  1. After you have rebuilt the ANE, right-click the application project in the Package Explorer and select Properties.
  2. Select Flex Build Path and then click Native Extensions.
  3. Click SampleASExtension.ane to select it (see Figure 12). 
  4. At this point clicking on Refresh should update Flash Builder with the new ANE, but in practice some developers have found that Refresh intermittently fails to update the build.  For best results, always click Remove, and then click Add ANE to refresh the ANE definition.
The lack of cohesion between the process of creating the native extension and the normal Flash Builder workflow can be a bit challenging.  While the process of simply using a release-quality native extension is fairly straightforward, native extension developers don't have it quite so easy.
 
 
ANESampleTestHomeView.mxml
The main application code for the sample application is located in ANESampleTestHomeView.mxml. 
 
  1. Copy the code from the ANESampleTest archive and paste it into the code editor window, replacing the stubbed contents.
  2. Save the file.
The script portion just imports the SampleASExtension class and defines two click handlers at lines 11 and 17 for the buttons that are defined after the script.  Each of these handlers instantiates a new SampleASExtension class and then calls one of the two API methods defined for the extension, either showBrowser() or getVersion().  Creating a new SampleASExtension class for each click is a little wasteful, but the implementation of that class only creates one static ExtensionContext class on the native side.
 
 
ANESampleTest-app.xml
The application descriptor file is ANESampleTest-app.xml.  Most of the nodes are commented out and can remain that way, but you may want to examine them in detail if you're curious.  There are a few items that you need to edit here, or you may simply paste the contents of the version of this file from the ANESampleTest.fxp archive into the generated file and replace the XML.
 
  1. The <versionNumber> node at line 30 is by default 0.0.0.  The sample application will display this version number when the Get Version button is clicked, along with the version number of the AIR runtime. Put some arbitrary number here so you can verify that this function is working.
    The application will launch an Android activity, so you also need to declare that here in the application descriptor file, and you also want to enable the application for interactive debugging.
     
  2. Search for the uncommented <android> node.  There is a <manifest> node nested within.  Just before the closing </manifest> tag, add the following XML:
<application android:enabled="true" android:debuggable="true"> <activity android:name="com.adobe.sampleasextension.WebViewActivity"></activity> </application>
 
Build it!
Before you build the application, you have to set up the Flex compiler to generate version 19 of SWF. The ASC 2.0 compiler you used to build the ActionScript library generates version 19 by default, but the Flex compiler defaults to version 14. 
 
  1. Right-click the ANESampleTest project in the Package Explorer and select Properties > Flex Compiler.
  2. For Additional Compiler Arguments add -swf-version=19, and also add -locale en_US if it is not already present.  If you don't do this you won't get an error until you package the application.
  1. Right-click the project in the Package Explorer and select Build.  There should be no problems at this point. 
You will find two build products in the bin-debug folder in the Package Explorer: ANESampleTest-app.xml and ANESampleTest.swf.  Be careful that you don't confuse the ANESampleTest-app.xml file in the bin-debug folder with the one in the src folder. If you edit the former instead of the one in the src folder then your changes will be lost with the next build. Later, when you do export a release build, those same two files will be generated in the bin-release-temp folder, and the same warning applies (if the deployment proceeds without error these file will be deleted automatically).
 
 
Deploying on Android
You will need a p12 certificate to export the release build Android APK package that you can install on the device. You can use, for testing purposes only, the one included in the ANESampleBuild archive (cer.p12).  You will also need an Android device connected to your development machine with a USB cable. 
 
  1. Choose Project > Export Release Build in Flash Builder.
  2. Ensure that Google Android is selected under Target Platforms, and that the Export To Folder is set to an appropriate directory. The default is the root of the project folder, which is fine. 
  3. Click Next to configure the Flex build packaging.
The Digital Signature and Native Extension buttons may be marked with errors in this dialog box if the code signing and native extension options have not been specified (see Figure 14).
 
  1. In the Deployment section, specify whether you want to install and launch the application after it is packaged, and whether you want to include a captive AIR runtime in the package or if you want to use a shared AIR runtime already installed on the Android device.  If you select the latter, the AIR 3.6 runtime must be installed on the device, but users will get an opportunity to install the runtime from the specified AIR download URL (or upgrade it) when they run the application.  These instructions assume that you are launching as well as installing, and that the AIR runtime is already installed on the device.
  2. In the Digital Signature section, browse to the location of the cer.p12 certificate in the ANESampleBuild folder, and use "password" as the password.
  3. In the Native Extensions section, select Package to include your SampleASExtension.ane file in the package.  Note that there will be an error marked for SampleASExtension.ane until you select this option. 
  4. Click Finish to package the application.
  5. Install it and launch it on your Android device. 
If the AIR runtime needs to be installed or upgraded the device will request permission to do that for you. The test application itself is very simple and its operation should be self-evident.  The Android APK package, ANESampleTest.apk, will be left for you in the root of the project directory.  Note that if Flash Builder 4.7 can't find a connected device it will silently fail to launch it, but the APK package will still be generated. If the app doesn't get installed on your connected device, physically reconnecting the device and re-exporting the build will usually resolve the issue.
 
Note: When you remove and re-add the ANE file to the project after modifying the ActionScript or native libraries, the option to include the ANE in the final application package may get reset.  You may need to right-click the project, select Properties > Flex Build Packaging > Google Android > Native Extensions, and then ensure that the Package option is selected (see Figure 15).
 

 
Debugging the native extension

You can use Flash Builder to interactively debug the ActionScript application and Eclipse to debug the native Android code.  This tutorial doesn't go into the details of the operation of the interactive debuggers; instead it focuses on setting up the debugging configurations.
 
 
Flash Builder debug configuration
On the ActionScript side, debugging an application that uses native extensions is pretty much the same as debugging any other ActionScript application.  The Flash Builder tool bar contains a green debug icon that starts the debugging session. It is next to the green run icon that launches the application normally. 
 
  1. To create a new debug configuration, click the small arrow to the right of the debug icon and select Debug Configurations (see Figure 16).
  1. Select Mobile Application and then click the New button, leftmost on the toolbar.
  2. For the name type ANESampleTest.
    The debug configurations can be saved and given descriptive names so that the appropriate configuration can be chosen from the tool bar.  The name "ANESampleTest" is OK here, but if you were developing for more than one platform then it would be best to include the platform in the name.
     
  3. Ensure that the target platform is Google Android.  For the launch method, select On Device, and for debugging method select Debug Via USB (see Figure 17). 
  4. Click Debug to start the debug session.
You may see a Choose Device dialog box if Flash Builder can't find a connected device.  If this occurs, try disconnecting and reconnecting the device and click Refresh.  If Flash Builder still cannot find the device, ensure that the device has USB debugging enabled in Android's Settings > Developer options configuration.
 
Flash Builder will package a debug version of the application, install it on the device, and wait for a connection.  You may see a screen on the device indicating that it is waiting as well, but that should disappear after a few moments, to be replaced by the application's HomeView with the Launch Activity and Get Version buttons. 
 
If you haven't already set any breakpoints you can do this now since the application is just waiting for you to click its buttons. At this point you can debug as normal.  You will be able to trace everything down to the point where you enter a call into any of the ExtensionContext methods.  You will also see the output of any trace() statements you have put into the code.
 
 
Eclipse debug configuration
Debugging the native code through Eclipse is complicated by the fact that you are not running the main application from there, but you can still set up a listener and then attach to the running application process.
Start by ensuring that Eclipse can make a debug connection to the application.
 
  1. Go to the DDMS perspective of Eclipse by choosing Window > Open Perspective > Other > DDMS. 
    DDMS (Dalvik Debug Monitor Server) is a Google debugging tool that provides port forwarding, process and thread information, log viewing, and many other functions.  You are mostly interested in the Devices area in the upper left corner for now.  There should be an entry there for your Android device (see Figure 18).  If there is no device listed there, then DDMS failed to get a connection and you may have to disconnect and reconnect the device, or restart DDMS until it can find your device.
     
    Ideally you want to have both Eclipse and Flash Builder connected to the device, but sometimes this can be difficult to achieve.  If Flash Builder is not able to connect to the device after connecting to DDMS, you can always just run the debug version of the application directly from the device.  The debug version of the application is installed onto the device whenever you run a debug session from Flash Builder, so if you were successful in the previous step you should have it there.  It will try to connect to Flash Builder but you can cancel the attempt.
     
  2. Remove your previous breakpoints from Flash Builder, put one before the call to createExtensionContext() in SampleASExtension.as, and then start a debug session from Flash Builder. 
    You don't have to put a breakpoint in the ActionScript at all, as the application will wait for user input once it's started, but you may find it interesting to step through from the beginning of the native code startup.
     
    Since you have marked the application as debuggable in its descriptor file, it should show up under the entry for your device in the DDMS perspective view of Eclipse, with a label like "air.ANESampleTest.debug".  The first number to the right is the process id and the second is the port it's listening on, usually port 8600.  If this were a normal application you would be able to select the running process and then click the green debug icon to the right of the devices tab to establish a connection to it.  However, in this case, you will get an error.
To connect to the running native extension you first need to set up a special listener. 
 
  1. Click the small triangle to the right of the debug icon in the DDMS toolbar and select Debug Configurations. 
  2. Select Remote Java Application, and click New button at the far left of the Debug Configurations toolbar. 
  3. Type a descriptive name for the configuration (Eclipse will suggest one based on what you were looking at last).  The project should already be labeled ANESample_java.  Type the port number that the application process is listening to as the Port; this will usually be 8600 or some number close to it (see Figure 19).
  1. Click Debug.
    There should now be a green debug icon next to the process entry in the Devices pane of DDMS.
     
  2. Open the Debug perspective by choosing Window > Open Perspective > Debug in Eclipse.
    You will see the same code windows that you have opened in the Java perspective. 
     
  3. Insert a breakpoint at the beginning of the createContext() method of ANESample and another at the beginning of the call() method of the showBrowser FREFunction implementation, or any other place in which you're interested.
  4. Click the Launch Activity button of the application running on the Android device.  If you've put a breakpoint in the ActionScript code in the SampleASExtension constructor, the debugger will now be suspended there. 
  5. Go to Flash Builder's debug perspective and step over the call to createExtensionContext()
  6. In Eclipse you should now see the application process suspended at your first breakpoint in createContext().  Step over that and you are back to the next statement in the ActionScript code displayed in Flash Builder. 
  7. Direct Flash Builder to resume running from there and you should be back at your next breakpoint in the native code in Eclipse, from which you can continue to step and debug normally. 
Congratulations!
 

 
Where to go from here

You have gone through the complete process of developing, debugging, and using a simple AIR native extension on the Android platform.  This tutorial has touched only lightly on some subjects and ignored others entirely, keeping the focus on issues specific to developing Android Java code with Eclipse and ActionScript code with Flash Builder 4.7 and AIR SDK 3.6.  Explore some of the reference materials below to broaden and deepen your understanding of this useful technology: