Fixnum.org

Latest update: Please wait, fetching tweets ...

Recent posts

Using the Android NDK

Written on Saturday 23/01/2010 at 09:24

A few months ago I was looking to replace my Nokia E61 because the battery was getting pretty unreliable. I ended up buying a T-Mobile G1 (or HTC Dream, whichever you prefer), because they were cheap at that time, due to the then-recent release of the HTC Magic. Ironically, the G1’s battery life is even worse than the Nokia with a near-dead battery, but that's not the point. The point is I had a mobile phone with an open operating system and a toolkit for Linux.

If you’ve used Android, you’ll know that while performance is OK, it does tend to choke from time to time. This ‘choking’ is attributed to the garbage collection of the Dalvik virtual machine. While this is acceptable (but still quite annoying) for normal applications, it is a dealbreaker for highly interactive applications such as games. Google is not oblivious to this problem, and has released an NDK, or native development kit, to complement their Java-based SDK. This allows developers to write performance critical parts of their application in C or C++, and use that from Java using something called JNI.

I wanted to try this out, but I failed to find any up-to-date tutorial on the subject. After quite a bit of trying, I did get it working though. I thought I’d share my experience with the world, so if anyone else wanted to get started with the Android NDK, they’d have a smoother start.

I write my code without Eclipse and the Android plugin for it, but I’ll be explaining things for both command-line junkies like myself and Eclipse users, like the majority of Android developers. I’ve tested the Eclipse instructions on Windows, but it should work fine on Mac and Linux as well. The Command line instructions will only work on Mac or Linux, or on Windows if you use Cygwin.

Step 0: Download and install the SDK and NDK

I’m assuming you’ve already done this. Installing the NDK simply means extracting it somewhere you can easily reach from the command line or terminal.

Step 1: Create a project

Create a project like you normally would. For Eclipse users, this would be through the "New Project" wizard. For command line users, you’d run something like:

android create project --target 2 --name Demo --path project_folder --activity DemoActivity --package your.pkg.name

Nothing new so far if you’ve build normal Android applications before.

Step 2: Make your project visible to the NDK

The development kit requires your application to be in the apps directory of your NDK’s install path. Since Eclipse is most comfortable with handling your code in the workspace directory, I recommend you make a symbolic link. Even if you don’t use Eclipse, you’ll probably want to put your code somewhere other than the NDK install path.

First you’ll have to create a directory to hold your project and makefiles under the apps directory. Call it anything you like, I’ll be referring to it as “the application folder” from here on in. I’m calling it demo_app for this tutorial. Once you've done that, you need to create a symbolic link named project inside this directory pointing to your Android project’s directory. On a Linux or Mac system, type the following into your terminal while in the application folder:

ln -s /full/path/to/android/project project

On Windows, you can do the same by using the linkd command:

linkd project full\path\to\android\project

You should also create a jni directory in project:

mkdir project/jni

Step 3: Add native references to your Java code

You need to add some references to your JNI code in the generate Java code. I’ve highlighted the required changes to DemoActivity.java.

package your.pkg.name;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class DemoActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
         Log.i("---DEMO---", "Return value from native lib: " +
                                          getString());
    }

    public native String getString();

    static {
           System.loadLibrary("native_lib_name");
    }
}

Step 4: Build Java code and generate header files

Ok, so this really is more like two steps, but they’re so simple it would be embarassing not to combine them. If you’re using Eclipse, building is most likely done automatically for you. To compile your Java code from the command line, move into your project folder and type

ant compile

You should now have a nice set of Java .class files in the bin directory of your project. Move your terminal over to bin/classes, and generate header files for your native method calls like this:

 javah -jni your.pkg.name.DemoActivity

This should get you a header file called your_pkg_name_DemoActivity.h. Move this over to the jni directory created earlier:

 mv your_pkg_name_DemoActivity.h ../../jni

Step 5: Implement the header files

Next, you'll need to create a C file in the jni directory, implementing the header created earlier. I’ve named it DemoActivity.c, and it looks like this:

#include "your_pkg_name_DemoActivity.h"

JNIEXPORT jstring JNICALL Java_your_pkg_name_DemoActivity_getString
(JNIEnv * env, jobject obj)
{
    return (*env)->NewStringUTF(env, "Complex string calculated in native code");
}

The details here are about JNI, not the Android NDK, so if you have any troubles here, look for a JNI tutorial. I don't know much about JNI myself.

Step 6: Create makefiles

Now, I know makefiles can be somewhat scary, but don't worry about it. You only need to edit the obvious names here, not write your own rules. For native Android extions, you'll need two makefiles.

The first should be in the application directory, which I named demo_app earlier, and the file should be called Application.mk. It looks like this:

APP_PROJECT_PATH := $(call my-dir)/project
APP_MODULES      := native_lib_name

The second should be create in the jni folder with your C source code and header files, be called Android.mk and look somewhate like this:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := native_lib_name
LOCAL_SRC_FILES := DemoActivity.c

include $(BUILD_SHARED_LIBRARY)

That’s all you need to do. The NDK’s main makefile will take care of the rest.

Step 7: Build the native code

To build the native code, move your terminal to the root of the Android NDK’s install path. This should be two directories below the application directory, and run:

make APP=demo_app

Obviously, you’ll need to replace the demo_app with whatever you named your application directory earlier. Output should look something like this:

Android NDK: Building for application 'demo_app'    
Compile thumb  : native_lib_name <= apps/demo_app/project/jni/DemoActivity.c
SharedLibrary  : libnative_lib_name.so
Install        : libnative_lib_name.so => apps/demo_app/project/libs/armeabi

Step 8: Build the Android application

You now need to rebuild and repackage the entire application to include your native library. If you’re using Eclipse, simply press run. For command line user, you need to run another ant task in the project folder:

ant debug

If you want to install the application from the command line as well, run ant install too. To see what messages are being logged, run adb logcat.

Now you can run the application, and in the logs, you should read a wonderful message like this:

I/---DEMO---(  198): Return value from native lib: Complex string calculated in native code

That’s it. Feel free to leave a comment if you have any questions or run into problems.

Twitsy - A Twitter Client for Mobile Phones

Written on Saturday 13/06/2009 at 11:00

If you follow me on Twitter, you may have noticed that a few days ago, I released a little Twitter client, targetted at simple feature-phones (and obviously smartphones) with Java support. This means it should work on every mobile phone out there, except for the iPhone. This is what it looks like:

Screencast of Twitsy

I've been looking for a free Twitter client for my Nokia E61 for a while now, but all the Java clients are really, really limited, unusable or just ugly. I like Gravity and even considered buying it, but it's not worth the €8 (10% of the price of my phone!).

So I decided to roll my own Twitter client, it's called Twitsy and you can get it at fixnum.org/twitsy. Let me know what you think, especially if you run into trouble.

Building the E text editor on Fedora 10

Written on Sunday 19/04/2009 at 10:24

E is a brilliant text editor: it's simple, light weight, and has all the features I want from an editor. In fact, most of these were shamelessly stolen from TextMate, which is everyone's preferred editor on the Mac, but that's not the point. The people behind the E text editor have released their source code under a strange, not-quite-open-source license. While it's a shame they didn't really open source this little gem of an application, they did give us Linux users free play:

The editor could not have been build without the support of a lot of open source projects (most notably wxWidgets). So to give back, the Linux version will be totally free (as in beer).

To satisfy my addiction with block-selection in text files, I decided to download the source and try getting it to build.

Screenshot of E on my Fedora

Packages required

E depends on quite a bit of packages, most of which are missing from your average Fedora installation. E also uses a slightly modified WebKit, it seems, which in turn has a collection of dependencies you'll have to satisfy. I'm assuming you have all the required build tools installed.

To install all dependencies for E, run this as root:

yum install wxGTK-devel glib2-devel atk-devel libcurl-devel libtomcrypt-devel libtommath-devel

And in order to be able to build WebKit, you'll need to do the following:

yum install libxml2-devel libxslt-devel libsqlite3x-devel libicu-devel libjpeg-devel gperf

Bakefile

You'll also need Bakefile, a system that generates platform-specific makefiles for cross platform projects. Unfortunately, they do not provide Fedora RPMs, nor is the package available in the default repositories. You can however simply download a tarball here, and then unleash rpmbuild on the archive:

rpmbuild -ta bakefile-0.2.6.tar.gz
sudo rpm -i ~/rpmbuild/RPMS/*/bakefile-0.2.6-1.i386.rpm

Getting the source

Now we can finally download the actual E code and start building. To get the code, run:

git clone git://github.com/etexteditor/e.git

Make sure the path to the source code doesn't contain any spaces, since WebKit can't handle those.

Externals

First, we need to build all the dependencies that come with E. To download these, move into the externals and run:

./get_externals_linux.sh

Then you can go ahead and build them:

./build_externals_linux.sh debug

Building E

With all that out of the way, we can finally build E itself. Move into the src folder of the source tree (that's cd ../src if you're coming from the externals folder). One minor issue with building on Fedora is that we're using the libtomcrypt that's included in the repositories, not the one we built ourselves. Because of this, make is looking in all the wrong places to find the include files, but a small modification to the Makefile will set that straight. So fire up your favourite editor, open Makefile and look for a line like this:

INCLUDES = $(WXINCLUDES) $(OURINCLUDES) $(GTKINCLUDES) -I../ecore -I.

and change it to:

INCLUDES = $(WXINCLUDES) $(OURINCLUDES) $(GTKINCLUDES) -I../ecore -I. -I/usr/include/tomcrypt

There's also a bug I found and fixed (details), which stops E from displaying most files in the Project Pane. To fix it just run:

wget http://fixnum.org/public/e/projectpane_icons_fix.patch
patch -p1 projectpane_icons_fix.patch

UPDATE: This is no longer needed, E now builds fine with the libtomcrypt found in the externals directory and this patch (and many more I and other people made) have been merged into the master tree.

And now we're finally ready to start the actual building:

make DEBUG=1

So now you have a fine, shiny E binary that listens to the name e.debug. It's a healthy little baby, but a little on the chubby side, weighing in at 256MB. To trim it to 25MB, you can use strip, which removes a bunch of debugging information:

strip e.debug -o e.stripped

And then it all comes crashing down

Now when you fire E up, it greets you with a nice "assertion failed" dialog window. No big deal, you think, clicking continue to get rid of it. But whenever you type something in the editor area, you get another one. At first, I was a bit startled by this, and thought it was just plain broken. However, it turns out that it's just because E doesn't have any language bundles installed, and the syntax highlighting can't handle not finding any bundles. You'll also need some themes, if you want your code to look all shiny and colourful. I've uploaded a tarball with all themes and bundles available, to install all this, run:

wget http://fixnum.org/public/e/e-bundles-themes.tgz
tar xzf e-bundles-themes.tgz -C ~/.e/

At this point, you should have a nice, semi-working E running on your system. Sure, you'll run into some of those nasty assertion failures from time to time, but isn't that what living on the edge is all about?

Problems? Fixes?

If you run into a problem following my instructions, or possibly even a fix for said problem, feel free let me know.