How to use JNI

Many developers asked how to use JNI, especially when they were integrating 3rd SDKs on Android. So I write this document to describe it.
It is a big topic, this document will not cover all knowledge. Please refer http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
or other documents for more detail information.

I think jni includes two parts
  • java code invoke native code
  • native code invoke java code

In this document, native code means c/c++.

1. Java code invoke c++ code

We use an example to describe it. The sample code may be different from http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html,
but can work on android.

  • java code (org.cocos2dx.sample.Sample.java)
    1class Sample {
    2    public void invokeNativeCode() {
    3        int sum = nativeAdd(1, 2);
    4    }
    5
    6    private native int nativeAdd(int a, int b);
    7}
    

The keyword "native" means nativeAdd() is a native method. The method accepts two integer parameters and returns an integer.
The prototype to declare a native method is:

private native int invokeNativeCode()
MethodModifiers native ResultType MethodDeclarator
  • c++ code(SampleNative.cpp)
     1// SampleNative.h
     2#ifdef __cplusplus
     3extern "C" {
     4#endif 
     5
     6jint Java_org_cocos2dx_sample_Sample_nativeAdd(JNIEnv *env, jobject thiz, jint a, jint b)
     7{
     8    return a + b;
     9}
    10
    11#ifdef __cplusplus
    12}
    13#endif
    
The declaration of native function is
1ResultType Java_classpath_functionName(JNIEnv *env, jobject thiz, other parameters)
  • ResultType
    ResultType should be the same as java codes. In java, it is int, in c++ it is jint. we will explain it latter.
  • classpath
    classpath should be the full path of java class, such as String, its full path is java.lang.String. And should
    replace "." with "_".
  • functionName
    functionName should be the same as java code.
  • parameters
    Every native implementation will receive JNIEnv* and jobject as its first two parameters. jobject points which
    java object invokes this native function.

Argument types in the native method declaration have corresponding types in native programming languages.
You can refer 12.1.1(old TOC) of http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html for detail information.
See: JNI Types and Data Structures and Native method arguments

2. c++ code invoke java code

C++ code can invoke java static function or non static function. This document will only describe how c++ code
invoke java static function. Invoking non static function is similar.

For example, there is a java class like

1// org.cocos2dx.sample.Sample.java
2class Sample {
3    public static int sum(int a, int b) {
4        return a + b;
5    }
6}

We can invoke Sample.sum like this
1env->CallStaticIntMethod(classId, methodId, parameters)
  • env
    It is a pointer of JNIEnv.
  • CallStaticIntMethod
    Because Sample.sum is a static method and its return type is int, so invoke CallStaticIntMethod
  • classId, methodId, parameters
    These three elements will determine which method of which class to invoke.

So we should get these elements to invoke Sample.sum().

2.1 Get pointer of JNIEnv

Please refer getJNIEnv() in cocos2dx/CocosDenshion/android/jni/SimpleAudioEngine.cpp.

2.2 Get classId

We can get class id like this

1(JNIEnv*)->FindClass(ClassName);

ClassName should be the full path of the class whose method is invoked by jni.
In this example, it is "org/cocos2dx/sample/Sample".

2.3 Get method id

As we say, we will take static method as example, so we can get method id like this

1(JNIEnv*)->GetStaticMethodID(classID, methodName, method signature);

We have got JNIEnv* and classID in 2.1 and 2.2, and methodName is the same as java.
In this example, it is "sum".
We also need to "method signature" to determine which method to invoke, because there may be
two or more methods have the same name.

You can refer 12.3.3 of http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html (Type Signatures ) for detail message.
In this example, it is "(II)I".

There is a tip to get a method signature: view .class file of corresponding .java file in eclipse,
then you will see all method's signatures.

2.4 Parameters

Argument types in the native method declaration have corresponding types in native programming languages.
You can refer 12.1.1 of http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html (Types) (previously http://java.sun.com/docs/books/jni/html/jniTOC.html) for detail information.