Tuesday, December 14, 2010

tools for working with android jni

When we make use of jni on android, it's a error-prone task to manually write the native function name for a given java native function. Though there are rules for us to follow, no one would like to memorize that. javah to the rescue.
For example, for the following java class with a native method.
 1 package com.rmd.jni;

 2

 3 import android.app.Activity;

 4 import android.os.Bundle;

 5

 6 public class Main extends Activity

 7 {

 8     /** Called when the activity is first created. */

 9     @Override

10     public void onCreate(Bundle savedInstanceState)

11     {

12         super.onCreate(savedInstanceState);

13         setContentView(R.layout.main);

14     }

15

16     public native boolean JniMethod(int a);

17 }


We can follow steps below to generate a native header file:
  1. cd to project root folder
  2. Compile the project, e.g., using ant debug command
  3. run javah -jni -classpath bin/classes -d jni com.rmd.jni.Main (this command generates a native header file in jni directory, for com.rmd.jni.Main class)

And we get a header file com_rmd_jni_Main.h with content below:

 1 /* DO NOT EDIT THIS FILE - it is machine generated */

 2 #include <jni.h>

 3 /* Header for class com_rmd_jni_Main */

 4

 5 #ifndef _Included_com_rmd_jni_Main

 6 #define _Included_com_rmd_jni_Main

 7 #ifdef __cplusplus

 8 extern "C" {

 9 #endif

10 /*

11  * Class:     com_rmd_jni_Main

12  * Method:    JniMethod

13  * Signature: (I)Z

14  */

15 JNIEXPORT jboolean JNICALL Java_com_rmd_jni_Main_JniMethod

16   (JNIEnv *, jobject, jint);

17

18 #ifdef __cplusplus

19 }

20 #endif

21 #endif


There are cases that we need to provide a method signature of a java function to the GetMethodID function in native code. javap can help us.
Consider the java class below, within which exists a JniCallback method. And this method is meant to be called from native code.

 1 package com.rmd.jni;

 2

 3 import android.app.Activity;

 4 import android.os.Bundle;

 5

 6 public class Main extends Activity

 7 {

 8     /** Called when the activity is first created. */

 9     @Override

10     public void onCreate(Bundle savedInstanceState)

11     {

12         super.onCreate(savedInstanceState);

13         setContentView(R.layout.main);

14     }

15

16     public boolean JniCallback(int a);

17 }

After it's compiled, we can use javap -classpath bin/classes -s -p com.rmd.jni.Main command to find out the signature of JniCallback method. Shown below.
Compiled from "Main.java"
public class com.rmd.jni.Main extends android.app.Activity{
public com.rmd.jni.Main();
Signature: ()V
public void onCreate(android.os.Bundle);
Signature: (Landroid/os/Bundle;)V
public native boolean JniMethod(int);
Signature: (I)Z
}

Reference:
Java Native Interface Programming