Building a Native Extension | Part 4 – The Android Code

Building the Android library was very interesting.  It was easier for me to write Java as it was more similar to ActionScript.  Some amount of debugging (log statements) is actually possible with zero work on the developer’s part which is a great addition (more on that later).  Also, using the AIR runtime extensions in Java is a much simpler process.  However, the Android operating system leaves a lot of work up to the developers, and you’ll find that some functionality is built into the iOS framework but that a solution will need to be built from scratch for Android.

The Android Library

Creating the Android library is pretty straight forward.  If you haven’t already, you should download the Android SDK and install the ADT Eclipse plugin into a plain copy of eclipse (not Flash Builder).  (You probably can install the ADT plugin into Flash Builder, but I personally found it easier to just keep them separate.)

1.  Open Eclipse and create a new Android project.  Name it whatever you want and choose the minimum SDK you wish to support.  Chances are you’ll want to pick 2.2 (the first version of Android that AIR supports).

2.  The AIR runtime extensions need to be added to the project.

Right click on the project and go to “properties”.

Click on the “Java Build Path” item and go to the “Libraries” tab.

Click on “Add External JARs” and navigate to the directory air_sdk_dirlibandroid.  Select the FlashRuntimeExtensions.jar file.

Press “OK”.

3.  Create a class that implements FREExtension.  The package and name for this class should match the initializer node for the Android-ARM platform in the extension.xml file. This class should have the methods createContext(), dispose(), and initialize().

The createContext() method accepts a string parameter which is the type of context to create.  This is the second parameter passed to the ExtensionContext.createExtensionContext() method.  The return value for createContext() should be a class that extends FREContext.

[sourcecode language=”java”]
public FREContext createContext(String contextType) {
return new VolumeExtensionContext();
}
[/sourcecode]

The dispose() method will be called when the native extension is done being used by the developer.  Here you should do any clean up required.

The initialize() method is called when the native extension is finished being built.

4.  Create a class that extends FREContext.  This class should have the methods dispose() and getFunctions().

The dispose() method is just like the dispose method of the FREExtension.

The getFunctions() method returns a collection of FREFunction objects.  There should be one FREFunction for each method that is called from the main ActionScript library.  Each FREFunction is mapped to a string value, which is the name of the function.

[sourcecode class=”java”]
public Map<String, FREFunction> getFunctions() {
Map<String, FREFunction> functions = new HashMap<String, FREFunction>();

functions.put("init", new InitFunction());
functions.put("setVolume", new SetVolumeFunction());

return functions;
}
[/sourcecode]

5.  Create one class that implements FREFunction for each method invoked from the main ActionScript library.

These classes will each have a call() method.  This method is invoked when the function is called from the main ActionScript library.  This is where the heavy lifting happens in the native extension.  This is the place where you’ll add the native code to do whatever it is that your native extension does.

The call() method is passed an FREContext and an array of FREObject instances.  The FREContext is the extension context used to invoke the method.  The array of FREObject instances is a collection of the parameters passed to the method; one FREObject for each parameter.

FREObject is a java representation of an ActionScript object.  It is a wrapper class, so to get to the underlying value you must invoke methods of FREObject.  For example, in the setVolume() method we pull out the Number value that is the new volume.

[sourcecode class=”java” highlight=”7″]
public FREObject call(FREContext context, FREObject[] args) {
Context appContext = context.getActivity().getApplicationContext();
AudioManager aManager = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);

double volume = 1;
try {
volume = args[0].getAsDouble();
} catch (Exception e) {

}

int maxVolume = aManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
volume = volume * maxVolume;
int index = (int) volume;

aManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);

return null;
}
[/sourcecode]

The bolded line is where the value passed from ActionScript is extracted from the FREObject collection.

6.  Create the jar file.

Right click the on the Android project and select ‘Export’.  Expand the ‘Java’ item and select ‘JAR file’.  Be sure the project you’re exporting is checked in the “Select resources to export:” box.  Choose where to save the jar file and click Finish.

 

A note about debugging:

Similar to the console in Xcode, the Android Eclipse IDE provides a way to log out to a console.  You won’t be able to hit breakpoints but you can see log statements from the native code.

When using Log.d(TAG, String); statements the output will show up in the LogCat console when the AIR application using the extension is running on the device and the device is plugged in via usb.

How to open the LogCat window: While Eclipse is running, select the “Window” menu option. Then navigate to “Show View” -> “Other”. Expand the “Android” item and then select the “LogCat” item. Press “OK”.

The LogCat window shows all of the logging happening on the device, so you will want to filter (by pressing the green plus sign) by tag to see only your specific logging.

Continue to part 5

There are no comments.

Leave a Reply