cocos2d-x中通过jni调用android方法

最近的一个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的使用过程


1、创建一个Cocos2d-xC++项目,包名“com.game.UseJni”

2、在Eclipse中导入项目中的Android工程,在src目录下新建包“com.game.JniMethod”,并在包中新建一个java“JniMethod.java”。这里的名字都是随意取的,在C++调用时会用到。



在JniMethod.java中写了一些静态方法,供C++中调用


JniMethod.java

[java]  view plain  copy
  1. package com.game.JniMethod;  
  2. import android.util.Log;  
  3. public class JniMethod   
  4. {  
  5.     // 不带参数  
  6.     public static void AndroidFunc1()  
  7.     {  
  8.         Log.d("jni""AndroidFunc1 called");  
  9.     }  
  10.     // 带一个float参数  
  11.     public static void AndroidFunc2(float number)  
  12.     {  
  13.         Log.d("jni""AndroidFunc2 called: " + number);  
  14.     }  
  15.     // 带一个String参数  
  16.     public static void AndroidFunc3(String name)  
  17.     {  
  18.         Log.d("jni""AndroidFunc3 called: " + name);  
  19.     }  
  20.     // 带两个参数  
  21.     public static void AndroidFunc4(String name, int age)  
  22.     {  
  23.         Log.d("jni""AndroidFunc4 called: " + age);  
  24.     }  
  25.     // 带一个boolean参数,并返回一个int  
  26.     public static int AndroidFunc5(boolean flag)  
  27.     {  
  28.         Log.d("jni""AndroidFunc5 called");  
  29.         return flag ? 10 : 100;  
  30.     }  
  31.     // 带一个int 数组参数  
  32.     public static void AndroidFunc6(int arr[])  
  33.     {  
  34.         int sum = 0;  
  35.         for (int i : arr)   
  36.         {  
  37.             sum += i;  
  38.         }  
  39.         Log.d("jni""AndroidFunc6 called: " + sum);  
  40.     }  
  41.     // 返回一个int 数组  
  42.     public static int[] AndroidFunc7()  
  43.     {  
  44.         int arr[] = {10203040};  
  45.         return arr;  
  46.     }  
  47. }  


3、用xcode 打开项目的C++工程, 在Class目录下新建C++类JniMethod.h、JniMethod.cpp,在这个类中调用刚才写的Java静态方法。





JniMethod.h
[java]  view plain  copy
  1. </pre><pre>  

[cpp]  view plain  copy
  1. //  
  2. //  JniMethod.h  
  3. //  UseJni  
  4. //  
  5. //  Created by try on 14-10-3.  
  6. //  
  7. //  
  8.   
  9. #ifndef __UseJni__JniMethod__  
  10. #define __UseJni__JniMethod__  
  11.   
  12. #include <stdio.h>  
  13.   
  14. #if defined(ANDROID)  
  15.   
  16. class JniMethod  
  17. {  
  18. public:  
  19.     static void callAndroidFunc1();  
  20.     static void callAndroidFunc2(float number);  
  21.     static void callAndroidFunc3(std::string name);  
  22.     static void callAndroidFunc4(std::string name, int age);  
  23.     static int  callAndroidFunc5(bool flag);  
  24.     static void callAndroidFunc6(std::vector<int> arr);  
  25.     static std::vector<int> callAndroidFunc7();  
  26. };  
  27.   
  28. #endif  
  29. #endif /* defined(__UseJni__JniMethod__) */  

JniMethod.cpp

[cpp]  view plain  copy
  1. //  
  2. //  JniMethod.cpp  
  3. //  UseJni  
  4. //  
  5. //  Created by try on 14-10-3.  
  6. //  
  7. //  
  8. //#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  
  9. #include "cocos2d.h"  
  10. #include "JniMethod.h"  
  11.   
  12. #if defined(ANDROID)  
  13. #include "platform/android/jni/JniHelper.h"  
  14.   
  15. USING_NS_CC;  
  16.   
  17.   
  18. // 调用android静态方法:没有参数  
  19. void JniMethod::callAndroidFunc1()  
  20. {  
  21.     JniMethodInfo minfo;  
  22.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc1""()V");  
  23.       
  24.     CCASSERT(isHave, "jni callAndroidFunc1 not found");  
  25.       
  26.     if (isHave)  
  27.     {  
  28.         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);  
  29.     }  
  30.       
  31. }  
  32.   
  33. // 调用android静态方法:一个float参数  
  34. void JniMethod::callAndroidFunc2(float number)  
  35. {  
  36.     JniMethodInfo minfo;  
  37.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc2""(F)V");  
  38.       
  39.     CCASSERT(isHave, "jni callAndroidFunc1 not found");  
  40.       
  41.     if (isHave)  
  42.     {  
  43.         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, number);  
  44.     }  
  45. }  
  46.   
  47. // 调用android静态方法:一个string参数  
  48. void JniMethod::callAndroidFunc3(std::string name)  
  49. {  
  50.     JniMethodInfo minfo;  
  51.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc3""(Ljava/lang/String;)V");  
  52.   
  53.     CCASSERT(isHave, "jni callAndroidFunc3 not found");  
  54.       
  55.     if (isHave)  
  56.     {  
  57.         jstring jStr = minfo.env->NewStringUTF(name.c_str());  
  58.         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jStr);  
  59.     }  
  60. }  
  61.   
  62. // 调用android静态方法:多个参数  
  63. void JniMethod::callAndroidFunc4(std::string name, int age)  
  64. {  
  65.     JniMethodInfo minfo;  
  66.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc4""(Ljava/lang/String;I)V");  
  67.       
  68.     CCASSERT(isHave, "jni callAndroidFunc4 not found");  
  69.       
  70.     if (isHave)  
  71.     {  
  72.         jstring jName = minfo.env->NewStringUTF(name.c_str());  
  73.         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jName, age);  
  74.     }  
  75. }  
  76.   
  77. //  
  78. int  JniMethod::callAndroidFunc5(bool flag)  
  79. {  
  80.     JniMethodInfo minfo;  
  81.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc5""(Z)I");  
  82.       
  83.     CCASSERT(isHave, "jni callAndroidFunc5 not found");  
  84.       
  85.     if (isHave)  
  86.     {  
  87.         jint num = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID, flag);  
  88.         return num;  
  89.     }  
  90.     return -1;  
  91. }  
  92.   
  93. //  
  94. void JniMethod::callAndroidFunc6(std::vector<int> arr)  
  95. {  
  96.     JniMethodInfo minfo;  
  97.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc6""([I)V");  
  98.       
  99.     CCASSERT(isHave, "jni callAndroidFunc6 not found");  
  100.       
  101.     if (isHave)  
  102.     {  
  103.         jintArray jarr = minfo.env->NewIntArray(arr.size());  
  104.         jint *intArr = minfo.env->GetIntArrayElements(jarr, NULL);  
  105.         for (int i = 0; i < arr.size(); ++i)  
  106.         {  
  107.             // http://www.2cto.com/kf/201312/268735.html  
  108.             intArr[i] = arr[i];  
  109.         }  
  110.         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jarr);  
  111.     }  
  112. }  
  113.   
  114. //  
  115. std::vector<int> JniMethod::callAndroidFunc7()  
  116. {  
  117.     std::vector<int> arr;  
  118.     JniMethodInfo minfo;  
  119.     bool isHave = JniHelper::getStaticMethodInfo(minfo, "com/game/JniMethod/JniMethod""AndroidFunc7""()[I");  
  120.       
  121.     CCASSERT(isHave, "jni callAndroidFunc7 not found");  
  122.       
  123.     if (isHave)  
  124.     {  
  125.         jintArray jarr = (jintArray)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);  
  126.         jsize len = minfo.env->GetArrayLength(jarr);  
  127.         jint *intArr = minfo.env->GetIntArrayElements(jarr, NULL);  
  128.         for (int i = 0; i < len; ++i)  
  129.         {  
  130.             arr.push_back(intArr[i]);  
  131.         }  
  132.     }  
  133.   
  134.     return arr;  
  135. }  
  136.   
  137. #endif  

4、在HelloWorldScene.cpp中调用JniMethod.cpp的方法,这里是直接放到bool HelloWorld::init()方法中调用的

[cpp]  view plain  copy
  1. #if defined(ANDROID)  
  2.       
  3.     JniMethod::callAndroidFunc1();  
  4.     JniMethod::callAndroidFunc2(3.14f);  
  5.     JniMethod::callAndroidFunc3("hello");  
  6.     JniMethod::callAndroidFunc4("hello", 3);  
  7.           
  8.     int ret = JniMethod::callAndroidFunc5(true);  
  9.     log("callAndroidFunc5: %d", ret);  
  10.       
  11.     std::vector<int> arr6;  
  12.     arr6.push_back(1);  
  13.     arr6.push_back(20);  
  14.     arr6.push_back(300);  
  15.     JniMethod::callAndroidFunc6(arr6);  
  16.       
  17.     std::vector<int> arr7 = JniMethod::callAndroidFunc7();  
  18.     for (int i : arr7)  
  19.     {  
  20.         log("callAndroidFunc7: %i", i);  
  21.     }  
  22.       
  23. #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中的内容

[cpp]  view plain  copy
  1. // 定义Jni函数信息结构体  
  2. JniMethodInfo minfo;    
[cpp]  view plain  copy
  1. // 查找函数是否存在  
  2. // 第二个参数为函数所在的包名+类名,注意以“/”分隔  
  3. // 第三个参数为函数名  
  4. // 最后一个参数是函数的参数与返回值的描述信息,括号里的是传入的参数类型,括号右边的是返回值类型,  
  5. // AndroidFunc1为无参所以括号内为空没有返回值,括号右边的返回值类型为V  
  6. bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/game/JniMethod/JniMethod","AndroidFunc1","()V");   
[cpp]  view plain  copy
  1. // AndroidFunc2的参数描述信息是"(F)V",传入参数为float(签名F),返回值为空(签名V)  
  2. // AndroidFunc4的参数描述信息是"(Ljava/lang/String;I)V",传入参数为String(签名Ljava/lang/String;)和int(符号I),返回值为空(签名V)  
  3. // AndroidFunc6的参数描述信息是"([I)V",传入参数为int[](签名[I),返回值为int(签名I)  



参数返回值类型 的签名(Signature)与Java类型 的对应关系,有了这个对应关系以上写的函数就很好理解了




[cpp]  view plain  copy
  1. // 调用Java静态函数,前两个参数为固定写法,从第三个参数起可以加自己传入的参数  
  2. minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID)  
  3.   
  4. // 没有返回值的静态函数调用为 CallStaticVoidMethod,注意函数名中的Void  
  5. // 返回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://blog.csdn.net/jiangwei0910410003/article/details/17653803

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值