Android Beginners: NDK Setup Step by Step

Most Android developers start their learning from pure Java, Android SDK based apps. While everyone is aware that there is the NDK (the Native Development Kit), they don’t face the need to use it. Since NDK is distributed separately from the SDK, including documentations and samples, you are not likely to get familiar with NDK before you actually try it as a solution to one of your development challenges.

Because of that, many people think of NDK as of “black magic” of Android development. Many developers who are not familiar with NDK think it is 1) complex to understand and use, and at the same time a lot of developers will think it is a sort of a 2) silver bullet that can solve any problem that can’t be solved with SDK.

Well, both opinions are rather wrong, as I hope to show further in this post. Although it does have a maintenance cost and does add technical complexity to your project, NDK is not difficult to install or use in your project. And, while there are cases where NDK will be really helpful for your app, NDK has a rather limited API that’s mostly focused on several performance-critical areas, such as:

  • OpenGL, including support for some newer versions that the (Java) SDK supports
  • Math (some, but not all, calculation-intensive algorithms might benefit from being done on the native layer)
  • 2D graphics – pixelbuffer support (only starting with 2.2)
  • libc – it’s there for compatibility and perhaps to allow you to port existing native code

In this tutorial we will take our basic Android development environment that we created in one of the previous articles and add NDK support to it. We will also create a basic skeleton project that uses NDK that you can use as the foundation for your NDK-powered apps.

The downloads that are necessary for the initial configuration of the environment might take some time (around 30 minutes total), so be prepared.

Ready? Let’s go!

Step 1: Installing C/C++ Support on Eclipse

This is where we stand right after we’re done with the previous tutorial. In short, we have a basic Eclipse installation, plus Android SDK and ADT that brings Android support to Eclipse:

(we’re not going to use our old project, foobar, so you can just close it.)

While NDK supports both C and C++, C++ support is rather limited. For example, exceptions are not supported and there are some known bugs in static constructor/destructor invocations. Also, most of the time when you will use NDK as it was intended – for moving the most performance-critical parts of code to the native layer – you are not likely to need much OOP abstraction and other design goodies. What I’m trying to say is that NDK code is more likely to be written in C rather than C++.

Anyway, our Eclipse installation does not support either C or C++ right now. We don’t really need the full support, including building etc. But we would like to have syntax coloring and basic syntax checking. Thus we have to add some Eclipse features via the update mechanism, almost like when we added Android support.

Right now go to HelpInstall New Software menu item. Choose Galileo as the update site (“Work with”). Let the item tree load, and check Eclipse C/C++ Development Tools in the Programming Languages branch:

Then press Next. Say yes to everything, accept the licenses and let Eclipse finish the update. Once it is done, you will see the prompt to restart Eclipse:

Say Yes and wait for Eclipse to restart. You have C/C++ support in your Eclipse IDE now.

Step 2: Installing Cygwin

Android is Linux based, and thus it is no surprise that when you build native code for it, you need some Unix tools. On Windows, NDK supports Cygwin 1.7.x and above. If you don’t know what Cygwin is, it’s just a set of software that emulates Unix environment on Windows which is necessary in some cases, including ours.

In order to get Cygwin, go to cygwin.com:

There’s a small grey box on the right side of the page that says “Install or update Cygwin now!”. Click it, and Cygwin’s setup.exe will download and run:

Choose Install from Internet, then click Next, then choose the installation directory (be sure to choose a directory path that contains no spaces in it) – and by the way, the whole thing is going to require up to few gigs of space. Then, choose the local package directory – just use some temporary directory, you’re not likely to need it afterwards.

At this point Cygwin will connect to its central site and download the list of mirror sites. Choosing a mirror site that looks geographically close to you may save you some download time:

After you choose the mirror and click Next, Cygwin will download and present to you the list of available packages:

By default, only the base packages are installed. We, however, need the development packages. Rather than picking the packages we think we need, and then struggling with missing dependencies and other typical Unix nightmares, I suggest that we install the entire Devel branch. Click (once) on the word “Default” next to the root Devel node and wait few seconds while the setup hangs. When it is back, you will see that “Default” changes to “Install” for the Devel node, just like on the screenshot above.

Now click next and let Cygwin download the packages and install the environment:

This might take a while, so you can go have a coffee now. Or lunch if your internet connection is slow.

When you are back, you will hopefully see the final setup screen:

Allow it to create an icon on the desktop. Here’s what you will see on your desktop after you click Finish – an icon that launches the Cygwin console:

Click it once, let the Cygwin console start up and initialize:

To check that we have the tool that is important for Android NDK, type make -v in the console:

You should see the same response that tells us that GNU Make is present in our Unix environment that is emulated by Cygwin. Cool!

Note: From my own experience, Cygwin installation is often unstable and can be error-prone. If you have a specific issue, let’s discuss it in comments and I’ll try to help. Don’t go further if something is wrong at this step, since correctly installed Cygwin is a requirement for working with NDK on Windows.

Step 3: Installing the Android NDK

Our next step is to download Android NDK itself and place it on our filesystem. You can get NDK from the official Android site:

Download the NDK zip for Windows and extract it somewhere, but again, be sure that there are no spaces in the path. In my case, I extracted it to C:\, so the path is C:\android-ndk-r4.

Now we have the environment ready for our first NDK app!

Step 4: Making a Basic NDK App

The general idea of using NDK in apps is to put your native pieces of code into libraries that you can then consume from the Java code. Thus, you always start with a standard (Java) app and then add NDK pieces to it. Thus, let’s create a basic app in Eclipse as we did previously, using the New Android Project wizard:

There is, however, an important thing to check, and believe it or not, it is spaces in the path again. My Eclipse workspace is located in a directory that has spaces in it, so I had to uncheck the Use default location checkbox and manually choose a path that does not have spaces, as you can see in the screenshot above. In general, it’s better to keep Eclipse workspaces located in space-free paths.

Otherwise, there are no NDK-specific things you should do when creating the app. I allowed the wizard to create a dummy activity called NdkFooActivity that we will use later on.

After the app has been created by the wizard…

..Make a folder called jni in the root of the project (right-click the project node, NewFolder). Create a file called Android.mk (NewFile) within that folder with the following contents:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Here we give our module name and source file(s)
LOCAL_MODULE    := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c

include $(BUILD_SHARED_LIBRARY)

Except the module name (ndkfoo), treat everything in that file as magic. You can go deeper into Unix Makefiles later if you want.

The Android.mk file is important for the NDK build process to recognize your NDK modules. In our case we named our module ndkfoo and told the build tool that it consists of one source file named ndkfoo.c. Let’s create it in the same jni folder:

Here’s the content for you to copy and paste:

#include <string.h>
#include <jni.h>

jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
	return (*env)->NewStringUTF(env, "Hello from native code!");
}

Android actually uses the standard Java way to communicate with native code called JNI (Java Native Interface). It defines conventions and mechanisms that Java code and C/C++ code use to interact. You can read more about JNI in the official Sun docs, but for now you might notice that the name of the C function is not just random – it matches the Java class name. In addition, what the function does is it uses the JNIEnv object to create a Java string from a literal, and returns the string to the caller.

You will need to learn more JNI if you’re going to use NDK a lot. By the way, it is also possible to call Java methods from native code, create custom objects and so on.

Now, in order to create a binary library from the C source that we wrote, we will use a combination of Cygwin and Android NDK tools. Launch the Cygwin console and use the cd command to go directly to the folder where your project is. Notice that Windows drives are mapped under /cygdrive within the emulated Unix environment you work with in the Console console. In my case, the command line is: cd /cygdrive/c/projects/ndkfoo

Then, issue a command that will invoke the NDK build tool. In my case, since NDK is installed in C:\ it looks like this: /cygdrive/c/android-ndk-r4/ndk-build

Here’s a screenshot for you to check:

As you can notice, a successful run of the ndk-build tool will create an .so file in a new folder called libs that will be created in your project root (if it’s not there yet). The .so file is the binary library that will be included into the application .apk package and will be available for the Java code of the app to link to. You just need to hit F5 in Eclipse after selecting the project root to update the Eclipse project with the changes you did in the Cygwin console.

You have to repeat the ndk-build command every time you modify the C/C++ source of your NDK code. Eclipse ADT does not support NDK so you need to do it from the Cygwin console. Don’t forget to refresh Eclipse every time!

Anyway, the NDK part is actually finished. What we need to do now is to change the Java code of the NdkFooActivity class to use the NDK code:

package com.mindtherobot.samples.ndkfoo;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;

public class NdkFooActivity extends Activity {

	// load the library - name matches jni/Android.mk
	static {
		System.loadLibrary("ndkfoo");
	}

	// declare the native code function - must match ndkfoo.c
	private native String invokeNativeFunction();

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // this is where we call the native code
        String hello = invokeNativeFunction();

        new AlertDialog.Builder(this).setMessage(hello).show();
    }
}

As you can probably guess, this code will invoke the NDK method that will return the string, that will be displayed as an alert on the screen. Here’s the result of running the ndkfoo app on the emulator:

Congratulations! Your first NDK app is running fine.

Step 5: Be Wise and Careful

As it was mentioned above, and as you probably understand better now, NDK is not a monster and is quite easy to use in your app. However, every time you want to use NDK, please think twice and perform investigation to see how much you could actually gain from using it. Mixing C/C++ with Java is generally a bad idea from the code quality point of view, and Dalvik VM is getting faster and faster so you can avoid the NDK in many cases.

Also, be sure to read the NDK docs and learn JNI thoroughly to make sure you use NDK correctly and safely.

Otherwise, happy NDK’ing. :)

Tags: , , , , , , , ,

83 Responses to “Android Beginners: NDK Setup Step by Step”

  1. anand says:

    thank you ivan. it’s beautiful .

  2. Arpita says:

    I am getting this error after writing ‘make -v’ on Cygwin

    Perl is not recognised as external or internal command, operable or batch file.

  3. dodo says:

    Thanks for your manual.

  4. Dear ivan,

    I am so appreciated for this great tutorial, it’s working perfectly.

    I want to use Zip Archive library (written in C/C++) in android using the NDK, do i need any extra steps other than this mention here?

    Thank you so much.

  5. ivan says:

    Ahmad,

    Glad you liked the tutorial.

    Yes, you need to compile the C/C++ sources into binary. That’s after you set up the NDK environment.

    -Ivan

  6. Thank you Ivan i will give it a try and let you know, Thanks again.

  7. Dear ivan,

    i am getting an error message from the NDK telling me “Your APP_BUILD_SCRIPT points to unknown file”,

    do you have any idea how i could resolve this issue?

    Best regards,

    ahmad

  8. Parvendra says:

    Hi Ivan,

    when I am running your solution then I am getting following error

    01-15 11:41:04.164: ERROR/AndroidRuntime(288): java.lang.UnsatisfiedLinkError: invokeNativeFunction

    would you please help me to understand whats wrong with it?

    Thanks
    Parvendra

  9. sergey says:

    Thank you for post.
    It really help

  10. ivan says:

    Glad it was helpful to you Sergey.

  11. anand says:

    hi, ivan.. good morning,

    please help meeeeeeeeee…
    to dump (or) to install application into device which has OMAP 35X processor, which cross compiler (i.e toolchain), i should use

  12. anand says:

    i’m using android ndk,windows xp, eclipse-pulsar
    will you explain the functionality of that toolchain?( i knew little bit)
    thank you .

  13. chaithra says:

    I am getting an error saying command not found once i type “make -v”. Plz suggest me what to do.

  14. Cocus says:

    Hi, well, good articles, I can compile a normal Java application, but not NDK applications. I’ve followed every step, and I haven’t received any error. But when I run the ndk-build, nothing happens, and backs again to the normal bash. 0 errors. Any idea?. Thanks.

  15. Asai says:

    When I run the setup for cygwin, everything supposedly works, but the destop and start menu icons are not created. I tried reinstalling, but no luck. Do you have ideas on how I should start cygwin?

  16. ( 8 -{D) says:

    I haven’t tried it yet, but thanx for taking the time! It looks great!. It’s very difficult (not that easy) finding updated documentation about working with the NDK. I imagine that the Google people are avoiding it on purpose, because they want people to focus on their SDK and their other homemade technology. If you know any web sites where I could find more info it would be great! Thanks again.

    Links I have found useful:

    http://groups.google.com/group/android-ndk?pli=1
    http://www.youtube.com/watch?v=byFTAhXVF7k&feature=player_embedded#!
    http://www.anddev.org/ (In my opinion, the best forum for Android developers)

  17. Asai says:

    I found the .bat file and ran it from there. Thanks for this post. It has been quite helpful.

  18. Pd says:

    Awesome work…Thanks !!

  19. NMM says:

    Thanks for this great tutorial.. :)

    but when I run emulator ..this error appear: JNI_Onload not found.

    How can I solve this problem?

  20. ivan says:

    NMM,

    Could you please give more details?

    -Ivan

  21. Ashok says:

    Hey thanks for this great tutorial and i’m having problems with cygwin make -v command it throws the following error
    $ make -v
    bash: make: command not found
    please help me to solve this…

  22. sgusc says:

    I’ve gotten to the point of attempting to compile the C code to generate the .so and I’m getting the following error:

    %> /cygdrive/c/android-ndk-windows/ndk-build
    Compile thumb : ndkfoo <= ndkfoo.c
    C:/code/ndkfoo/jni/ndkfoo.c:1:20: error: string.h: No such file or directory
    C:/code/ndkfoo/jni/ndkfoo.c:1:20: error: jni.h: No such file or directory

    make: *** [/c/code/ndkfoo/obj/local/armeabi/objs/ndkfoo/ndkfoo.o] Error 1

    So clearly this seems like an issue with the C compiler not being able to find the necessary built-in headers, but I have no idea why. I just installed the entire Devel package for Cygwin from scratch. If I write a standalone C program that includes string.h and jni.h, gcc can compile it just fine.

    What am I missing here? Thanks!

  23. Lewis Evans says:

    Great walk through, I seem to be having a problem when I publish though.

    I get an exception on

    java.lang.UnsatisfiedLinkError: invokeNativeFunction

    Im not sure if this is relevant but I also have a unresolved inclusion warning on #include and #include in my .c file.

    If anyone can point me in the right direction that would be great.

    Thanks
    Lewis

  24. Netom says:

    Hi Ivan,

    This was the best explanation and tutorial for setting NDK in Android that I have seen. It was much better than books like ‘Android CookBook’ or some other tutorials on internet that omitted lot of valuable information but which you included! Thank you very much for tutorial!
    Regards, netom

  25. Amit Padekar says:

    This is really good tutorial.
    I am very happy with this.

    Thanks

  26. Jojo says:

    @Parvendra, @Lewis Evans

    I had java.lang.UnsatisfiedLinkError because the c function name didn’t match the fully qualified name of my java class. You have to change line 4 in ndkfoo.c to match the package and class name of the target java class:

    jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {

    Then you need to click [Project]->[Clean] before you test so eclipse knows it has to recompile.

    Hope that helps.

  27. Ouael says:

    Hi Ivan,
    Thanks for the tuto.

    I have an issue using cygwin.
    When I type “make -v” i have the error “can’t find c:/Program in path”

    I also have a cygwin warning talking about environment variables.

    Do you know how to solve this issue ?
    thanks

  28. Ying says:

    Very helpful! Thanks!

  29. Learner says:

    I have a .cpp project that I want to port in android which includes threading and networking.
    As there are multiple files in different folders in the project I am confused what to do with it.
    Anyone can help me how to go ahead?

  30. HelloWorld says:

    Thanks for the great tutorial for a beginner!
    Yet I’m having a problem :(

    I’ve just followed your instructions exactly but when I’m running the sample program, its showing that “The application Ndk,Foo (process com.example.ndkfoo) has stopped unexpectedly. Please try again.

    I dont know what to do :(

    Though console is showing success.

    [2011-03-04 18:35:59 - NdkFoo] Android Launch!
    [2011-03-04 18:35:59 - NdkFoo] adb is running normally.
    [2011-03-04 18:35:59 - NdkFoo] Performing com.example.ndkfoo.NdkFoo activity launch
    [2011-03-04 18:35:59 - NdkFoo] Automatic Target Mode: launching new emulator with compatible AVD ‘Froyo’
    [2011-03-04 18:35:59 - NdkFoo] Launching a new emulator with Virtual Device ‘Froyo’
    [2011-03-04 18:36:01 - NdkFoo] New emulator found: emulator-5554
    [2011-03-04 18:36:01 - NdkFoo] Waiting for HOME (‘android.process.acore’) to be launched…
    [2011-03-04 18:36:25 - NdkFoo] HOME is up on device ‘emulator-5554′
    [2011-03-04 18:36:25 - NdkFoo] Uploading NdkFoo.apk onto device ‘emulator-5554′
    [2011-03-04 18:36:25 - NdkFoo] Installing NdkFoo.apk…
    [2011-03-04 18:36:57 - NdkFoo] Success!
    [2011-03-04 18:36:57 - NdkFoo] Starting activity com.example.ndkfoo.NdkFoo on device emulator-5554
    [2011-03-04 18:37:03 - NdkFoo] ActivityManager: Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.ndkfoo/.NdkFoo }

  31. Kanchan Hira says:

    Hi it was a good tutorial. It helped me a lot.

    I require help to create my own RSS feed using Android ndk. Please revert back if any one knows anything….:-).

  32. Dang says:

    Hi all,

    I install all software on ubuntu 10.4. When I run the program, I have this error: [2011-03-12 01:39:59 - ndkfoo] Launch error: timeout
    any idea to solve the error above.

    Thanks,

  33. Roy Samuel says:

    An excellent post. Very informative and thanks for the many screenshots that you have included.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>