2010年7月5日星期一

How to use NDK and Eclipse to setup and build a Android JNI project under Ubuntu 10.04

How to use NDK and Eclipse to setup and build a Android JNI project under Ubuntu 10.04

Assume the following software are installed:
- Eclipse 3.5.1
- Android SDK (version 8)
- ADT 0.9.7
- Android NDK r4

1. Use Eclipse and ADT to create a Android project. Remember to set a right min. version for your project.
More information can be found from Android SDK document, Android NDK section.

2. Declare your native functions and load library functions.

Here is a simple example:

In ActivityMain.java file, I wrote:

package com.xxx.TestJNI;

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

public class ActivityMain extends Activity {
private static final String TAG = "TestJNI:ActivityMain";

// Declare native functions
public native String getString();

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "OnCreate >>>>>");

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Log.d(TAG, "String from native library = " + getString());

Log.d(TAG, "OnCreate <<<<<");
}
// load native library
static {
System.loadLibrary("jnitest");
}
}

If "Project-->Build Automatically" option is enabled, Eclipse will generate the corresponding class file in the {bin} folder.
You can find the class file in {project}/bin/{package}/

3. Create {jni} folder under your project folder. I.e. mkdir {project}/jni

4. Create JNI header file:
Type the following command:

javah -classpath {project}/bin -d {project}/jni/ {full package name}.{class name}

For example:
javah -classpath workspace/TestJNI/bin -d workspace/TestJNI/jni/ com.xxx.TestJNI.ActivityMain

where "com.xxx.TestJNI" is the full package name and "ActivityMain" is the class name.

Then you should find a header file in the {jni} folder.

5. Create the corresponding C/C++ file in the {jni} folder and write your codes.
For example:

In the C++ file (com_xxx_TestJNI_ActivityMain.cpp), I wrote:

#include "com_xxx_TestJNI_ActivityMain.h"
// we want to use android logging functions such that we can use Logcat for debugging
#include <android/log.h>

#define TAG "TestJNI:jnitest"

// this function will be called when the library is loaded
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// we want to use JDK/JRE 1.4 functions so we will return JNI 1.4 version to JAVA VM
// Otherwise, JAVA VM assumes we want to use JDK/JRE 1.1 functions
// More information can be found from JAVA Native Interface Specification (In the JDK documentation)

JNIEnv *env = 0;
jint result = -1;

__android_log_print(ANDROID_LOG_DEBUG, TAG, "On Load...");

if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_WARN, TAG, "JNI 1.4 is not supported!");
return result;
}

result = JNI_VERSION_1_4;

return result;
}

JNIEXPORT jstring JNICALL Java_com_xxx_TestJNI_ActivityMain_getString(JNIEnv *env, jobject obj) {

__android_log_print(ANDROID_LOG_DEBUG, TAG, "Create and return String object");

return env->NewStringUTF("Hello native world");
}

Here, we can see that I use "env->NewStringUTF("Hello native world")" to create a String object.
However, if your source file is C, then you have to change the line to "(*env)->NewStringUTF(env, "Hello native world")".

You can find more information from {NDK}/build/platforms/android-(X)/arch-arm/usr/include/jni.h.
(X) = the selected android system version.

In fact, you can search all functions which can be used from {NDK}/build/platforms/android-(X)/arch-arm/usr/include/.
Also, you can read {NDK}/docs/STABLE-APIS.TXT for a quick reference.
For JNI programming, please read JDK 6 Documentation, Java Native Interface section.

6. Create a Make file (Android.mk) in {project}/jni:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := com_xxx_TestJNI_ActivityMain.cpp
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

For the module name (LOCAL_MODULE), it should be as same as what you use for the System.loadLibrary() call in your JAVA source file.

For more information about Make file, please read {NDK}/docs/OVERVIEW.TXT and {NDK}/docs/ANDROID-MK.TXT

7. Build the native shared library.
Type the following commands:

cd {project}
{NDK}/ndk-build -B V=1

For more information about build process, please read {NDK}/docs/OVERVIEW.TXT and {NDK}/docs/NDK-BUILD.TXT

8. Rebuild your android project

Suppose the native library was built successfully, in Eclipse, select "Project-->Clean..." and then Eclipse will rebuild the project again.

Now, you can use DDMS, Logcat and software simulator/hardware to test your application.

沒有留言: