Sooner or later in your Android game development foray you may find the need to have some code that runs faster. It turns out that Android code written in C runs 10-100 times as fast as its Java counterpart. I can verify this, as I've already moved a few major components in my newest 3D game engine into native land. That's quite a boost but let's face it - C is a pain in the ass and while Eclipse is great for Java, it's not for C, right? Wrong. Here's how to set up a super speedy NDK development environment.
First of all, Eclipse can do way more than just Java. Java is what it's great at and what it was designed for but the architecture makes it so that it can handle any language effectively, including C. There is a component called CDT that allows for C/C++ Development in Eclipse. I'm getting ahead of myself, though. Here's what you need:
Android NDK (Native Development Kit)
Eclipse CDT (C Development Tooling)
If you're in Windows, you'll need Cygwin with the devel packages installed (Especially GCC and Make)
Here's what you need to do:
Install all 3 of those things. I like to install my NDK to c:\Android_NDK. I'll refer to that dir for the rest of this article.
Get acquainted with the NDK. You need to configure each project as an "app" in the c:\Android_NDK\apps dir. Just take a look at the examples. They work and are thorough.
How to test your NDK:
Run cygwin
cd /cygdrive/c/Android_NDK
make APP=hello-jni
It should compile without errors. If you are missing GCC or Make or any other dev packages, you will want to run your Cygwin setup again and check to make sure that all of the development packages are installed. If you have strange errors, I suggest reporting them in the NDK user's group.
Once your NDK is working, you can add an app for your project and set up the basic native framework for your project. Please refer to the examples for this part. You will need a specific build file that tells the compiler what sources to compile. JNI code is usually located in your Android project's jni folder. A file called Android.mk will need to be in there which instructs the compiler on what to compile.
After you get the basic configuration done, you will want to start writing some C. NDK uses Java's standard JNI bindings to work. All of the existing documentation on JNI should apply from this point forward. What to code is beyond the scope of this article.
Now for the good part
If you've done any NDK work, you're probably used to using a text editor or vim or some other editor to edit your C/CPP then running make APP=myapp every time to build, then clicking refresh on your project in Eclipse and then hoping that the shared object library file that gets deployed is current. What a pain in the ass! There's a much, much better way.
Now that you have CDT installed, you can edit all of your C/C++ right from Eclipse. If you right click on a C/CPP source file, just pick Open With--C/C++ Editor and it will use the CDT editor. Much nicer! It won't be able to figure out what the code is doing because it's not compiling it, but it will make editing nice and all in one spot.
Building is a snap as well. Ever used builders in Eclipse? They are configurable triggers that will execute what you configure and refresh resources for you. Here's how I set mine up:
Right click on your project, pick properties.
Select "builders" from the left-hand list.
Click "New..." on the right side.
Select "Program" as the configuration type.
I name mine "Native Builder"
Location - c:\cygwin\bin\bash.exe
Working Directory - c:\cygwin\bin
Arguments -
--login -c "cd /cygdrive/c/Android_NDK && make APP=myapp"
Make sure you have the two hyphens before login and the quotes after the hyphen-c
Now go to the refresh tab
Check "Refresh resources upon completion"
Select "Specific resources"
Click on the "Specify resources" button and select your project's lib directory.
Check "Recursively include sub-folders"
Now go to the build options tab
Check "Allocate Console"
Check "Launch in background"
Check "Run the builder After a Clean"
Check "Run the builder During manual builds"
Check "Run the builder During auto builds"
Check "Specify working set of relevant resources"
Click on "Specify Resources"
Select your project's JNI directory and all files within.
Now click OK on the bottom.
The assumption here is that cygwin is installed to c:\cygwin, NDK is in c:\Android_NDK and your project is called "myapp". Change where appropriate.
What did you just do?! You made it so that any time you edit any files within your JNI directory and you save them, Eclipse will run the NDK Builder for you via Cygwin and show the compile output in your console. When it finishes, it will refresh your output (lib) directory which will trigger ADT to compile a new APK for you and YOU ARE GOOD TO GO!
This seriously sped me up while working on my current project. I hope you can all benefit from it!
18 Comments
Post a comment here or discuss this and other topics in the forumsThank you for your excellent job.
For now, Android NDK offers 'ndk-build' for us not to 'cd' to the project directory.
Arguments field can be modified as shown below. (for win32)
--login -c "ndk-build -C `cygpath -u '${build_project}' `"
maybe
--login -c "ndk-build -C '${build_project}'" (for non-win32)
I hope this will be helpful.
Console output?
I've got an approximation of this set up (in OSX) and it's working wonderfully, with one exception. I'm not getting the output from my ndk-build in the standard console. It's flashing up for half a second or so before disappearing, and I can't figure out how to either pipe it into the normal console or at least keep that output open separately. The result is that if the ndk-build fails, I'm unable to see that it has...
Anyone have any thoughts?
On Linux
Thanks for the post -- very nice.
On linux instead of feeding commands to bash, I created a shell script at ~/bin/build_ndk_app with the following 2 lines:
cd /home/zach/android/android-ndk
make APP=$1 -B
And then I just point the builder to this script, and add the project name for the argument.
Thanks again.
A Treasure!
Robert, I sincerely thank you for this wonderful tip!
I was happy with CDT and using Eclipse to edit C/C++ files and makefiles, but I never ventured into making the process entirely automatic and efficient!
Thank you so much!
thank you for your
thank you for your help!
Question: Since I've followed these instructions, now I've lost my SDK-ish XML editor in my java projects. Its just a plain text editor and I don't have the nifty AndroidManifest.xml editor to easily handle updating my files (including the "Export APK Wizard". Any ideas?
Yes, right click on the file
Yes, right click on the file in Package Explorer or Navigator or Java Explorer or whatever view you use to get around your project. Click Open With. If things are installed correctly, you'll have several Android options including a Layout Editor, Menu EDitor, Manifest Editor, etc. Choose Android Manifest Editor.
If you don't have those options, you should uninstall/reinstall ADT.
Nice example
I just fixed one issue i was facing.
changed library was not reflecting in my apk but later i realized that my project path in eclipse was different with the one i was compiling :)
its working fine now
very usefull but one issue with me
Hi Dear,
Thanks for sharing it.
i set it up as advised but when i change anything in c file, it doesn't create new shared library.
i also changed Application.mk, removed library from lib but still getting this msg
make: Nothing to be done for `all'.
Great to hear you are working
Great to hear you are working on a new game! I was disappointed that you didn't win a prize in the ADC2. LR3D and Project INF were my favorite arcade entries and neither game won.
ADC2 was a good experience
ADC2 was a good experience and was the kind of motivation I really needed to get my butt kicked into gear. I'm glad that you enjoyed the game. For how rushed the LR3D v1.0 entry was, I was happy just to have it in the top 20.
Our new game is a world of difference in quality. I haven't posted anything yet because I'm waiting until I have something really substantial to show.
Excellent post
Thank you for this; I will probably be setting this up for my next project. I'm barely able to chug the sort of performance I need for my current game using Java and a SurfaceView, but it's too late to justify changing now. I've had to implement a whole lot of performance optimizations, but you can only go so far. NDK should help a lot. I assume you're using C++ with OpenGL ES?
You've mentioned performance differences between G1 and the Droid before, so quick question: With my droid running my game I can get 60 fps most of the time, dropping to 40 fps when things get a bit more messy. Obviously I'll have to do some real testing on one, but do you think it would maintain 20-30 fps on the G1 given the performance on the droid? Testing on multiple phones is very difficult with how expensive they are outside of a contract...
I have a healthy mix of Java
I have a healthy mix of Java and C for my games. I use Java for the majority of the code and C for the really math intensive stuff, like collisions and heavy geometry operations.
The only way to find out what kind of performance you'll get on a G1 is to test on a G1-class phone. The G1, MyTouch, Eris and Hero all perform about the same because they all have the same MSM7201A chip.
What I like to do now is I run an FPS counter along with an update timer. The update timer shows me how long (in ms) my last update took. That way if the FPS drops badly, I can see if it's my update (CPU-bound) or if it's the GPU slowing down. Adding additional timers to watch AI or other things is also a good idea. More mature engines graph out these things so that you can see how several of the subsystems are performing in real-time.
Using an update and draw
Using an update and draw timer is a good idea. I have an FPS counter already but obviously that doesn't give a whole lot of information about why performance has gone down. I have primarily been relying on using method tracing in Debug to figure out what causes the slowdown; it's actually been incredibly helpful. The only issue is that I can't actually run trace mode on the emulator, given that it runs about 6 times slower than the Droid. I've learned quite a lot about performance though. For instance, I had no idea how absurdly long it takes to do something like "string1" + "string2", or how much less efficient a small HashMap is compared to a small array, even if you don't use all the elements.
I just thought of another thing as well that you probably know. Does using OpenGL give a significant performance increase for drawing? For example, my app is done almost completely with sprites, so I rely quite heavily on Canvas.drawBitmap() and its overloads. I've optimized the update methods to the point where any more gains would be trivial compared to the draw time. Do you think switching to the OpenGL equivalent would net a reasonable performance increase?
Profiling is good because
Profiling is good because it'll show you where you're really losing a lot of cycles. Working with strings is really bad. There are tons of allocations that happen even on simple concatenations.
OpenGL for sprites is really fast on any device that has hardware acceleration (a GPU). It takes a little bit of though to get your head around it because you have to set up the scene ahead of time and know to use a texture atlas and start learning about UVs on quads and such but once you get it, it's not that hard. I'm doing another 2D game after I finish my current 3D one and I'll be doing all OpenGL for it.
Hello! (First sorry for my
Hello!
(First sorry for my bad english)
Thank you for this great tutorial, it worked like a charm for me! Theres only one thing that i like to be available with NDK development in Eclipse: to specify where editor look for header files, so it could provide me IntelliSense like tips. I found an another tutorial about this topic here: http://cdtdoug.blogspot.com/2009/09/using-cdt-for-android-native.html this does it by converting the project into a C/C++ one. If i go into the project properties i can specify the platform headers under the C/C++ settings by pointing to the directory in the NDK's folder, so editor get knows about the code elements there. Although i don't know how to add your automatic compiling to this project, also it can't build the project anyway, Eclipse can't find make program (i guess because we didn't specify the toolchain to use for this). Do you have any suggestions what should i do to achive what i like to do?
Thanks if you spare some time for my problem!
You need to install Cygwin
You need to install Cygwin with the full devel packages to get make and gcc.
Great post
A guy working directly on cdt posted something similar a couple of months ago. It's definitely a big plus whend doing ndk projects, altough build times can sometimes get on your nerves (I'm looking at you bullet physics library!).
Care to elaborate on your new project? How about doing something similar to the light racer 3d dev blog for it? I think that would make a lot of people happy, including me :)
Elaboration
The new project is very ambitious but is coming along. What I can say about it is that it's a first/third-person (sort-of) FPS game. It's a hybrid of things. We've spent most of our time working on the technology and so far so good, though I'm finding it difficult to work with the limitations of the G1-class GPU at the moment.
I'll be posting some screenshots and hope to have a nice demo out in a month.
Thanks for reading!
Post new comment