OpenFL Extensions haxe android插件技术

For the most part, OpenFL does an excellent job of providing you with the features you need in a platform-independent manner. It tells you the screen size, loads your assets, and even maps Android’s back button to the escape key.

Unfortunately, the OpenFL dev team cannot think of everything. Maybe you want to adjust the screen brightness on Android. Or the music volume. Maybe you want access to the camera on iOS. Or maybe you need to integrate a custom library used internally at your company, which the OpenFL dev team could not possibly have integrated for you.

For simplicity, I’ll be using screen brightness as an example. Setting this can be done in only 1-3 lines of code on both iOS and Android. The catch is, neither of those examples are in Haxe, and there’s no way to convert them to Haxe. If only you’d written the app “normally” rather than using OpenFL, you could just copy-paste those few lines of code, and you’d be done! But no, you wanted luxuries like cross-platform compilation, and now you have to somehow use Haxe code to invoke functions in Objective-C and Java.

Fun Fact

Did you know, when you compile for Android, OpenFL creates a complete, self-contained Android project, and then tells the Android SDK to compile that? And when compiling for iOS, it creates an Xcode project, and then has Xcode do the remaining work?

You can see for yourself by checking your output folder (probably eitherbin or Export; I’ll assume the former). Dig into bin/android/bin, and you’ll find all the files and folders you’d expect to find in a normal Android project. You could even, if you felt bold enough, modify the project, and compile it directly using the Android SDK. (Warning: Don’t actually do this! OpenFL will almost certainly overwrite your changes.)

The same applies to iOS – after compiling, you can check outbin/ios/bin to see the project that OpenFL created. You could try modifying this too, but again, OpenFL is going to revert your changes. There has to be a better way.

Creating an Extension

The OpenFL team is well aware of this problem, and in their infinite wisdom they created the “extension” feature. Also in their infinite wisdom, they wrote no documentation whatsoever before moving on to the next feature.

Extensions are basically mini-projects consisting of native (or Java) code, as well as Haxe bindings. You include them in your project, and then you can call the native (or Java) code by calling the Haxe bindings. Let’s look at an example.

Start by running the following:

$ lime create extension SetBrightness

I’m calling it “SetBrightness” because that’s all we’ll be doing here. You can call it something else.

Let’s take a look at the default extension. (Note: the tree command only works this way on Windows, sorry.)

>tree SetBrightness /F
SetBrightness
│   haxelib.json
│   include.xml
│   SetBrightness.hx
│
├───dependencies
│   └───android
│       │   AndroidManifest.xml
│       │   build.xml
│       │   project.properties
│       │
│       └───src
│           └───org
│               └───haxe
│                   └───extension
│                           SetBrightness.java
│
├───ndll
│   ├───Linux
│   ├───Linux64
│   ├───Mac
│   ├───Mac64
│   └───Windows
└───project
│   Build.xml
│
├───common
│       ExternalInterface.cpp
│       SetBrightness.cpp
│
└───include
Utils.h

Let’s break this down a little.

  • SetBrightness.hx – Contains Haxe bindings for your native (and Java) functions. Currently everything in here is sample code, but it serves as a useful template.
  • SetBrightness.java – Where your Java code goes. This will only be included on Android. Again, this is just sample code at the moment.
  • SetBrightness.cpp – Where your C++ code goes. (Contains even more sample code.) This will be included on both Android and iOS, but there’s no good reason to use it on Android.
  • ExternalInterface.cpp – An intermediate step between your SetBrightness.cpp and SetBrightness.hx. You’ll need to update this each time you add, remove, or rename a C++ function.
  • Utils.h – You also need to update this every time you change your C++ code. (Sheesh, why isn’t this automated?)
  • Build.xml – Controls how this extension will be compiled. If you rename one of the .cpp files, you’ll need to update it here.

Everything else can be left alone for now.

Writing Code for Android

Click through all the folders under dependencies/ until you reach SetBrightness.java. Add the following code:

public static void setBrightness(float brightness) {
    WindowManager.LayoutParams layout = Extension.mainActivity.getWindow().getAttributes();
    layout.screenBrightness = brightness;
    Extension.mainActivity.getWindow().setAttributes(layout);
}

That’s all well and good, but how do you call this function? The answer… is JNIDramatic thunder crashes Actually, it’s not that bad if you’re only dealing with one function. Climb your way back to the rootSetBrightness/ folder, and add this to SetBrightness.hx:

#if android
public static function setBrightness(brightness:Float):Void {
    setbrightness_set_brightness_jni(brightness);
}
private static var setbrightness_set_brightness_jni = JNI.createStaticMethod("org.haxe.extension.SetBrightness", "setBrightness", "(F)V");
#end

That’s still a little much. Fortunately, shoe[box] came up with an easier way. Start by including the “inthebox-macros” library in your project, change the package in SetBrightness.hx to org.haxe.extension, and add@:build(ShortCuts.mirrors()) just before the class declaration. Now the code above can be replaced with this:

#if android
@JNI public static function setBrightness(brightness:Float):Void;
#end

All that’s left is to include the extension in your project (see below), and you can call SetBrightness.setBrightness(0.8); from Haxe.

Well, on Android at least. Let’s get it working on iOS too.

[Edit: Wait, there’s one more thing. You aren’t compiling an ndll for Android, but by default Lime expects you to. To fix the error, go into include.xml and replace <ndll name="SetBrightness" /> with <ndll name="SetBrightness" unless="android" />.]

Writing Code for iOS

You’ll notice that the extension is set up for C++ code, but to access system properties like brightness, you need to use Objective-C code. Fortunately, this part’s easy: just change the .cpp file extensions to .mm. You’ll also need to update their names in Build.xml. And because Objective-C is specific to iOS, I suggest disabling them for everything else.

<compilerflag value="-Iinclude" if="iphone"/>

<file name="common/ExternalInterface.mm" if="iphone"/>
<file name="common/SetBrightness.mm" if="iphone"/>

If for some reason you do need C++ functions on other platforms, you can add similar tags for that, except with unless="iphone".

Now to write some actual Objective-C code! Put this in SetBrightness.mm:

void setBrightness(float brightness) {
    [[UIScreen mainScreen] setBrightness:brightness];
}

Now update Utils.h:

void setBrightness(float brightness);

Don’t forget to update ExternalInterface.mm:

static void setbrightness_setBrightness (value brightness) {
    setBrightness(val_float(brightness));
}
DEFINE_PRIM (setbrightness_set_brightness, 1);

Last but not least, create the Haxe bindings in SetBrightness.hx:

#if ios
public static function setBrightness(brightness:Float):Void {
    setbrightness_set_brightness(brightness);
}
private static var setbrightness_set_brightness = Lib.load ("setbrightness", "setbrightness_set_brightness", 1);
#end

Phew! That was a lot of updating. [Edit: inthebox-macros can generate the Haxe code, and I wrote a utility to generate ExternalInterface.mm and Build.xml.]

Time to compile!

$ lime rebuild . ios

Including the Extension

Almost done! All that’s left is to include it in your project.

This can actually be done in two ways. The easy way works if you’re only using one machine, or if the relative path is the same on all machines (for example, if the extension project is contained within your main project). All you have to do is add this to your project.xml or application.xml file:

<include path="path/to/SetBrightness" />

The slightly harder way is to register it with Haxelib by running the following from the root of the extension:

$ haxelib dev SetBrightness .

Then include it:

<haxelib name="SetBrightness" />


发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

(Spamcheck Enabled)

最新评论