Tuesday, July 17, 2012

Android NDK - Configure Eclipse to invoke native C/C++ code and library in Android


Android NDK allows you to implement part of Android program in native code language such as C/C++.  It's often mistake for Android developers to jump into NDK and delegate heavy computational part into native libraries written in C/C++ for performance improvements. However, as stated in the NDK documentation,

Notably, using native code on Android generally does not result in a noticable performance improvement, but it always increases your app complexity. In general, you should only use the NDK if it is essential to your app—never because you simply prefer to program in C/C++  
Today, I am going to cover how I managed to configure my Eclipse environment to start developing with Android NDK. Before you proceed the rest of tutorial, think twice. Make sure you are doing this for code reuse and portability and not for computational performance benefits.

Prerequisite

This tutorial assumes you have installed Android SDK environment, Java JDK, and Android ADT plugin. If you haven't installed any of those things listed above, follow the tutorial posted by Android code monkey. Once you are done with that, create a new Android project in your Eclipse environment and follow the rest of the tutorial.

Android NDK Installation 

- Install Android NDK
- Unzip Android NDK  (i.e. C:\Android\android-ndk-r8 or /usr/local/android/android-ndk-r8)

Native Code Configuration (C/C++ code)

Install C/C++ Eclipse plugin
- Choose Help -> Install New Software… from the main menu.
- Choose http://download.eclipse.org/releases/galileo as the source site. If you have another Eclipse release than Galileo choose the appropriate url.



Create JNI folder in your eclipse project
- A folder named 'jni' (lowercase) must be created by you in the Eclipse project's root directory.
 

Create C/C++ JNI sources (example.c)
- Create your c files in jni directory you created above
- For the tutorial, I created example.c to illustrate the basics. I wrote a simple function called initEngine(int x) that doubles up the int x passed and returns the sum.
 

Header Information
- You must have #include and this is necessary for all the JNI configuration in your native code

Return Type
- JNIEXPORT int JNICALL
      - int - return type of your JNI call

Function Declaration 
- Functional declaration in between _ has meanings:
     - Java: We will use Java to invoke this native code
     - com_goeverywhere_jni: package representation of your Java JNI class. 
     - JNILoader: name of the Java class 
     - initEngine: method name within the Java class

Function parameters
- (JNIEnv * env, jobject obj) - this is required for JNI invocation
- Parameters preceding above is the parameter for your function declaration
     - jint x: this is added for my JNI function parameter for initEngine(int x)

Create Android.mk

Android.mk is a makefile needed to compile your native sources between Android NDK and your native code. Information writing on Android.mk file can be found in 'docs' folder inside the Android NDK folder. The most relevant document is the 'ANDROID-MK.TXT'



- LOCAL_PATH - path of your module. $(call my-dir) refers to same directory as the 'Android.mk' file
- LOCAL_MODULE - module name. This name should not have any spaces in it as it will be made into the actual library's name ('libexample.so' for us).
- LOCAL_CFLAGS - compiler flags.
- LOCAL_SRC_FILES - source file name

Write Java JNI library in Java

Now, let's write some Java code!



- Notice that the prefix of function declaration of native c function written above (i.e. Java_com_goeverywhere_jni_JNILoader_initEngine) must match with the Java package represenatation
- System.loadLibrary(module) must be invoked to load the native module via JNI and this must match what you defined in Android.mk:LOCAL_MODULE
- The functional declaration in java side must match with native declarations above with special keyboard native

Configure Eclipse Builder 

There are multiple ways you can compile what you have implemented above. You can install cygwin and install packages associated with it to compile with GCC libraries that comes with it. However, Android NDK already ships with precompiled version of make files and other necessary bundles.

I didn't want to deal with going into Cygwin or cmd prompt everytime I compile my code. Therefore, what I ended up doing is simply configuring an Eclipse Builder that automatically builds using ndk-build.cmd from Android NDK.

Right click on your project -> Properties -> Builders



Create a new Eclipse Project builder 


- Location: refer to ndk-build.cmd from your Android NDK installation directory
- Working Directory: reference to your Android project in your Eclipse

Eclipse Project builder -> Refresh tab



- libs directory is where your Android project looks for compiled resources (jars, libs) by default
- Click "specify resources" and configure location of libs directory
- Once you configure this and refresh your project, your builder will execute and compile all the source codes for you!

Eclipse Project builder -> Build options


- Navigate to "Build Options" tab
- Click "specify resources" and configure your location of jni directory

You are done!


- Your console will show that you have successfully compiled your sources. Depending on your CPU architecture, your compiled library will be compiled into the appropriate folder in your libs (i.e. armeabi)

Tuesday, April 24, 2012

Designing UI elements with Android fragment and Android SDK Manager issues I ran into

Designing UI elements with Android fragment and Android SDK Manager issues I ran into Implementing your Android UI with fragment not only makes your application components more modular, this is an optimal design for multiple platform if you plan to target your application to be available in all Android platforms such as tablets, Google TV, and mobile. Android introduced fragment in API 3.0 but you don't necessary want to make your min API level to 11+ because then the devices with lower API won't be able to download your application in Google play store.

As seen from graph above, it seems very wise to design min API as low as Android 2.2 to grab the most of the market share. It turns out you can still use Android fragment feature from 3.0 API without increasing the min API level in your application by utilizing Android compatibility package. This requires you to download the support package using Android SDK manager. I also found out there's a sample project comes from your android-sdk\samples\android-xx\APIDemos but when I tried to import the project into the workspace, it gave me the following error:
You do not have the latest version of the SDK Tools installed: Please update.
So it looks like I need SDK Tools and compatibility package - no problem. I decided to simply download latest API levels/support/compatibility packages because who knows if I have to end up debugging particular version of the android. You will get a pop up from motodev and htcdev asking for developer credentials but no worries they are legit - you can create an account for free on their website. After creating developer account, I tried it again - While attempting doing so, I ran into more errors in Android SDK manager. Depending on what you have currently installed in the system, you will get an error:
File not found: ...\android-sdk\temp\google_apis-15_r02.zip (Access is denied)

[2012-04-24 00:01:20 - SDK Manager] Skipping 'Android SDK Tools, revision 19'; it depends on 'Android SDK Platform-tools, revision 11' which was not installed.
Error after error!! One thing to note about access is denied error is that it's not a precise error message. In my case, I simply didn't have anything in that folder. I then thought I might have been to ambitious to install everything at once. Therefore, I just decided to install Android SDK Platform-tools, revision 11 then but SDK manager is still not happy.
Failed to rename directory C:\android-sdk\tools to C:\android-sdk\temp...
The error might tell you to turn off anti-virus because you expose yourself to security risks, make sure you don't have command prompts or folders opened associated with android-sdk. I have no idea why Android SDK tools is not fully backward compatible but I figured out a workaround here eventually. To summarize the trick, I had to do the following:
INSTRUCTIONS:

1. make a copy of the tools directory and call this new directory tools2.

2. DO NOT USE 'SDK Setup.exe'.

3. Instead open up a cmd.exe window as administrator and run the following from this new tools2 directory (obviously the full path on your local machine will be different):

android-sdk-dir> tools2\android.bat update sdk

Basically, as noted before in this thread, 'SDK Setup.exe' invokes tools\android.bat, which makes it impossible for it to rename the tools directory thereafter. It's a bit goofy and should never have passed QA validation..
After you execute the command above, you will be prompted with Android SDK manager and you will be able to install anything you wish for in Android SDK manager. Sudos kudos!