Monday, October 3, 2011

AIR extensions in Java for Android Part 2 -- Creating the ActionScript part

Now that we have a JAR file containing the "native" Android code, we can create the ActionScript code that goes with it. The ActionScript part of the extension serves as a go-between between the Java code and the AIR application.

The ActionScript part of an extension is an ordinary library class. The only unique part of it is that to access the native code, it creates a ExtensionContext object. The library class uses this extension context object to call functions in the Java part of the extension.

In addition, to the Java JAR file and the ActionScript library, a native extension includes an extension descriptor file. This descriptor is used by the ExtensionContext code in the runtime to look up the proper Java classes.



Create the project
I'm using Flash Builder/Eclipse in this example.

From the Flash perspective, choose New > Flex Library project
Give it a name
Choose the Generic library type
Choose a Flex SDK, the SDK must include the AIR 3 SDK as well
Check the checkbox for including the AIR libraries
Click Finish

Note: Using the Flex framework in the ActionScript extension code can be problematic. If you do, you must statically link the framework with the extension code. The extension is loaded before the framework swcs used in the application, so normally, it is not available.

Create a main class
Now add a main class to the library. This class is one that your AIR application uses to access the features provided by your extension. This class is essentially the interface presented to the AIR application.

Fundamentally, the ActionScript class has two jobs:
  • Create and initialize the context
  • Call functions in the Java code and return the results
It can do far more than that, naturally, but not in this example. Here's the entire ActionScript class:

package com.example
{
    import flash.external.ExtensionContext;

    public class DataExchange
    {
        private const extensionID:String = "com.example.DataExchange";
        private var extensionContext:ExtensionContext;
       
        public function DataExchange()
        {
            extensionContext = ExtensionContext.createExtensionContext( extensionID, null );
        }
       
        public function exchangeBoolean( value:Boolean ):Boolean
        {
            return extensionContext.call( "exchangeBooleanFunction", value );
        }
    }
}

The statement: ExtensionContext.createExtensionContext( extensionID, null) creates the extension context. When the application first calls the ExtensionContext createExtensionContext() method, the runtime finds the extension Java classes using the extension ID string (via the extension descriptor), instantiates the FREExtension implementation and calls its initialization function.  The runtime then creates the FREContext object. (Once the FREExtension object is created, it is kept until the application exits.)

The application can then call the functions in the context, in this case with:

extensionContext.call( "exchangeBooleanFunction", value );

The first parameter, functionName, is the key used in the Java extension code as a key for the function Map object. That function in the FREContext instance looked like this:
functionMap.put( ExchangeBooleanFunction.NAME, new ExchangeBooleanFunction() );
where NAME = "exchangeBooleanFunction."

Creating the ActionScript library
Flash Builder automatically builds the SWC file for the library (unless you turn off Build Automatically). However, we don't need a SWC file, we need a SWF file. To get the SWF, unzip the SWC file, which is a special kind of ZIP archive at heart. This can be as easy as changing the file extension to .zip and double clicking it. Inside, there is a file called library.swf, which is all we need. Don't rename it. For some reason, the file has to be library.swf when we create the ANE package. (This is the most annoying step in building ANE's by hand. Ideally, your build script will do the unzip and copy step for you.)

But before we can make the ANE package, we need the extension descriptor file.

Creating the extension descriptor
An extension descriptor is an XML file:

<extension xmlns="http://ns.adobe.com/air/extension/2.5">
  <id>com.example.DataExchangeExtension</id>
  <versionNumber>1</versionNumber>
  <platforms>
        <platform name="Android-ARM">
      <applicationDeployment>
        <nativeLibrary>DataExchangeExtension.jar</nativeLibrary>
        <initializer>com.example.DataExchangeExtension</initializer>
      </applicationDeployment>
    </platform>
  </platforms>
</extension>

This descriptor file has a couple of important pieces of information:
id: An arbitrary identifier used by the runtime to look up information for this particular extension (an application can use more than one extension. Use something nobody else is likely to use. The extension id appears here and is also used in the application descriptor of any apps using the extension.

platform name: The platform name, Android-ARM, identifies the platform (i.e. Android, iOS, Windows, etc) that the extension is implemented for. You can include more than one platform implementation in a single ANE package. This example only includes one. The names are specified by the runtime and are hard to remember. Look them up. [add link for where to look up the platform names].

native library: the JAR file (in this case; it will be something else for iOS, for example) containing the Java code.

initializer: The class that implements FREExtension for this extension.

Now that we have the three pieces of the native extension puzzle, we can create the ANE package (in the next post).

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.