Cocos2d-x3.3RC0通过JNI实现Java与C++互调(一)

2015-01-27 14:05:40 · 作者: · 浏览: 314

一、JNI

JNI(Java Native Interface):Java的本地调用。本文通过JNI在Cocos2d-x3.3RC0中完成Java与C++的互调。具体实现以下两个功
能:(1)通过Android sdk的API得到应用程序的包名,并传递给C++层函数。(2)通过C++函数调用Android的Java层函数,显示一个对话框。点击按钮退出程序。
详细知识见:http://blog.csdn.net/yuxikuo_1/article/details/39577257。其中最重要的是JNIEnv,这是一个C结构体。封装了许多
常用函数:具体如下:
struct _JNIEnv {
????/* do not rename this; it does not seem to be entirely opaque */
????const struct JNINativeInterface* functions;
?
#if defined(__cplusplus)
?
????jint GetVersion()
????{ return functions->GetVersion(this); }
?
????jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
????????jsize bufLen)
????{ return functions->DefineClass(this, name, loader, buf, bufLen); }
?
????jclass FindClass(const char* name)
????{ return functions->FindClass(this, name); }
// 这里省略其他函数...
?
}
Cocos2d-x对jni的操作进行了封装,提供JniHelper类解决Java与C++的通信。
下面介绍两个常用的函数:

1、getStaticMethodInfo:

用来判断java类中静态函数是否存在,初始化结构体JniMethodInfo。该结构体封装了JNIEnv*和java.lang.Class、函数ID。这样可以使用JNIEnv*调用CallStaticXXXMethod(jclass clazz,jmethodID methodID,...)和CallXXXMethod(jobject obj,jmethodID methodID,...)等常用函数,其中XXX代表函数返回值类型,如void、int等。如下代码:参数1:JniMethodInfo,参数2:类的绝对路径,该路径为:proj.android/src/下的目录,例如引擎模板工程下的路径为:src/org/cocos2dx/cpp/XXX。XXX为cpp下的java文件。记住路径中不用加.java后缀,因为路径使用的是类名。参数3:函数名,参数4:函数签名,具体规则见3类型签名

JniMethodInfo info;  
bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/AppActivity","getObj","()Ljava/lang/Object;");  
jobject jobj;  
if(ret)  
{  
    log("call void getObj() succeed");  
    jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID);  
}  
  
bool re = JniHelper::getMethodInfo(info,"org/cocos2dx/cpp/AppActivity","func1","()V");  
if(re)  
{  
    log("call func1 succeed");  
    info.env->CallVoidMethod(jobj,info.methodID);  
}  

2、getMethodInfo:用于调用Java类的非静态函数


#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
    JniMethodInfo info;  
    //判断org/cocos2dx/cpp/AppActivity.java中是否存在getObj静态函数  
    bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/AppActivity","getObj","()Ljava/lang/Object;");  
    jobject jobj;//用于存放返回的对象  
    if(ret)  
    {  
        log("call void getObj() succeed");  
        jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID);//调用getObj函数,返回一个对象  
    }  
    //判断org/cocos2dx/cpp/AppActivity.java中是否存在func1非静态函数  
    bool re = JniHelper::getMethodInfo(info,"org/cocos2dx/cpp/AppActivity","func1","()V");  
    if(re)  
    {  
        log("call func1 succeed");  
        info.env->CallVoidMethod(jobj,info.methodID);//通过返回的对象调用非静态函数  
    }  
      
#endif  

3、类型签名

类型签名 Java类型
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L full-qualified-class; 完全限定的类
[ type type[ ]
(arg-types) ret-type 方法类型

如java方法:long f(int n,String s,int[] arr); 类型签名为:(ILjava/lang/String;[I)J。注意L后的分号,[是半开的,要与类型签名完全一致。

二、具体步骤

1、创建Cocos2d-x3.3RC0工程

这个不做过多介绍,既然研究到Jni了,相比都不是太菜鸟了。

2、ADT与XCode分别导入工程

3、Xcode的Class目录下添加JniTest类

\
JniTest.h代码如下:JniTest.cpp暂时没有代码
#ifndef __JniDemo__JniTest__
#define __JniDemo__JniTest__

#include "cocos2d.h"
USING_NS_CC;

void setPackageName(const char* packageName)//从Java层传过来的包名在此处打印出来
{
    log("packageName = %s",packageName);
}

void exitApp()//Java层调用C++层的该函数,关闭程序。
{
    Director::getInstance()->end();
}

然后在HelloWorldScen