{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 JniMethodInfo t;
 2 
 3 if (JniHelper::getStaticMethodInfo(t,
 4   "MyAwesomeJavaClass",
 5   "doMeAFavour",
 6   "()V")) {
 7 
 8     t.env->CallStaticVoidMethod(t.classID, t.methodID);
 9     t.env->DeleteLocalRef(t.classID);
10 }

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 JniMethodInfo t;
 2 
 3 if (JniHelper::getStaticMethodInfo(t,
 4   "MyAwesomeJavaClass",
 5   "sayHello",
 6   "(Ljava/lang/String;I;)Z;")) {
 7 
 8     const char* myName = "Beautiful Name";
 9     int times = 3;
10 
11     jstring stringArg1 = t.env->NewStringUTF(myName);
12     jboolean retV = t.env->CallStaticBooleanMethod(t.classID,
13         t.methodID,
14         stringArg1,
15         times);
16 
17     t.env->DeleteLocalRef(t.classID);
18     t.env->DeleteLocalRef(stringArg1);
19 }

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 jstring s = (jstring) t.env->CallObjectMethod(t.classID,
2         t.methodID);
3 
4 // convert it to std::string
5 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