cocos2d-x中通过jni调用android方法
2014-10-04 17:28
323 查看
最近的一个Cocos项目有使用到JNI,结果又是通过百度来查找使用方法,为了方便以后查看,在这里小结一下,应该会比较适合初次使用Jni的小伙伴们:)
JNI是Java Native Interface的缩写,中文为JAVA本地调,是Java语言提供的一种通用接口,用于Java代码与本地化代码的交互。
所谓本地化代码(Native Code)是指已被编译为特定于处理器的二进制代码,如Windows下的DLL,MAC OS X下的SO文件。
通过JNI可以实现C++与Java的相互调用。
这里主要是讲解在Cocos2d-x中通过Jni调用Java方法。
以下将会从创建一个新项目开始,完整讲解Jni的使用过程
在JniMethod.java中写了一些静态方法,供C++中调用
JniMethod.java
JniMethod.h
JniMethod.cpp
参数返回值类型 的签名(Signature)与Java类型 的对应关系,有了这个对应关系以上写的函数就很好理解了
下面列出常用的一些调用方法
callAndroidFunc7 中 jint *intArr = minfo.env->GetIntArrayElements(jarr,NULL);
通过函数GetIntArrayElements来获得jintArray中的数组指针,然后通过指针操作数组元素
这里给出其它数组类型的函数,通过看Array Type的类型,可以看到不同类型的数组有不同的JNI类型名
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://blog.csdn.net/jiangwei0910410003/article/details/17653803
JNI是Java Native 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
package com.game.JniMethod; import android.util.Log; public class JniMethod { // 不带参数 public static void AndroidFunc1() { Log.d("jni", "AndroidFunc1 called"); } // 带一个float参数 public static void AndroidFunc2(float number) { Log.d("jni", "AndroidFunc2 called: " + number); } // 带一个String参数 public static void AndroidFunc3(String name) { Log.d("jni", "AndroidFunc3 called: " + name); } // 带两个参数 public static void AndroidFunc4(String name, int age) { Log.d("jni", "AndroidFunc4 called: " + age); } // 带一个boolean参数,并返回一个int public static int AndroidFunc5(boolean flag) { Log.d("jni", "AndroidFunc5 called"); return flag ? 10 : 100; } // 带一个int 数组参数 public static void AndroidFunc6(int arr[]) { int sum = 0; for (int i : arr) { sum += i; } Log.d("jni", "AndroidFunc6 called: " + sum); } // 返回一个int 数组 public static int[] AndroidFunc7() { int arr[] = {10, 20, 30, 40}; return arr; } }
3、用xcode 打开项目的C++工程, 在Class目录下新建C++类JniMethod.h、JniMethod.cpp,在这个类中调用刚才写的Java静态方法。
JniMethod.h
</pre><pre>
// // JniMethod.h // UseJni // // Created by try on 14-10-3. // // #ifndef __UseJni__JniMethod__ #define __UseJni__JniMethod__ #include <stdio.h> #if defined(ANDROID) class JniMethod { public: static void callAndroidFunc1(); static void callAndroidFunc2(float number); static void callAndroidFunc3(std::string name); static void callAndroidFunc4(std::string name, int age); static int callAndroidFunc5(bool flag); static void callAndroidFunc6(std::vector<int> arr); static std::vector<int> callAndroidFunc7(); }; #endif #endif /* defined(__UseJni__JniMethod__) */
JniMethod.cpp
// // JniMethod.cpp // UseJni // // Created by try on 14-10-3. // // //#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "cocos2d.h" #include "JniMethod.h" #if defined(ANDROID) #include "platform/android/jni/JniHelper.h" USING_NS_CC; // 调用android静态方法:没有参数 void JniMethod::callAndroidFunc1() { JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc1", "()V"); CCASSERT(isHave, "jni callAndroidFunc1 not found"); if (isHave) { minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID); } } // 调用android静态方法:一个float参数 void JniMethod::callAndroidFunc2(float number) { JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc2", "(F)V"); CCASSERT(isHave, "jni callAndroidFunc1 not found"); if (isHave) { minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, number); } } // 调用android静态方法:一个string参数 void JniMethod::callAndroidFunc3(std::string name) { JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc3", "(Ljava/lang/String;)V"); CCASSERT(isHave, "jni callAndroidFunc3 not found"); if (isHave) { jstring jStr = minfo.env->NewStringUTF(name.c_str()); minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jStr); } } // 调用android静态方法:多个参数 void JniMethod::callAndroidFunc4(std::string name, int age) { JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc4", "(Ljava/lang/String;I)V"); CCASSERT(isHave, "jni callAndroidFunc4 not found"); if (isHave) { jstring jName = minfo.env->NewStringUTF(name.c_str()); minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jName, age); } } // int JniMethod::callAndroidFunc5(bool flag) { JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc5", "(Z)I"); CCASSERT(isHave, "jni callAndroidFunc5 not found"); if (isHave) { jint num = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID, flag); return num; } return -1; } // void JniMethod::callAndroidFunc6(std::vector<int> arr) { JniMethodInfo 4000 minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc6", "([I)V"); CCASSERT(isHave, "jni callAndroidFunc6 not found"); if (isHave) { jintArray jarr = minfo.env->NewIntArray(arr.size()); jint *intArr = minfo.env->GetIntArrayElements(jarr, NULL); for (int i = 0; i < arr.size(); ++i) { // http://www.2cto.com/kf/201312/268735.html intArr[i] = arr[i]; } minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jarr); } } // std::vector<int> JniMethod::callAndroidFunc7() { std::vector<int> arr; JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod", "AndroidFunc7", "()[I"); CCASSERT(isHave, "jni callAndroidFunc7 not found"); if (isHave) { jintArray jarr = (jintArray)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); jsize len = minfo.env->GetArrayLength(jarr); jint *intArr = minfo.env->GetIntArrayElements(jarr, NULL); for (int i = 0; i < len; ++i) { arr.push_back(intArr[i]); } } return arr; } #endif
4、在HelloWorldScene.cpp中调用JniMethod.cpp的方法,这里是直接放到bool HelloWorld::init()方法中调用的
#if defined(ANDROID) JniMethod::callAndroidFunc1(); JniMethod::callAndroidFunc2(3.14f); JniMethod::callAndroidFunc3("hello"); JniMethod::callAndroidFunc4("hello", 3); int ret = JniMethod::callAndroidFunc5(true); log("callAndroidFunc5: %d", ret); std::vector<int> arr6; arr6.push_back(1); arr6.push_back(20); arr6.push_back(300); JniMethod::callAndroidFunc6(arr6); std::vector<int> arr7 = JniMethod::callAndroidFunc7(); for (int i : 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函数信息结构体 JniMethodInfo minfo;
// 查找函数是否存在 // 第二个参数为函数所在的包名+类名,注意以“/”分隔 // 第三个参数为函数名 // 最后一个参数是函数的参数与返回值的描述信息,括号里的是传入的参数类型,括号右边的是返回值类型, // AndroidFunc1为无参所以括号内为空没有返回值,括号右边的返回值类型为V bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/game/JniMethod/JniMethod","AndroidFunc1","()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静态函数,前两个参数为固定写法,从第三个参数起可以加自己传入的参数 minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID) // 没有返回值的静态函数调用为 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#wp20949http://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://blog.csdn.net/jiangwei0910410003/article/details/17653803
相关文章推荐
- cocos2d-x中通过jni调用android方法
- Android通过JNI调用cocos2d-x中的C++方法
- 在android中通过JNI调用本地方法
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法 边缘检测 范例代码
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(下)
- Cocos2d-x游戏开发之Cocos2dx通过JNI调用Android的Java代码(webView实例)
- Android JNI 通过C/C++调用JAVA方法
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(上)
- android实现app通过jni调用C/C++方法
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法实现边缘检测代码(2)
- 【iOS-cocos2d-X 游戏开发之十三】详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- Cocos2d-x3.3RC0通过JNI调用Android的Java层URI代码发送短信
- Cocos2d-x3.3RC0通过JNI调用Android的Java层代码,实现分享功能
- 在eclipse下,JAVA通过JNI调用C++方法的简单例子(非android)
- 【iOS-cocos2d-X 游戏开发之十三】详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- android实现app通过jni调用C/C++方法
- Cocos2d-x3.3RC0通过JNI调用Android的Java层URI代码发送短信
- Cocos2d-x学习之通过Jni调用Android的Java层代码
- [转]Android通过NDK调用JNI,使用opencv做本地c++代码开发配置方法
- 【学习Android NDK开发】Java通过JNI调用native方法