{stnguyen} Game dev and random stuffs

Call Java functions from C++ in cocos2d-x

Calling Java functions from C++ (and vice-versa) for a cross-platform cocos2d-x game is actually not that hard (and scary, as I thought). Learning from cocos2d’s Java_org_cocos2dx_lib_Cocos2dxHelper.cpp file and a bit of searching on the internet should give us all the information we might need.

The following note actually applies for all native Android applications, not just cocos2d-x games.

Simplest case: void method with no arguments

Suppose you have a static void doMeAFavour() java function declared in MyAwesomeJavaClass, calling it from C++ is as simple as:

1
2
3
4
5
6
7
8
9
10
JniMethodInfo t;

if (JniHelper::getStaticMethodInfo(t,
  "MyAwesomeJavaClass",
  "doMeAFavour",
  "()V")) {

    t.env->CallStaticVoidMethod(t.classID, t.methodID);
    t.env->DeleteLocalRef(t.classID);
}

That’s it! Yes, that simple!

But what about passing parameters and/or retriving a return value? We will need to learn a bit about Java method signature.

Java method signature

Do you see "()V" part when we call JniHelper::getStaticMethodInfo()? It’s called a Java method signature, or in my words is a string showing argument types and return type of a Java method.

Rules:

Signature Java Type
V void
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

Examples:

static String doMeAFavour(int times)
// Signature: "(I;)Ljava/lang/String;"

static bool sayHello(String to, int times)
// Signature: "(Ljava/lang/String;I;)Z;"

Passing parameters and receiving return value

Suppose we have a Java method which takes 2 arguments and return a bool value

static bool sayHello(String to, int times)

To call it from C++, do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
JniMethodInfo t;

if (JniHelper::getStaticMethodInfo(t,
  "MyAwesomeJavaClass",
  "sayHello",
  "(Ljava/lang/String;I;)Z;")) {

    const char* myName = "Beautiful Name";
    int times = 3;

    jstring stringArg1 = t.env->NewStringUTF(myName);
    jboolean retV = t.env->CallStaticBooleanMethod(t.classID,
        t.methodID,
        stringArg1,
        times);

    t.env->DeleteLocalRef(t.classID);
    t.env->DeleteLocalRef(stringArg1);
}

Explain:

  • Pass any number of parameters into CallStaticBooleanMethod call.
  • You may need to wrap paramters into JNI types as in line 11. If you did so, remember to delete local refence as in line 18.
  • There’s a whole family of CallStatic[ReturnType]Method depends on the returning value type you need. Each method return a corresponding JNI type (e.g. jboolean, jfloat, jobject…)

Receiving return value of type String

Recieving a string from Java is a bit trickier (yeah, just a bit). String is an object in Java, so we’re using CallStaticObjectMethod and convert the result to std::string:

1
2
3
4
5
jstring s = (jstring) t.env->CallObjectMethod(t.classID,
        t.methodID);

// convert it to std::string
std::string str = JniHelper::jstring2string(s);

You might need to retain the String being returned from Java method, or else C++ will receive a pointer to a released space. The easiest way would be making the returning value static


In part 2 of this tutorial, I will write about calling C++ methods from Java ;) Stay tuned…

UPDATE: part 2 is here

Comments

comments powered by Disqus