最近的一个cocos项目有使用到JNI,结果又是通过百度来查找使用方法,为了方便以后查看,在这里小结一下,应该会比较适合初次使用Jni的小伙伴们:)
JNI是JavaNative Interface的缩写,中文为Java本地调,是Java语言提供的一种通用接口,用于Java代码与本地化代码的交互。
所谓本地化代码(Native Code)是指已被编译为特定于处理器的二进制代码,如Windows下的DLL,MAC OS X下的SO文件。
通过JNI可以实现C++与Java的相互调用。
这里主要是讲解在Cocos2d-x中通过Jni调用Java方法。
以下将会从创建一个新项目开始,完整讲解Jni的使用过程
1、创建一个Cocos2d-x的C++项目,包名“com.game.UseJni”
2、在Eclipse中导入项目中的Android工程,在src目录下新建包“com.game.JniMethod”,并在包中新建一个java件“JniMethod.java”。这里的名字都是随意取的,在C++调用时会用到。
在JniMethod.java中写了一些静态方法,供C++中调用
JniMethod.java
- packagecom.game.JniMethod;
- importandroid.util.Log;
- publicclassJniMethod
- {
-
- staticvoidAndroidFunc1()
- {
- Log.d("jni","AndroidFunc1called");
- }
-
- voidAndroidFunc2(floatnumber)
- Log.d("jni","AndroidFunc2called:"+number);
- }
- //带一个String参数
- voidAndroidFunc3(Stringname)
- "AndroidFunc3called:"+name);
- //带两个参数
- voidAndroidFunc4(Stringname,intage)
- "AndroidFunc4called:"+age);
- //带一个boolean参数,并返回一个int
- intAndroidFunc5(booleanflag)
- "AndroidFunc5called");
- returnflag?10:100;
- //带一个int数组参数
- voidAndroidFunc6(intarr[])
- intsum=0;
- for(inti:arr)
- sum+=i;
- "AndroidFunc6called:"+sum);
- //返回一个int数组
- int[]AndroidFunc7()
- intarr[]={10,20,0); background-color:inherit">30,0); background-color:inherit">40};
- returnarr;
- }
3、用xcode打开项目的C++工程, 在Class目录下新建C++类JniMethod.h、JniMethod.cpp,在这个类中调用刚才写的Java静态方法。
JniMethod.h
</pre><pre>
//
- //JniMethod.h
- //UseJni
- //
- //Createdbytryon14-10-3.
-
- #ifndef__UseJni__JniMethod__
- #define__UseJni__JniMethod__
-
- #include<stdio.h>
- #ifdefined(ANDROID)
- classJniMethod
- public:
- voidcallAndroidFunc1();
- voidcallAndroidFunc2(floatnumber);
- voidcallAndroidFunc3(std::stringname);
- voidcallAndroidFunc4(std::stringname,intage);
- staticintcallAndroidFunc5(boolflag);
- voidcallAndroidFunc6(std::vector<int>arr);
- staticstd::vector<int>callAndroidFunc7();
- };
- #endif
- #endif/*defined(__UseJni__JniMethod__)*/
JniMethod.cpp
//JniMethod.cpp
- //#if(CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)
- #include"cocos2d.h"
- #include"JniMethod.h"
- #include"platform/android/jni/JniHelper.h"
- USING_NS_CC;
- //调用android静态方法:没有参数
- voidJniMethod::callAndroidFunc1()
- JniMethodInfominfo;
- boolisHave=JniHelper::getStaticMethodInfo(minfo,"com/game/JniMethod/JniMethod","AndroidFunc1","()V");
- CCASSERT(isHave,"jnicallAndroidFunc1notfound");
- if(isHave)
- minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID);
- //调用android静态方法:一个float参数
- voidJniMethod::callAndroidFunc2(floatnumber)
- JniMethodInfominfo;
- "AndroidFunc2","(F)V");
- CCASSERT(isHave,"jnicallAndroidFunc1notfound");
- if(isHave)
- minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID,number);
- //调用android静态方法:一个string参数
- voidJniMethod::callAndroidFunc3(std::stringname)
- "AndroidFunc3","(Ljava/lang/String;)V");
- "jnicallAndroidFunc3notfound");
- jstringjStr=minfo.env->NewStringUTF(name.c_str());
- //调用android静态方法:多个参数
- voidJniMethod::callAndroidFunc4(std::stringname,87); background-color:inherit; font-weight:bold">intage)
- "AndroidFunc4","(Ljava/lang/String;I)V");
- "jnicallAndroidFunc4notfound");
- jstringjName=minfo.env->NewStringUTF(name.c_str());
- intJniMethod::callAndroidFunc5(boolflag)
- "AndroidFunc5","(Z)I");
- "jnicallAndroidFunc5notfound");
- jintnum=minfo.env->CallStaticIntMethod(minfo.classID,flag);
- returnnum;
- return-1;
- voidJniMethod::callAndroidFunc6(std::vector<int>arr)
- "AndroidFunc6","([I)V");
- "jnicallAndroidFunc6notfound");
- jintArrayjarr=minfo.env->NewIntArray(arr.size());
- jint*intArr=minfo.env->GetIntArrayElements(jarr,NULL);
- for(inti=0;i<arr.size();++i)
- //http://www.2cto.com/kf/201312/268735.html
- intArr[i]=arr[i];
- std::vector<int>JniMethod::callAndroidFunc7()
- int>arr;
- "AndroidFunc7","()[I");
- "jnicallAndroidFunc7notfound");
- jintArrayjarr=(jintArray)minfo.env->CallStaticObjectMethod(minfo.classID,minfo.methodID);
- jsizelen=minfo.env->GetArrayLength(jarr);
- jint*intArr=minfo.env->GetIntArrayElements(jarr,NULL);
- inti=0;i<len;++i)
- arr.push_back(intArr[i]);
- returnarr;
- #endif
4、在HelloWorldScene.cpp中调用JniMethod.cpp的方法,这里是直接放到boolHelloWorld::init()方法中调用的
#ifdefined(ANDROID)
- JniMethod::callAndroidFunc1();
- JniMethod::callAndroidFunc2(3.14f);
- JniMethod::callAndroidFunc3("hello");
- JniMethod::callAndroidFunc4("hello",3);
- intret=JniMethod::callAndroidFunc5(true);
- log("callAndroidFunc5:%d",ret);
- int>arr6;
- arr6.push_back(1);
- arr6.push_back(20);
- arr6.push_back(300);
- JniMethod::callAndroidFunc6(arr6);
- int>arr7=JniMethod::callAndroidFunc7();
- inti:arr7)
- log("callAndroidFunc7:%i",i);
- #endif
5、修改UseJni/proj.android/jni工程目录下的Android.mk文件,添加JniMethod.cpp
6、在终端运行UseJni/proj.android目录下的build_native.py,编译成功,可以看到生成了SO文件
7、回到Eclipse,刷新安卓工程然后运行,可以在日志中查看运行结果
Tag为“jni”的是在安卓中自己输出的日志,Tag为“Cocos2d-x debug info”的是在C++中输出的日志
8、程序写完了,这里说明一下上面的函数使用方法,主要是JniMethod.cpp中的内容
//定义Jni函数信息结构体
- JniMethodInfominfo;
//查找函数是否存在
- //第二个参数为函数所在的包名+类名,注意以“/”分隔
- //第三个参数为函数名
- //最后一个参数是函数的参数与返回值的描述信息,括号里的是传入的参数类型,括号右边的是返回值类型,
- //AndroidFunc1为无参所以括号内为空没有返回值,括号右边的返回值类型为V
- "()V");
//AndroidFunc2的参数描述信息是"(F)V",传入参数为float(签名F),返回值为空(签名V)
- //AndroidFunc4的参数描述信息是"(Ljava/lang/String;I)V",传入参数为String(签名Ljava/lang/String;)和int(符号I),返回值为空(签名V)
- //AndroidFunc6的参数描述信息是"([I)V",传入参数为int[](签名[I),返回值为int(签名I)
参数返回值类型 的签名(Signature)与Java类型 的对应关系,有了这个对应关系以上写的函数就很好理解了
//调用Java静态函数,前两个参数为固定写法,从第三个参数起可以加自己传入的参数
- //没有返回值的静态函数调用为CallStaticVoidMethod,注意函数名中的Void
- //返回int的静态函数调用为CallStaticIntMethod,注意函数名中的Int,我在这犯了不少错。。。
下面列出常用的一些调用方法
callAndroidFunc7中jint *intArr = minfo.env->GetIntArrayElements(jarr,NULL);
通过函数GetIntArrayElements来获得jintArray中的数组指针,然后通过指针操作数组元素
这里给出其它数组类型的函数,通过看Array Type的类型,可以看到不同类型的数组有不同的JNI类型名
9、参考文献
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp20949
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp23720
http://www.linuxidc.com/Linux/2011-10/44997.htm
http://xiaominghimi.blog.51cto.com/2614927/908818/
http://public0821.iteye.com/blog/423941
http://www.52php.cn/article/p-qumwvlyp-qy.html (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|