参考:http://codingnow.cn/cocos2d-x/992.html
参考了Himi的博客:http://www.himigame.com/android-game/725.html,总结一下在VS2010上面实现如何在cocos2dx项目里利用JNI调用Android的java层代码。
本人用的是cocos2d-x 2.2.2版本,就用最简单的HelloCpp来当做例子。讲例子之前,希望刚接触的朋友还是先去看看Himi的博客:http://www.himigame.com/android-game/725.html 了解一下JNI大致的一个用法。
在VS2010里面新建TestJNI.h头文件:
<span style="font-size:14px;">#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include <jni.h>
#include "platform/android/jni/JniHelper.h"
#endif
#include "cocos2d.h"
USING_NS_CC;
class TestJNI
{
public:
void test1();
void test2();
void test3();
};
</span>
其中在写第一行到第四行的时候,本人编译器就自动报了错:说是找不到jni.h头文件,这个错误估计很多人都会遇到,下面说一下解决的办法:
第一步:选中HelloCpp项目,然后:项目->属性->配置属性->VC++目录->包含目录
第二步,在包含目录右边的路径中把JDK安装目录下的D:\jdk1.6\include和D:\jdk1.6\include\win32的路径加到里面去,本人添加的路径是:D:\jdk1.6\include;D:\jdk1.6\include\win32; 。路径之间用“;”分号隔开,还有把上面的路径改成你们机器下面的具体路径就行了。 添加完成之后,点确定按钮,过一会编译就能通过了。然后去cocos2dx的安装目录下的Debug.win32目录下拷贝几个已经编译好的库文件(本人机器上的路径是:E:\develop_sofware\cocos2d-x-2.2.2\cocos2d-x-2.2.2\Debug.win32),我个人就懒得每个去报了错就去这个目录下找,我是直接拷贝Debug.win32这个目录下的所有文件到:HelloCpp工程目录下的Debug.win32里面去(本人目录:E:\develop_sofware\cocos2d-x-2.2.2\cocos2d-x-2.2.2\samples\Cpp\HelloCpp\proj.win32\Debug.win32)。
不拷贝的话,生成的时候会报诸如:找不到 libcocos2d.lib文件,这些错误。
然后还要配置一下”链接器->输入->附加依赖项",附加依赖项的值增加:如:libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies
如下图:
这样配置VS基本就应用没什么问题了。(注:每个工程都要这么配置一下!是比较坑爹,我也很郁闷,如果同学们有其他好的方法也请麻烦告诉一下,谢谢!)
测试一下是否可用吧,在VS2010里面再新建一个TestJNI.cpp文件(这里吐槽一下,vs不知道怎么想的,创建头文件的时候不会自动创建相应的CPP文件,可能是本人不会用吧,毕竟没怎么用过VS。Xcode这一点就做的不错。)
<span style="font-size:14px;">#include "TestJNI.h"
void TestJNI::test1(){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)//判断当前是否为Android平台
// 调用Android里面无参数、无返回值的静态方法
JniMethodInfo methodInfo;
bool isHave = JniHelper::getStaticMethodInfo(methodInfo,"org.cocos2dx.hellocpp.TestJNI","testNoParameNoReturn","()V");
if(!isHave)
{
methodInfo.env->CallStaticVoidMethod(methodInfo.classID,methodInfo.methodID);
}
#endif
}
void TestJNI::test2(){
// 有参数,无返回值
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)//判断当前是否为Android平台
JniMethodInfo methodInfo;
bool isCall = JniHelper::getStaticMethodInfo(methodInfo,"org.cocos2dx.hellocpp.TestJNI","testNoParameButReturn","(I)V");
if(isCall)
{
methodInfo.env->CallStaticVoidMethod(methodInfo.classID,methodInfo.methodID,999);
}
#endif
}</span>
简单说一下大致的意思:在test1()方法中,先判断一下当前环境是否是Android,如果是就执行#if #endif块中的代码。定义一个JniMethodInfo类型的对象 methodInfo ,然后把它传到JniHelper::getStaticMethodInfo()方法中。简单说一下JniHelper::getStaticMethodInfo(参数1,参数2,参数3,参数4)这个方法的四个参数:
参数1:JniMethodInfo类型的实例
参数2:需要调用的Android层下面定义了该方法的类的完整路径
参数3:需要调用的方法的名字
参数4:描述参数的参数列表和返回值
前面3个参数都比较好理解,后面第4个参数就要再多说几句:test1()方法中的"()V",代表的意思是:此函数无参数无返回值。再举个例子:如果Android上面写了这么一个函数:public float getIndex(int index); 参数4就要传入"(I)F",代表调用的方法有一个Int类型的参数,并且会返回一个float类型的数据。具体的类型对照表请看下面:
参数、返回值样式对照表:
调用了JniHelper::getStaticMethodInfo()函数之后,会有个bool返回值,true代表找到了这个方法,false就代表没找着。然后就通过JniMethodInfo类型的对象 methodInfo获得成员变量env,最后通过env调用CallStaticVoidMethod函数来具体调用Android层上面对应的那个方法。(是不是感觉有点像java的反射?呵呵)。
好,VS上面的代码就写到这里,再看看Android工程里面是怎么弄的:
第一步,先导入HelloCpp工程(去cocos2d目录下面去找,本人的路径是:E:\develop_sofware\cocos2d-x-2.2.2\cocos2d-x-2.2.2\samples\Cpp\HelloCpp\proj.android);
第二步,点开工程目录下的jni目录,如下图:
然后打开Android.mk文件,在里面把我们刚才在VS上面新建的那个TestJNI.cpp文件路径也弄进去(注:经常有的时候在VS或者Xcode上面新加了cpp文件,忘记加到这里去,编译的时候老是通过不过,这个地方要小心点!),具体如下:
第三步,编写TestJNI.java文件(这个名字随便起,不过要对应VS上面调用的类名),代码如下:
然后运行,效果如下:
这里注明一下:Android工程的sdk版本必须是2.3以上才能运行正常。
关于多参数传递的问题:
举例:
java代码中有:
public static void showThree(bool b, int i)
那么对应的C++调用代码为:
void TestJNI::showThree(bool b, int i){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)//判断当前是否为Android平台
JniMethodInfo jmi;
bool ishave = JniHelper::getStaticMethodInfo(jmi,Package_Utils_Path,"showThree","(ZI)V");
if(ishave)
{
jboolean isShow = b;
jint p = i;
jmi.env->CallStaticVoidMethod(jmi.classID,jmi.methodID,isShow,p);
}
#endif
}
上面代码中的"(ZI)V",表示:该函数包含两个参数,分别是:java中的boolean类型和int类型,返回值为void。
总结:获取多参数函数的时候,参数类型之间不用写分隔符。