一、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结构体。封装了许多
常用函数:具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
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类型签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
2、getMethodInfo:用于调用Java类的非静态函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
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暂时没有代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
然后在HelloWorldScene.cpp中包含如下头文件,并在menuCloseCallback中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
4、Jni层代码
打开ADT工程目录下的jni/hellocpp/列表,在hellocpp下添加c++类,test.cpp和test.h。代码如下:一定包含extern "C"
1 2 3 4 5 6 7 8 |
|
test.cpp代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
5、Java层函数
在ADT工程目录src/org.cocos2dx.cpp的目录下添加java类,JniTestHelper.java
1)JniTestHelper.java代码如下:
2)AppActivity.java代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package
org.cocos2dx.cpp;
import
org.cocos2dx.lib.Cocos2dxHandler.DialogMessage;
import
android.os.Handler;
import
android.os.Message;
public
class
JniTestHelper {
private
static
Handler mHandler;
//Java的Handler传递消息
public
static
void
init(Handler handler) {
JniTestHelper.mHandler = handler;
}
public
static
native
void
setPackageName(String packageName);
//声明两个静态nativa函数,在Jni中test.cpp中定义,调用C++层的对应函数。
public
static
native
void
exitApp();
private
static
void
showTipDialog(
final
String title,
final
String text)
{
Message msg = mHandler.obtainMessage();
//接受消息
msg.what = AppActivity.SHOW_DIALOG;
DialogMessage dm =
new
DialogMessage(title, text);
//重点是这一步,之前的教程自己定的数据结构,而新版本的Cocos的
dm.titile = title;<span style=
"white-space:pre"
> </span>
//Jni库为我们提供了DialogMessage这个数据结构类。所以不用自定义
dm.message = text;
msg.obj = dm;
msg.sendToTarget();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package
org.cocos2dx.cpp;
import
org.cocos2dx.lib.Cocos2dxActivity;
import
org.cocos2dx.lib.Cocos2dxGLSurfaceView;
import
org.cocos2dx.lib.Cocos2dxHandler.DialogMessage;
import
android.app.AlertDialog;
import
android.content.DialogInterface;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
public
class
AppActivity
extends
Cocos2dxActivity{
public
static
final
int
SHOW_DIALOG =
0x0001
;
protected
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
JniTestHelper.init(mHandler);
//将下面定义的Handler对象,初始化JniTestHelper中的Handler对象。
JniTestHelper.setPackageName(
this
.getPackageName());
}
public
Cocos2dxGLSurfaceView onCreateView(){
Cocos2dxGLSurfaceView glSurfaceView =
new
Cocos2dxGLSurfaceView(
this
);
glSurfaceView.setEGLConfigChooser(
5
,
6
,
5
,
0
,
16
,
8
);
return
glSurfaceView;
}
static
{
System.loadLibrary(
"cocos2dcpp"
);
}
private
Handler mHandler =
new
Handler()
{
public
void
handleMessage(Message msg) {
switch
(msg.what)
{
case
SHOW_DIALOG:
//设置提示框
DialogMessage dm = (DialogMessage)msg.obj;
new
AlertDialog.Builder(AppActivity.
this
)
.setTitle(dm.titile)
.setMessage(dm.message).setNegativeButton(
"cancle"
,
new
DialogInterface.OnClickListener() {
@Override
public
void
onClick(DialogInterface arg0,
int
arg1) {
// TODO Auto-generated method stub
arg0.dismiss();
}
})
.setPositiveButton(
"Ok"
,
new
DialogInterface.OnClickListener(){
public
void
onClick(DialogInterface arg0,
int
arg1) {
arg0.dismiss();
JniTestHelper.exitApp();
}
})
.create().show();
break
;
}
}
};
}
好了,代码和注释基本就结束了,还需要该的是Android.mk文件。代码如下:
之前介绍过万能mk文件生成方法,详见http://blog.csdn.net/yuxikuo_1/article/details/39552431。为了减少出问题的几率,建议改高AndroidManifest中的SDK版本,不改无所谓也。
1
2
3
4
LOCAL_SRC_FILES := hellocpp/main.cpp \
hellocpp/test.cpp \
//将新建的test.cpp类加入mk文件
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp
6、工程总目录
1 |
|
三、编译运行
如出现问题可参考 1)http://blog.csdn.net/yuxikuo_1/article/details/39654499 2)http://blog.csdn.net/yuxikuo_1/article/details/39552639 3)http://blog.csdn.net/yuxikuo_1/article/details/39671733
http://www.2cto.com/kf/201410/347637.html