Building CodenameOne iOS Apps Locally

Note: This post discusses the mechanics around building CodenameOne iOS projects locally. See my subsequent post for information about a project that automates this entire process.

I’ve been playing around with Codename One quite a bit recently, as it appears to offer enormous potential in the field of mobile development. One initial stumbling block that I had with CodenameOne was that you needed to use their build server to actually build your application. Since the code is open source, it is actually possible to build it yourself, but there were no build scripts available to automate this task, and the only instructions on how to do still required a fair bit of tinkering to get it to work.

Last month, as an exercise, I created an iOS port for CodenameOne that runs on Avian (a light-weight AOT compiler for Java), just to see if it was possible. It was indeed possible, and I was able to successfully get applications built with CodenameOne up and running using Avian on my iPhone. After some benchmarking, I found that there wasn’t a compelling performance difference between my Avian port and the XMLVM port that they are currently using on the build server. Therefore, rather than sink a lot of time into a competing port, it would be better to start working with the “official” XMLVM port for my development.

Today, as another exercise, I built an ANT target that would automate the building of a CodenameOne application for iOS on my local machine. To use it, you simply copy and paste the target into your Netbeans CodenameOne project’s build.xml, and modify some of the properties to point to the proper locations in my environment. Most of the logic is based on the build instructions that had previously posted in the CodenameOne forum.

Installation Prerequisites

You will need the following components to be in place on your system before you can use the ANT target:

After these are installed, the ANT target should work for any application you try to build.

Step 1: Checking out the CodenameOne repository

You simply need to open Terminal and check out the codename one repository. The following example creates a directory called “src” inside your home directory, and checks out codenameone in a directory named codenameone-read-only inside this src directory.

$ cd ~
$ mkdir src
$ cd src
$ svn checkout http://codenameone.googlecode.com/svn/trunk/ codenameone-read-only

At this point, the CodenameOne repository trunk will be located at ~/src/codenameone-read-only.

Step 2: Install XMLVM

The iOS Port project of the CodenameOne repository includes a copy of XMLVM that you can install if you don’t have it installed yet. It is located at:

codenameone-read-only/Ports/iOSPort/xmlvm

You can find installation instructions for XMLVM at http://xmlvm.org/documentation/

Update Dec. 14/2012: Currently you need to use the xmlvm distribution that is included inside the iOSPort directory. Installation instructions are still the same:
$ cd /path/to/codenameone-read-only/Ports/iOSPort/xmlvm
$ sudo ant
$ sudo ant install

The above instructions would install xmlvm at /usr/local/bin/xmlvm

Once you have XMLVM installed, you should be able to use the ANT target in your own projects.

Step 3: Add Build Scripts to iOSPort

The ANT target depends on a Python script to be able to add files to Xcode projects from the command line. You will need to download this buildscripts directory, and copy it into the codenameone-read-only/Ports/iOSPort directory (i.e. the final location would be

/path/to/codenameone-read-only/Ports/iOSPort/buildscripts

You can download these build scripts here

You also need to add a template for the Main application entry point into the iOSPort directory. Create a file at codenameone-read-only/Ports/iOSPort/MainStub.java with the following contents:

Adding the Ant Target to Your Project

  1. Create a CodenameOne application project in NetBeans (if you haven’t already).
  2. Open the build.xml file for your project. (e.g. you can click on the “Files” tab, then expand the tree node for your project, and double click the “build.xml” file.
  3. Paste the following snippet into the build.xml file. It can appear anywhere inside the <project>…</project> tags.
  4. Modify the codename1.repo.path property to point to the codenameone-read-only directory (i.e. where you checked out the CodenameOne repository to).
  5. Modify the xmlvm.path property to point to the XMLVM binary on your system.
  6. Modify the ant.path property to point to the ANT binary on your system.
  7. Modify the python.path property to point to the python binary on your system.

Building your Project in NetBeans

Once you have successfully added the the ANT target to your build.xml file, you should be able to build the project.

  1. Click on the “Files” tab.
  2. Right click on the “build.xml” file in your project, and select “Run Target” > “Other Targets” > “build-for-ios-device-locally”
  3. Wait. It should open Xcode with your project when it is finished building.
  4. You should be able to just run or build your project in Xcode like it is a normal iOS project. It will take some time (usually about 5 minutes per build), because XMLVM produces a couple thousand Objective-C files and includes them in the Xcode project. (Don’t worry, LLVM will strip out all unused code so that the resulting binary isn’t too big).

*Note: It doesn’t seem to like building for the simulator. You can only build for an iOS device currently. I believe this is because it includes a library, zbar, that is only compiled for arm devices (not the i386 emulator).

iOS Signing Identity & Provisioning Profile

It is worth noting that you will need to set up Xcode to use your iPhone Developer identity, or it will stop you in your tracks. You will also have to set up a provisioning profile if you are doing development builds. This was a real pain in the ** to get right (in fact it was probably harder than writing the ANT script), but there is lots of documentation on this on both the CodenameOne site and the Apple site (and all around Google too).

You’ll need to make sure that your App ID (set in Project Properties in NetBeans) will need to begin with your the unique code that your provisioning profile is set up with.

Current Limitations : Native Interfaces

This build script doesn’t currently build native interfaces that you may have developed as part of your application. Native Interfaces need to have some special glue generated at build time for them to work, and the code and specs for this glue have not been released. If you are using native interfaces, you’ll need to use the CodenameOne build server in order to access them.

I am working on replicating that glue so that Native interfaces will work in local builds, and will post it when complete. An inability to develop native interfaces locally is a major impediment to being able to contribute to the CodenameOne project. It is critical that *all* build functions can be performed locally or I fear that it will be difficult for a community to form around this wonderful project.

More Thoughts on Avian vs XMLVM for iOS

I’ve only been using CodenameOne for a couple of weeks now, and I’ve been experimenting with both Avian and XMLVM on iOS. As I mentioned above, the fact that XMLVM actually outperforms Avian on many benchmarks means that I may not pursue the Avian port much further. However there are a few aspects of using Avian that have come to my attention in the short time that I’ve been playing with CodenameOne:

  1. Debugging and Stack Traces are better on Avian. XMLVM currently isn’t a whole lot of help if you run across an exception. It states that stack traces are currently unavailable and simply prints the error message. Avian, on the other hand, will give you a full stack trace, which makes it easy to debug problems.
  2. A full Java runtime environment. In XMLVM there are a few things that don’t work the way you expect if you’re used to the Java runtime environment. E.g. I was trying to print debugging information to the console using the familiar System.out.println() only to find out that this doesn’t seem to output anything in XMLVM. (Not sure if there’s anything special I need to do to get this working). Also, things like loading resources from Jar files using Class.getResource() and Class.getResourceAsStream() don’t work on XMLVM. You need to use equivalents from the CodenameOne API which are thin wrappers over native methods that do the same thing.
  3. Well that’s all I have come up with so far..

Building Locally vs Sending to the CodenameOne build server

It is important for me to be able to build my CodenameOne projects locally because I want to start contributing to the project and I need to be able to test my changes to the CodenameOne core without sending them into Shai to add to the build server. However, for production releases, I still recommend using the build server. They have taken the time to sort of all of the kinks and add many optimizations that I just don’t have time to work out. Their build server is also a bit faster than building locally.

comments powered by Disqus