With the environment set up, let's start writing the code in NDK. This recipe walks through a Hello NDK program.
The NDK development environment needs to be set up properly before starting to write the Hello NDK program. Please refer to previous recipes in this chapter, depending upon the platform of your choice.
Follow these steps to write, compile, and run the Hello NDK program:
HelloNDK
as the value for Project Name. Select Create new project in workspace. Then click on Next:cookbook.chapter1
. Select the Create Activity box, and specify the name as HelloNDKActivity
. Set the value for Minimum SDK as 5 (Android 2.0)
. Click on Finish:HelloNDK
project, and select New | Folder. Enter the name jni
in the pop-up window, then click on Finish:jni
folder under the HelloNDK
project. Select New | File, enter hello.c
as the value for File name, then click on Finish. Type the following code in the hello.c
file:#include <string.h> #include <jni.h> jstring Java_cookbook_chapter1_HelloNDKActivity_naGetHelloNDKStr(JNIEnv* pEnv, jobject pObj) { return (*pEnv)->NewStringUTF(pEnv, "Hello NDK!"); }
jni
folder. Select New | File, enter Android.mk
as the value for File name, then click on Finish. Type the following code in the Android.mk
file:LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)
jni
folder, and type ndk-build
to build the hello.c
program as a native library.HelloNDKActivity.java
file. The file should contain the following content:public class HelloNDKActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setTextSize(30); tv.setText(naGetHelloNDKStr()); this.setContentView(tv); } public native String naGetHelloNDKStr(); static { System.loadLibrary("hello"); } }
HelloNDK
project in Eclipse. Select Run As | Android Application. Your Android phone or emulator will be displayed with something similar to the following screenshot:This recipe demonstrated how to write a Hello NDK program on Android.
naGetHelloNDKStr
returns the Hello NDK
string to the caller, as indicated in both the native code function definition and Java code method declaration. The native function name must follow a specific pattern for a package name, class name, and method name. The package and class name must agree with the package and class name of the Java class from which the native method is called, while the method name must be the same as the method name declared in that Java class.This helps the Dalvik VM to locate the native function at runtime. Failing to follow the rule will result in UnsatisfiedLinkError
at runtime.
The native function has two parameters, which are standard for all native functions. Additional parameters can be defined based on needs. The first parameter is a pointer to JNIEnv
, which is the gateway to access various JNI functions. The meaning of the second parameter depends on whether the native method is a static or an instance method. If it's a static method, the second parameter is a reference to the class where the method is defined. If it's an instance method, the second parameter is a reference to the object on which the native method is invoked. We will discuss JNI in detail in Chapter 2, Java Native Interface.
makefile
. The build system accepts an Android.mk
file, which simply describes the sources. It will parse the file to generate makefile
and do all the heavy lifting for us.We will cover details of how to write the Android.mk
file or even write our own makefile
in Chapter 3, Build and Debug NDK Applications.
Once we compile the native code, a folder named libs
will be created under our project and a libhello.so
library will be generated under the armeabi
subdirectory.
System.loadLibrary("hello")
. Note that instead of libhello
, we should use hello
. The Dalvik VM will fail to locate the library if libhello
is specified.The name of a native method is lengthy and writing it manually is error-prone. Fortunately, the javah
program from JDK can help us generate the header file, which includes the method name. The following steps should be followed to use javah
:
bin/classes
/ folder of our project.jni
folder, and enter the following command:$ javah -classpath ../bin/classes –o <output file name> <java package name>.<java class anme>
In our HelloNDK
example, the command should be as follows:
$ javah -classpath ../bin/classes –o hello.h cookbook.chapter1.HelloNDKActivity
This will generate a file named hello.h
with its function definition as follows:
JNIEXPORT jstring JNICALL Java_cookbook_chapter1_HelloNDKActivity_naGetHelloNDKStr (JNIEnv *, jobject);