From iOS to Android using SDL


As the title, and the image below, explains in this post I'll try to explain the basics about porting a C/C++ game that uses SDL from iOS to Android.

The game I'm referring is Eat the Whistle, I've already written a few posts about how I ported it from desktop to mobile here, here and here. So this post will focus on the iOS / Android differences.


uploaded_image


The details, as usual, are after the break...


As most of the readers intrested enough to this to click "read all" knows, the basic difference between Android and iOS is that the default development system for Android is Java based and does not allow to use languages that compile in native code.

Google anyway has given us another SDK to develop native applications that is called NDK (you can get it here) that permits native development using C/C++ (and also inline asm if wanted...).

To use the NDK you need to install also the SDK (that you can download here), you do not need Eclipse, so you can get the (smaller) version that do not provide the IDE.

I don't know how the setup of the SDK/NDK works on Windows, but all you have to do in linux and OSX is to unpack both archives somewhere add the following paths to your enviroment (.bashrc or .bash_profile):

  • path_where_you_unpacked_sdk/tools
  • path_where_you_unpacked_sdk/platform-tools
  • path_where_you_unpacked_NDK


The compilation of the application will be in two steps, the first step will compile native sources, you'll perform it with ndk-build.

The second step will compile your java support files and will pack your assets inside the apk, you can use eclipse to do this, but I found far more efficient do also this step from the command line using ant.

SDL does offer a skeleton android application that I suggest you to use as base for your project. The skeleton app contains all the files used for both build systems (ndk-build and ant) that you'll need to modify to suit your needs.

Your sources have to be placed in jni/src, or as I did, you can make that directory a link to where your sources really are, SVN will check in the links and at least on linux and osx this works without issues. The jni directory should contain also the sources of the other libraries you need to link, so SDL, and in my game also SDL_mixer and tremor (for ogg playback). Every module you insert needs to have an Android.mk file describing the files that have to be compiled, the compiler options and the additional paths for headers, the format is quite simple and if you know how to use a Makefile you'll find yourself at home.

You can use the link trick also for your assets, that should be placed in... assets.

The directory src contains the java sources, that are organized using the name identifier of your app.

In my case the identifier is etw.ggsoft.org, so my java sources have to be placed in src/org/ggsoft/etw.

In the main directory there is a file called AndroidManifest.xml, this file is very important since it defines your application identifier and what your application needs (in term of device features and permissions).

If your project uses C++ remember to add the following line to jni/Application.mk:

APP_STL := stlport_static

... this will save you a google search :)

The main work you'll have to do to adapt the SDL skeleton project to be your REAL project is to modify the references from org.libsdl.app to your app identifier.

You can do it in two ways, the hardest, and the one I've chosen, is to move the SDLActivity.java provided by SDL in my hiearchy (src/org/ggsoft/etw) and to change his identification in org.ggsoft.etw (the package statement specify this).

That gave me the advantage of being able to change the app layout from AbsoluteLayout to RelativeLayout (better for AdMob support), but doing this I've had to build a glue module for JNI bindings.

The problem of this approach is that JNI bindings use the package name to find the native function name to be called, so if you define in your java activity (with package identifier org.ggsoft.etw):

public static native void nativeKeyDown(int code);

You'll have to define a C glue function like that:


void Java_org_ggsoft_etw_SDLActivity_onNativeKeyDown(JNIEnv* env, jclass jcls, jint keycode)
{
extern void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env, jclass jcls, jint keycode);
Java_org_libsdl_app_SDLActivity_onNativeKeyDown(env, jcls, keycode);
}



This is mandatory because Java_org_libsdl_app_SDLActivity_onNativeKeyDown is defined inside libSDL2.so.

The alternative is to keep SDLActivity.java untouched in your project and extends it with a custom activity with your package identifier. You'll loose something in flexibility (you cannot change the layout method for instance), but you will not have to create glue functions.

Whenever choice you'll take you'll have another problem in android: access your assets.

Differently from OSX assets of Android applications are not unpacked, but are kept inside the APK, to access them you have an object called AssetManager, this object can only be created in the Java code, but can be accessed also through your native program using AAssetManager_fromJava. You can get an ANSI FILE handler to an object inside the assets, but you can not use fread() to read it, nor you can trust feof(), the file can be compressed, and the FILE handle is the handler of the whole APK package and not of the single asset!!!

So what I did, in the spirit of keeping the code as platform indipendent as possible, was to change my os_open() function (that I used instead of fopen() to support both sensitive and insensitive file systems) to try to extract on the application local storage space the assets that the game needs, the details of this implementation are in os_init.c.

Please note that if you use SDL_rwops to access your assets you do not need this, because the SDL Android port already uses AssetsManager calls inside SDL_Rwops callbacks. Also note that SDL2_Mixer, SDL2_ttf and SDL2_Image internally use SDL_Rwops so they can load compressed assets without particular tricks.

As usual the sources of the game are available here, the relevant parts about Android are in the subdirectory android-project. This source tree builds without changes on OSX and Linux.

In the next article I'll talk about the different business model I've choose for iOS and Android versions, and will add some details about the native to java interface (you will need to call java methods to do things like In App Billing and Advertising


Article published on: GGSoft start page - http://www.ggsoft.org/
Reference URL: http://www.ggsoft.org/index.php?mod=read&id=1361981509