Cocos2dx: Call Java code from C++ or Call C++ code from Java using JNI


Call Java code from C++

Step 1: Include Jni folder

  • Right click on project => Properties => C/C++ General => Paths and Symbols => (Right side) Select Source Location => Click Link Folder => Check Link to folder in the file system => Browse /Cocos2d/cocos2dx/platform/android/jni => Open
  • If the folder already existed in Source location then and error will show up, “The folder ‘jni’ already exists.” => Cancel
    otherwise, click OK

Step 2: Create Cpp class

  • Create a Cpp class (both .h and .cpp) named JniLink.h and JniLink.cpp in /Cocos2d/cocos2dx/platform/android/jni/

JniLink.h

/*
 * JniLink.h
 */

#ifndef JNILINK_H_
#define JNILINK_H_

extern "C"
{
	extern void openURL(const char* url);
}

#endif /* JNILINK_H_ */

JniLink.cpp


/*
 * JniLink.cpp
 */


#include "JniLink.h"
#include "JniHelper.h"

using namespace cocos2d;

extern "C"
{

	void openURL(const char* url)
	{
		JniMethodInfo t;

		if (JniHelper::getStaticMethodInfo(t,
				"org/cocos2dx/lib/Cocos2dxActivity", 	// fully qualified class name
				"openURL", 								// method name
				"(Ljava/lang/String;)V")) {				// data type of argument

			// jstring - C++ representation of Java String
			jstring stringArg = t.env->NewStringUTF(url);

			// call the method, with arguments
			t.env->CallStaticVoidMethod(t.classID, t.methodID, stringArg);
		}
	}
}

Step 3: Java code

  • Open Java class from Project src/org/cocos2dx/lib/Cocos2dxActivity
  • Change the code like following

Cocos2dxActivity.java


package org.cocos2dx.lib;

import org.cocos2dx.lib.Cocos2dxHelper.Cocos2dxHelperListener;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.view.ViewGroup;
import android.widget.FrameLayout;

public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener {
	// ===========================================================
	// Constants
	// ===========================================================

	private static final String TAG = Cocos2dxActivity.class.getSimpleName();

	// ===========================================================
	// Fields
	// ===========================================================
	
	private Cocos2dxGLSurfaceView mGLSurfaceView;
	private Cocos2dxHandler mHandler;
	private static Activity self = null;

	// ===========================================================
	// Constructors
	// ===========================================================

	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		this.self = this;
		
    	this.mHandler = new Cocos2dxHandler(this);

    	this.mGLSurfaceView = onCreateView();

		Cocos2dxHelper.init(this, this);
	}

   public static void openURL (String url) {
    	Intent aIntent = new Intent (Intent.ACTION_VIEW);
    	aIntent.setData(Uri.parse(url));
    	self.startActivity(aIntent);
    }

Step 4: Add the class to the Android.mk file

  • Open Android.mk file from Project jni/Android.mk
  • Add the newly added JniLink.cpp class reference like following

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := game_shared

LOCAL_MODULE_FILENAME := libgame

LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   /../../../cocos2dx/platform/android/jni/JniLink.cpp \
                   ../../Classes/HelloWorldScene.cpp
                   
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
					$(LOCAL_PATH)/../../../cocos2dx/platform/android/jni               

LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static cocos_extension_static
            
include $(BUILD_SHARED_LIBRARY)

$(call import-module,CocosDenshion/android) \
$(call import-module,cocos2dx) \
$(call import-module,extensions)

Step 5: Call the Java method from a Layer: HelloWorldScene.cpp

  • Include JniLink.h file to HelloWorldScene.cpp file
    #include "JniLink.h"
  • call method
    openURL("http://www.bing.com");
    from init() method

=============================================================================

Call C++ method from Java

Step 1: Create a cpp class

  • Create a cpp class (both .h and .cpp) named JniExample

JniExample.h


/*
 * JniExample.h
 */

#ifndef JNIEXAMPLE_H_
#define JNIEXAMPLE_H_


extern "C"
{
	void showMessageBoxJNI(const char * pszMsg, const char * pszTitle);
}

#endif /* JNIEXAMPLE_H_ */

JniExample.cpp


/*
 * JniExample.cpp
 */

#include "JniHelper.h"
#include "cocos2d.h"
#include "JniExample.h"

using namespace cocos2d;

extern "C"
{

	// the method name is required to be follow the fully qualified package format
	jstring Java_org_cocos2dx_lib_Cocos2dxActivity_nativeExample(JNIEnv * env, jobject thiz)
	{
		return env->NewStringUTF("Hello from C++");
	}

	// this method will call a Java method named "showMessageBox"
	void showMessageBoxJNI(const char * pszMsg, const char * pszTitle)
	{
		if (! pszMsg)
		{
			return;
		}
	
		JniMethodInfo t;
	
		if (JniHelper::getStaticMethodInfo(t
				, "org/cocos2dx/lib/Cocos2dxActivity"
				, "showMessageBox"
				, "(Ljava/lang/String;Ljava/lang/String;)V"))
		{
			jstring stringArg1;
	
			if (! pszTitle)
			{
				stringArg1 = t.env->NewStringUTF("");
			}
			else
			{
				stringArg1 = t.env->NewStringUTF(pszTitle);
			}
	
			jstring stringArg2 = t.env->NewStringUTF(pszMsg);
			t.env->CallStaticVoidMethod(t.classID, t.methodID, stringArg1, stringArg2);
	
			t.env->DeleteLocalRef(stringArg1);
			t.env->DeleteLocalRef(stringArg2);
			t.env->DeleteLocalRef(t.classID);
		}
	}
}

Step 2: Add JniExample.cpp to Android.mk

  • Carefully notice the class indicate sequence. “JniExample.cpp” is alphabetically smaller and need to be placed before “JniLink.cpp”

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := game_shared

LOCAL_MODULE_FILENAME := libgame

LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   /../../../cocos2dx/platform/android/jni/JniExample.cpp \
                   /../../../cocos2dx/platform/android/jni/JniLink.cpp \
                   ../../Classes/HelloWorldScene.cpp
                   
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
					$(LOCAL_PATH)/../../../cocos2dx/platform/android/jni               

LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static cocos_extension_static
            
include $(BUILD_SHARED_LIBRARY)

$(call import-module,CocosDenshion/android) \
$(call import-module,cocos2dx) \
$(call import-module,extensions)


Step 3: Update Cocos2dxActivity.java class

package org.cocos2dx.lib;

import org.cocos2dx.lib.Cocos2dxHandler.DialogMessage;
import org.cocos2dx.lib.Cocos2dxHelper.Cocos2dxHelperListener;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.FrameLayout;

public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener {
	// ===========================================================
	// Constants
	// ===========================================================

	private static final String TAG = Cocos2dxActivity.class.getSimpleName();

	// ===========================================================
	// Fields
	// ===========================================================
	
	private Cocos2dxGLSurfaceView mGLSurfaceView;
	private Cocos2dxHandler mHandler;
	private static Activity self = null;
	private final static int HANDLER_SHOW_DIALOG = 1;
	private static Handler handler;

	// ===========================================================
	// Constructors
	// ===========================================================

	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		this.self = this;
		
    	this.mHandler = new Cocos2dxHandler(this);

    	this.mGLSurfaceView = onCreateView();

		Cocos2dxHelper.init(this, this);
		
		handler = new Handler(){
        	public void handleMessage(Message msg){
        		switch(msg.what){
        		case HANDLER_SHOW_DIALOG:
        			showDialog(((DialogMessage)msg.obj).titile, ((DialogMessage)msg.obj).message);
        			break;
        		}
        	}
        };
	}

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	@Override
	protected void onResume() {
		super.onResume();

		Cocos2dxHelper.onResume();
		this.mGLSurfaceView.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();

		Cocos2dxHelper.onPause();
		this.mGLSurfaceView.onPause();
	}

	@Override
	public void showDialog(final String pTitle, final String pMessage) {
		Message msg = new Message();
		msg.what = Cocos2dxHandler.HANDLER_SHOW_DIALOG;
		msg.obj = new Cocos2dxHandler.DialogMessage(pTitle, pMessage);
		this.mHandler.sendMessage(msg);
	}

	@Override
	public void showEditTextDialog(final String pTitle, final String pContent, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength) { 
		Message msg = new Message();
		msg.what = Cocos2dxHandler.HANDLER_SHOW_EDITBOX_DIALOG;
		msg.obj = new Cocos2dxHandler.EditBoxMessage(pTitle, pContent, pInputMode, pInputFlag, pReturnType, pMaxLength);
		this.mHandler.sendMessage(msg);
	}
	
	@Override
	public void runOnGLThread(final Runnable pRunnable) {
		this.mGLSurfaceView.queueEvent(pRunnable);
	}

	// ===========================================================
	// Methods
	// ===========================================================
	
    public Cocos2dxGLSurfaceView onCreateView() {
    	// Init handler
    			
    	// FrameLayout
        ViewGroup.LayoutParams framelayout_params =
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                       ViewGroup.LayoutParams.FILL_PARENT);
        FrameLayout framelayout = new FrameLayout(this);
        framelayout.setLayoutParams(framelayout_params);

        // Cocos2dxEditText layout
        ViewGroup.LayoutParams edittext_layout_params =
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                       ViewGroup.LayoutParams.WRAP_CONTENT);
        Cocos2dxEditText edittext = new Cocos2dxEditText(this);
        edittext.setLayoutParams(edittext_layout_params);

        // ...add to FrameLayout
        framelayout.addView(edittext);

        // Cocos2dxGLSurfaceView
        Cocos2dxGLSurfaceView gLSurfaceView = new Cocos2dxGLSurfaceView(this);

        // ...add to FrameLayout
        framelayout.addView(gLSurfaceView);

        gLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
        gLSurfaceView.setCocos2dxEditText(edittext);

        // Set framelayout as the content view
		setContentView(framelayout);
		
		return gLSurfaceView;
    }
    
    public static void openURL (String url) {
    	Intent aIntent = new Intent (Intent.ACTION_VIEW);
    	aIntent.setData(Uri.parse(url));
    	self.startActivity(aIntent);
    }
    
    public static void showMessageBox(String title, String message) 
    {
    	
    	Message msg = new Message();
    	msg.what = HANDLER_SHOW_DIALOG;
    	
    	// calling this nativeExample() method from C++ 
    	msg.obj = new DialogMessage(title, nativeExample());
    	Log.d("tag", "I am here " + nativeExample());
    	handler.sendMessage(msg);
    }
    
    // This method body exists in C++, need to have "native" keyword 
    private static native String nativeExample();

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}

Step 4: Call from HelloWorldScene

  • include
    #include "JniExample.h"
  • Call the method
    showMessageBoxJNI("You shouldn't see this", "Java -> C++");

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s