Libgdx on iOS, days 1-2
I’ve started working on the iOS port of libgdx again. Instead of Avian, we are now going to use MonoTouch. This means you’ll have to shell out 399$ for a license for MonoTouch. You’ll also need a Mac and a device, and you’ll have to sign up with Apple for another 99$.
There are alternative ways to do things though, see mac in the cloud, a remote Mac rental service, which has MonoTouch licenses installed. I’m not sure if that licensing allows you to publish, but it can be a cheap way to test whether your app works on the iOS simulator, without having to shell out the money to develop for this golden, walled garden.
On to the technical details. MonoTouch is a full stack to develop iOS applications on top of Mono. Mono is an open-source implementation of Microsoft’s .NET platform, with C# being one of the most used languages (there are others, like F# that look really promising). You write your application in C#, usually in MonoDevelop, and IDE on top of Mono. Almost all native iOS APIs are exposed through C# wrappers, so you never have to touch Objective-C.
So, how do you get Java running on that platform? A year ago i experimented with IKVM. IKVM is an amazing project that lets you compile your Java bytecode to the CLR of .NET/Mono and adds full interoperability as well as a JRE implementation. It’s an extremely huge effort that’s been long in the making, check out their project page.
Now, if you clicked on the link in the last paragraph, you saw that libgdx already works with C# on .NET/Mono. Getting this to work on iOS via MonoTouch is a different beast. On iOS things need to be compiled to native code, which Mono does if you purchase a MonoTouch license. Mono supports different so called profiles, each supports a specific set of features, like runtime libraries or reflection support. IKVM relies on a few features of the desktop profiles that Mono for iOS does not support. To make IKVM work on iOS one has to solve those issues by modifying IKVM itself.
This is the part were i rely on Michael Bayne of Three Rings. He was one of the developers of Spiral Knights, a quite successful Java game. He’s currently working with the PlayN team (actually, he seems to BE the PlayN team at the moment), heavily improving it and bringing it to new platforms. One of those platforms is iOS. He modified IKVM to be compatible with Mono’s iOS profile and put his changes on Github. The only “challenge” i had to solve was to also support JNI, which PlayN doesn’t need at the moment. A fork and a pull request later, that was solved as well, and development of the libgdx iOS backend started. TL;DR: thanks to Michael for his fantastic work on porting IKVM to MonoTouch, without that we wouldn’t be able to do what we are currently trying to do.
Now, what challenges are involved in getting libgdx to work on iOS? Here’s a small list of things i’ll try to work on over the next few days:
Project Structure (Done)
The first step was to setup a somewhat sane project structure that allows me to write the backend in Eclipse, and only switch to MonoTouch for compilation. The end result can be found here. There is an Eclipse project containing the backend Java code (see src/ folder). Then there’s the XCode project that’s responsible for producing the libgdx.a library file, containing all our precious native code. Finally, there’s a MonoTouch project that pulls all those things together and lets me easily test changes to the backend. It has a pre-built step that makes sure that the latest Java code is used when building for iOS.
The libs/ folder contains all the IKVM tools necessary for compiling Java code to the CLR, plus Jar files that wrap Objective-C libraries, generated from the MonoTouch C# wrappers through IKVM.
Bare-bones Life-Cycle (Done, Sorta)
After the project structure was in place i could start working on a bare bones implementation of the backend. All it does is setup the application and GL surface to render to as well as logging facilities. The life-cycle handling is not a 100% sound yet (pause/resume anyone?), i have still to figure out how to map the iOS way of things to our API.
The next step is to implement the Input interface for iOS. It looks like that should be smooth sailing, and we can have all file types (internal, classpath, local, external, absolute). For reference, here’s the official documentation on the matter, and the corresponding MonoTouch docs. Since IKVM gives access to java.io we can reuse almost all of the stuff in our standard FileHandle class, which relies heavily on InputStreams and File.
MonoTouch has a wrapper for the native OpenGL ES bindings called OpenTK (also available on the desktop). For us, that’s pretty much useless so i’ll have to write my own wrapper. Thankfully, that thing already exists for Android, and it’s very simple to port it to iOS. The only thing i need to change is to not rely on Harmony’s buffer internals (see top of this), something i already did for our deprecated Angle backend.
This seems to be pretty straight forward, iOS touch APIs seem a tad bit less fucked up than the Android equivalent. Keyboard input will be interesting to explore, i don’t anticipate any big issues here though (and that will probably bite me in the ass ).
This is the biggest unknown for me so far. iOS supports OpenAL and has an API similar to Android’s MediaPlayer. Using OpenAL means to do all the format decoding on our own, something i’d rather avoid. It would be the number #1 way to implement AudioDevice and AudioRecorder as well as playing back in-memory sound effects. The MediaPlayer like API is probably unsuitable for sound effects. I’ll try to hunt down a nice audio library for iOS instead.
This weekend i’ll try to finish off at least the file i/o and graphics part of the backend. For now i’ll focus on GLES 2.0, writting a wrapper for GLES 1.x could be bootstrapped via some Android source, it’s not a top priority for me though.
Here’s a screenshot if text is not cool enough. It just shows MonoDevelop, some output testing native code and the simulator running a very simple ApplicationListener that still uses OpenTK for rendering.