(Updated V3.0)How to connect C++ and Java with JNI and Refresh GUI safely (Totorial 1)……(Tutorial by YUYE)

This post is also available in:

Chinese
http://blog.csdn.net/liuyuyefz/article/details/17754025

Note from YUYE:

You guys voted for me to update this "How to integrate plugin use it in cocos2d-x in the weekly tutorial vote, so your wish is my command! :]
This tutorial series is now fully up-to-date for Cocos2D-X 2.X/3.X, Android.

The Java Native Interface (JNI) is a programming framework that enables Java code running in a Java Virtual Machine (JVM) to call and be called[1] by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly.

Many guys ask me How to integrate the IAP facebook and SDK in cocos2d-x again and again, and thought I’d write a tutorial series based on my experience in case it might be useful to other newcomers.

This tutorial series will walk you through the process of creating a simple game to explain How can you get connect java to c++ with Cocos2D-x, from start to finish. You can follow along with the series, or just jump straight to the sample project at the end of the article.

h3. Jump to
Part 2:
www.part2.com
Part 3:
www.part3.com
of the series.

Downloading and Installing:

You can download cocos2d-x v2.2.2/v3.0beta from : http://www.cocos2d-x.org/download

The architecture and API is many difficult from v2.2.2/v3.0beta

The biggest change is v3.0: Changing namespace from “cocos2d” to “cc”

How to install it :

After you pull down the cocos2d-x v2.2.2/v3.0beta , you’ll want to create project. Open up a Terminal window to the “/Users/Username/cocos2d-x/tools/project-creator/” you downloaded cocos2d-x, and enter the following command:

v2.2.2

python create_project.py -project MyGame -package com.MyCompany.AwesomeGame -language cpp

v3.0beta

python create_project.py -n MyGame -k com.MyCompany.AwesomeGame -l cpp -p /Users/UserName/cocos2d-x-3.0beta/project 

And you can open the ios project first under the path "/Users/UserName/cocos2d-x/projects/MyGame/proj.ios
Go ahead and build and run the template as-is. If all works OK, you should see the following:

Change LabelTTF’s text

Before you can change the LabelTTF’s text, you’ll set LabelTTF as a Member Variable in order to set LabelTTF’s text in any functions.

So let’s Open “HelloWorldScene.ccp”

Replace the init method with the following:

2.X version:

bool HelloWorld::init()
{
    ......

    //CCLabelTTF * pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
    pLabel = CCLabelTTF::create("Hello World", "Arial", 24);

    return this;
}

3.X version:

bool HelloWorld::init()
{
    ......

    //auto label = LabelTTF::create("Hello World", "Arial", 24);
    label = LabelTTF::create("Hello World", "Arial", 24);

    return this;
}

Add the “LabelTTF declaration” to your HelloWorld class declaration:

2.X version:

class HelloWorld : public cocos2d::CCLayer
{
public:
    virtual bool init();  

    static cocos2d::CCScene* scene();
    //LabelTTF declaration
    cocos2d::CCLabelTTF * pLabel;
    .......
    CREATE_FUNC(HelloWorld);
};

3.X version:

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    //LabelTTF declaration
    cocos2d::LabelTTF * label;
    .......
    CREATE_FUNC(HelloWorld);
};

Add the following method right after the init method:

v2.x

void HelloWorld::changeText()
{
      pLabel ->setString("My Text!");
}

v3.x

void HelloWorld::changeText(float t)
{
    label ->setString("My Text!");
}

Add the following to your HelloWorld class declaration:

void changeText(float t);

One last thing before you go. You need to actually call the method to change the label’ text! So add the following call to your init method before you return:

changeText(0);

That’s it! Build and run the project, now you should see :

v2.x

JNI in C++

Next you want the LabelTTF’s text to be change by java – otherwise there wouldn’t be much of a challenge! So let’s add the method for C++ receiving Java’s call to the HelloWorld class, and set up an mark variable for JNI’ thread telling main thread to refresh draw method. Because, opengl can not allow direct change the draw method from others’ thread
Add the following method right before the createScene method:

v2.x

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include <jni.h>
extern
"C"
{
    void Java_org_cocos2dx_cpp_Cocos2dxActivity_changeTTFLabel(JNIEnv* env, jobject thiz,jstring textStr)
    {
        const char* str;
        str = env->GetStringUTFChars(textStr, false);
        std::string tempStr(str);
        HelloWorld::changeStr = tempStr;
    }
}
#endif

We are going to talk about the above one by one.

Part 1:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#endif

Above is for defining platform. It can only be called when compiling android projects; Others’ platform will not be effect by these code.

Part 2:

#include <jni.h>

It is a head file required by using JNI Method.

Part 3:

extern
"C"
{
  ...
}

You need to add extern “C” to clarify that you are compiling with C language as the generated function signatures would be different from that of C*+ during compiling process , otherwise you’d get a link error when running.

Part3:

void Java_org_cocos2dx_cpp_Cocos2dxActivity_changeTTFLabel(JNIEnv* env, jobject thiz,jstring textStr)

It goes like Java_package name_class name_method name(Arguments,…)

The arguments:
1.JNIEnv*: reference to JNI environment, which lets you access all the JNI fucntions.
2.jobject: reference to “this” Java object.
3.jstring: JNI defined a jstring type to represent the Java String. The last argument (of JNI type jstring) is the Java String passed into the C program. The return-type is also jstring.

Part 4:

const char* str;
        str = env->GetStringUTFChars(textStr, false);
        std::string tempStr(str);
        HelloWorld::changeStr = tempStr;

Above is for converting the jstring to the const char* then we use a static std::string variable to save the value.

One last thing before you go. You need to clarify the changeStr as a static std::string.So add the following before your JNI method :

std::string HelloWorld::changeStr =" ";

Then add the following to your HelloWorld class declaration:

static std::string changeStr;

Now you can try to build it. if it is not any problem. we go to next step.(more information for JNI refer to:http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html)

JNI in Java

Before we go to Java. let’s fix one problem. because you can just refresh the GUI in cocos2d-x in the main thread.

So we will create a schedule to detect if the java changed the mark variable.

Then replace HelloWorldScene.cpp with the following code:

V2.X

void HelloWorld::changeText(float t)
{
    if (HelloWorld::changeStr.compare(" ") !=0)
    {
        pLabel ->setString(HelloWorld::changeStr.c_str());
        HelloWorld::changeStr =" ";
    }
}

V3.X

void HelloWorld::changeText(float t)
{
    if (HelloWorld::changeStr.compare(" ") !=0)
    {
        label ->setString(HelloWorld::changeStr.c_str());
        HelloWorld::changeStr =" ";
    }
}

Replace the following to the “changeText(0);” call

CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(HelloWorld::changeText),this, 0,false);
Director::getInstance()->getScheduler()->scheduleSelector(schedule_selector(HelloWorld::changeText),this, 0,false); 

Now we are done with the C++ part.

Open the page in eclipse:

Before this, make sure you have the android environment to compile cocos2d-x under eclipse ready.
Refer to: http://www.wikihow.com/Set-up-an-Android-Development-Environment

COCOS2D-X V2.2.2

V2.X

And then at the bottom of the function:
public class TestJniextends Cocos2dxActivity{
……
}
add below:
private static native void changeTTFLabel(String textStr);// works as an intermediary API, allowing java to call the samely named JNI functions in C**.
Finally, at the bottom of
protected void onCreate{
……
}
add and call changeTTFLabel;
5) To view the final result, compile C** and java codes on a real computer
For C++:
Let’s enter the folder cocos2d-x2.2.0/projects/TestJni/proj.android, compile the shell script of build_native.sh

In Windows you’ll need cywin to simulate a linux environment, and in Mac you can just run ./build_native.sh. After a successful compilation, you’ll see something like below. If error occurs, read details to see why.

Now we can compile the java part of android in eclipse.
Click on eclipse – clean.

In the end, connect to a real computer and see label changed from Hello World to Test MyLabel Change!

COCOS2D-X V3.0 beta

V3.X

for V3.0 you should replace the Cocos2dxActivity.java like this:

package org.cocos2dx.cpp;

import java.util.Timer;
import java.util.TimerTask;

import android.app.NativeActivity;
import android.os.Bundle;
import android.os.Handler;

public class Cocos2dxActivity extends NativeActivity{

	private Handler handler = new Handler();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		
		//For supports translucency
		
		//1.change "attribs" in cocos\2d\platform\android\nativeactivity.cpp
		/*const EGLint attribs[] = {
	            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
	            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,  
	            //EGL_BLUE_SIZE, 5,   -->delete 
	            //EGL_GREEN_SIZE, 6,  -->delete 
	            //EGL_RED_SIZE, 5,    -->delete 
	            EGL_BUFFER_SIZE, 32,  //-->new field
	            EGL_DEPTH_SIZE, 16,
	            EGL_STENCIL_SIZE, 8,
	            EGL_NONE
	    };*/
		
		//2.Set the format of window
		// getWindow().setFormat(PixelFormat.TRANSLUCENT);
		
		handler.postDelayed( new Runnable() 
		{
			public void run() 
			{
				execute();
			}
		}, 100 * 1 );
	}
	
	private void execute() 
	{
		new Thread( new Runnable() 
		{
			public void run() 
			{
				String a=""; 
				a = String.valueOf((int)(Math.random() * 10+1)) ;
				changeTTFLabel("Test MyLabel Change!"+a);
			}
		}).start();
	}
	public static native void changeTTFLabel(String textStr);
	
}


Untitled.png (404.8 KB)


Untitled2.png (634.0 KB)


Untitled3.png (266.0 KB)


openHelloWorld.png (27.3 KB)


changeText2.0.png (13.6 KB)


changeText3.0.png (13.7 KB)


HelloWorld.png (20.4 KB)


MyText.png (15.6 KB)


JNIMethod.png (45.8 KB)


Activity3.0.png (132.5 KB)

2 Likes

hi yuye, thanks for the helpful tutorial :slight_smile:

But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,

How to implement it in 3.0 ?

I pushed it to my ToDo list. thank for you advise

Jonathan Napitupulu wrote:

hi yuye, thanks for the helpful tutorial :slight_smile:
>
But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,
>
How to implement it in 3.0 ?

Jonathan Napitupulu wrote:

hi yuye, thanks for the helpful tutorial :slight_smile:

But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,

How to implement it in 3.0 ?

You can use the code in GameSpice: https://github.com/gamespice/gamespicex to pass something from C++ to Java via JSON and map that to Java objects. Take a look here: https://github.com/gamespice/gamespicex/tree/master/lib/platform/android/jni

Yuye, thanks for the tutorial!

Venelin Valkov Thanks for u reference. I’ll post it to this tutorial head.:slight_smile:
Venelin Valkov wrote:

Jonathan Napitupulu wrote:

hi yuye, thanks for the helpful tutorial :slight_smile:

But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,

How to implement it in 3.0 ?

You can use the code in GameSpice: https://github.com/gamespice/gamespicex to pass something from C++ to Java via JSON and map that to Java objects. Take a look here: https://github.com/gamespice/gamespicex/tree/master/lib/platform/android/jni

Yuye, thanks for the tutorial!

I updated the tutorial for V3.X. please check it out.
Jonathan Napitupulu wrote:

hi yuye, thanks for the helpful tutorial :slight_smile:

But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,

How to implement it in 3.0 ?

Jonathan Napitupulu wrote:

hi yuye, thanks for the helpful tutorial :slight_smile:

But I noticed that in cocos2d-x 3.0, it’s a little bit different in Android, because of NativeActivity.java
The structure of Cocos2dxActivity.java in 3.0 and MyProject.java in 2.0 also different,

How to implement it in 3.0 ?

We’ve added Cocos2dxActivity.java back to sample projects. Actually it inherits from native activity. So you can integrate 3rd SDK as usual.

thanks.

how to call JNI form C++ in helloworld.cpp?

i wanna call java function like vibrator in 3.0 ver.

I’m sorry for I just wrote the chinese tutorial for how to call JNI form C++ to java.
and now I’m working on facebook’s tutorial. it’ll include the part what you want to know. so if I finished it. I’ll tell you the part for how to call JNI form C++ to java.
thank you very much for read my tutorials
jamesYou wrote:

thanks.

how to call JNI form C++ in helloworld.cpp?

i wanna call java function like vibrator in 3.0 ver.

Hi~~
how do i add WebView on Android?
I can add WebView at cocos2dx 2.x

But because 3.0 use NativeActivity…
I have no idea how to add WebView

like this post…

The other engine “Unity”
It can add WebView and he is nativeActivity

Any idea??

Sorry for my poor english

@Yehsam I think it is the same to this tutorials.

I created a demo implementation of C++ to Java communication in Cocos2d-x v.3.2. Source here:

https://github.com/ElliotMebane/Cocos2d-x_CPP_to_Java_via_JNI_Samples

Stefan Nguyen’s post that was a foundation for my work:

http://stnguyen.com/cocos2d-x/call-java-functions-from-cpp.html