Bind Objective-C
/Swift
and Java
/JNI
code to Haxe without writing glue code manually.
🚨 Warning: this library is in active development! 🚨
Writing Haxe-compatible native extensions that take advantage of iOS or Android API is quite complicated, especially if you start dealing with callbacks etc... This usually implies writing a lot of difficult to grasp glue code. This glue code is definitely not what you want to care about in practice. In addition, these intermediate files, that you would write yourself, usually don't integrate well with code editors. Just try to get iOS API code completion in this file that mixes Objective-C, C++ and HXCPP FFI code to display a UIWebView instance.
The idea of bind
is to let you focus exclusively on Objective-C
/Swift
code (that you would edit with full IDE integration on Xcode) when you work on an iOS native extension for Haxe, as well as Java
code (that you would edit inside Android Studio with full completion support) when your work on an Android native extension for Haxe. These Objective-C
/Swift
/Java
code files could even be used without Haxe
first, allowing you to test them separately etc...
Then, bind
utility will take your Objective-C
/Swift
code or Java
code as input and generate all intermediate glue code to make the same classes, methods and properties usable from a clean Haxe interface with types converted automatically.
In other words, use the best tools for each part: Xcode to make iOS code, Android Studio to make Android code and VSCode (or your other favourite Haxe editor) to make Haxe code that uses your iOS/Android bound code.
haxelib run bind objc NSSomeObjcHeader.h --namespace some::namespace --package some.haxe.pack --objc-prefix NS
haxelib run bind java some/package/SomeJavaClassFile.java --namespace some::namespace --package some.haxe.pack
You can use bind
utility to simply parse an Objective-C
header to list its classes, methods and properties and output them as JSON.
haxelib run bind objc SomeObjcHeader.h [SomeOtherObjcHeader.h ...] --json --parse-only --pretty
This --parse-only
option also work on java files
haxelib run bind run bind java some/package/SomeJavaClassFile.java [SomeOtherJavaFile.java ...] --json --parse-only --pretty
This bind
library is not a full-featured Objective-C/Swift or Java to Haxe converter. Its approach is pragmatic and is intended to be used on a clean and portable subset of Objective-C header syntax (iOS) or a clean an portable subset of Java syntax (Android) that acts as a public bridge/interface to all your native iOS/Android API.
Nothing is written to disk by default. The output is simply returned by the command. You can add a --json
argument to get output as JSON (file paths and contents), in order to integrate this into your own tool or add --export your/export/path
to let bind
save files to this export
directory.
Check out an example of bound Objective-C header that you can use as reference to see which subset of Objective-C can be handled by bind
. This file can be tested with the provided sample iOS/Objective-C project.
These are the Objective-C types that bind
utility can understand and convert to a corresponding Haxe type.
Objective-C Type | Haxe Type |
---|---|
NSString* | String |
CGFloat/float | Float |
NSInteger/int | Int |
BOOL/bool | Bool |
NSArray | Array |
NSDictionary | Dynamic (anonymous structure) |
typed ObjC Block | typed Haxe function |
You can check out The iOS Sample project which contains:
Haxe
project that can be compiled with build.hxml
C++
, generate bindings and run the result as an iOS AppC++
to iOS binaries, to generate bindingsObjective-C
Language bound to Haxe
Swift
Language bound to Haxe
through an Objective-C
compatible dynamic frameworkThis will obviously only work on a mac, with haxe, bind library and xcode properly installed.
Check out an example of bound Java class file that you can use as reference to see which subset of Java can be handled by bind
. This file can be tested with the provided sample Java
/Android
project.
These are the Java types that bind
utility can understand and convert to a corresponding Haxe type.
Java Type | Haxe Type |
---|---|
String | String |
Float/float | Float |
Int/int | Int |
Boolean/boolean | Bool |
List | Array |
Map | Dynamic (anonymous structure) |
Runnable/Func0 |
Void->Void function |
FuncN<A1,A2...,T> | A1->A2...->T function |
While it is totally possible (and showcased in the sample project) to run Haxe
/C++
in the same thread as Android's main UI thread, it is common to run it in a separate thread. For instance, this does happen when running an OpenGL ES app on Android: Haxe code is executed on Android's GLSurfaceView thread, which is not the same as the main UI thread.
The bindings generated by bind
utility can take care of switching to the correct thread as needed when passing values between Haxe and Java. To do so, an instance of android.os.Handler
or android.opengl.GLSurfaceView
used to execute Haxe
/C++
can be provided to bind.Support
(see bind.Support.setNativeThreadHandler()
and bind.Support.setGLSurfaceView()
). This can be tested in the sample project by setting MainActivity.HAXE_IN_BACKGROUND
to true
or false
. As all this thread handling is managed by the generated glue code, you should not have to care much about it. Just keep in mind that if Haxe is executed in a background thread, its thread need to wait for Android's UI thread everytime you are doing a synchronous call from Haxe to Java that has a non-void return value.
Bindings can also cope with more custom setups where the thread is not a GLSurfaceView
thread or doesn't have an Android
Looper
, like it is the case on SDL2
apps. By calling bind.Support.setUseNativeRunnableStack(true)
it will make Java
side notify JNI
/Native
side from Android
's UI Thread, when there are some Runnable
instances that need to be called from Haxe
thread. But note that this requires some more setup on Haxe
side: it needs to call bind.java.Support.flushRunnables()
regularly (at game frame update, likely), to call Java
back from the correct native thread and let it execute the awaiting Runnable
instances. Android sample project doesn't showcase this setup, but it is planned to provide a real world example of this later.
In general, you should anyway minimise the number of calls between Haxe and Java as this is an expensive operation.
You can check out The Android Sample project which contains:
Haxe
project that can be compiled with build.hxml
C++
, generate bindings and run the result as an Android AppC++
to Android binaries, to generate bindingsJava
Language bound to Haxe
through JNIThis currently only works on Unix-based systems (Mac/Linux), with haxe, bind library and Android SDK properly installed. Project will also work on Windows in the future.
Objective-C
classes, with methods, properties and comments in header filesObjective-C
blocks as Haxe functions in class methods and propertiesObjective-C
typedefs, including block types in typedefsC++
) to Objective-C
bindings from parsed informationsObjective-C
bindings and a sample Xcode
/iOS
projectSwift
(through Objective-C
compatible dynamic frameworks)Java
classes, with methods, properties and comments in java filesC++
) to Java
/JNI
bindings from parsed informationsAndroid
events through bind.Support
bind.json
file format allowing to create iOS
/Android
extensions with external dependenciesObjective-C
+ Java
/JNI
bindings having the same methods and properties