proj.android分析
AndroidManifest.xml
1. use opengl es 2.0
1
|
<uses-feature android:glEsVersion=
"0x00020000"
/>
|
2. 问题1,在哪里用到的这个so?
1
2
3
|
<!-- Tell Cocos2dxActivity the name of our .so -->
<meta-data android:name=
"android.app.lib_name"
android:value=
"cpp_empty_test"
/>
|
3. 支持的屏幕尺寸
1
2
3
4
5
|
<supports-screens android:anyDensity=
"true"
android:smallScreens=
"true"
android:normalScreens=
"true"
android:largeScreens=
"true"
android:xlargeScreens=
"true"
/>
|
assets目录
从Resources拷贝的资源
jni目录
除了make file外, 有个main.cpp, 内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//log相关
#define LOG_TAG "main"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
using
namespace
cocos2d;
//看起来怪怪的,new了一个AppDelegate之后,就不管了
//对比linux平台的,至少还调用了run方法
//问题2,谁调用的这个方法?
void
cocos_android_app_init (JNIEnv* env, jobject thiz) {
LOGD(
"cocos_android_app_init"
);
AppDelegate *pAppDelegate =
new
AppDelegate();
}
|
libs目录
由于我编译了,这个目录下有对应ABI的so。
src目录
AppActivity 代码如下
1
2
3
|
//看样子,料全在基类了
public
class
AppActivity extends Cocos2dxActivity {
}
|
小结下proj.android
留了两个问题待解答,详见下文。
Cocos2d-x针对Android平台的封装
cocos/platform/android/目录下都有什么
-
ControllerManualAdapter //粗略过了下代码,和游戏手柄相关,略
-
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
//android加速度传感器事件对接。注册监听器后,android产生相应事件并
//回调到Cocos2dxAccelerometer的onSensorChanged再经过
//Cocos2dxGLSurfaceView.queueAccelerometer(x,y,z,sensorEvent.timestamp);
//之后调用到Cocos2dxAccelerometer的本地方法onSensorChanged
//该方法所在位置Java_org_cocos2dx_lib_Cocos2dxAccelerometer.cpp,
//该方法在native层dispatchEvent一个传感器事件
Cocos2dxAccelerometer.java
//java层的图片工具类,简单跟了下代码,调用方向是从native方法调用到java层
Cocos2dxBitmap.java
//自定义了一个编辑对话框,对输入类型,键盘显示隐藏等做了些包装
Cocos2dxEditBoxDialog.java
//自定义编辑框,特殊处理了back按键
Cocos2dxEditText.java
//自定义handler,主要和弹出对话框相关
Cocos2dxHandler.java
//工具类,UserDefault存储相关的jni调用,获取包名,终止进程等
//主要调用方向是native到java
Cocos2dxHelper.java
//数据库存储,主要供native端调用到java
Cocos2dxLocalStorage.java
//lua相关
Cocos2dxLuaJavaBridge.java
//java层的音乐播放相关,包装的MediaPlayer,用来播放长的音乐等
//主要由Cocos2dxHandler.java调用过来
//看样子音乐播放这块多半就是用的java层的播放器了
Cocos2dxMusic.java
//java层的音乐播放相关,包装的用soundpool,
//用来播一些短的反应速度要求高的音效
Cocos2dxSound.java
//输入事件监听相关,配合Cocos2dxGLSurfaceView的工作
Cocos2dxTextInputWraper.java
//Typeface cache相关
Cocos2dxTypefaces.java
//android视频播放器,MediaPlayer+SurfaceView
//对应的helper用来将videoview从父控件动态添加删除,简化调用等
Cocos2dxVideoView.java
Cocos2dxVideoHelper.java
//自定义webview,类似上面的视频播放器的封装
Cocos2dxWebView.java
Cocos2dxWebViewHelper.java
//游戏手柄相关
GameControllerAdapter.java
GameControllerDelegate.java
GameControllerUtils.java
//放后面一起看TODO
Cocos2dxActivity.java
Cocos2dxRenderer.java
Cocos2dxGLSurfaceView.java
|
-
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
35
36
37
|
//application 在android平台相关的实现,跨平台实现细节,针对平台的具体实现
CCApplication-android.cpp
CCApplication-android.h
//native层的工具类,通过jni调用到java层弹框等
CCCommon-android.cpp
//native层的工具类,获取dpi,设置加速监听器,图片处理等
CCDevice-android.cpp
//fileUtils的android平台相关的实现,类似application了
CCFileUtils-android.cpp
CCFileUtils-android.h
//一堆和opengl相关的宏等
CCGL-android.h
//glview android平台的相关实现,类似application了
CCGLViewImpl-android.cpp
CCGLViewImpl-android.h
//一些宏定义
CCPlatformDefine-android.h
CCStdC-android.h
//放后面一起看TODO
javaactivity-android.cpp
//各种jni相关的helper类或者方法
//提一提touchesJni.cpp,他是用来对接android touch事件和key事件的
//和上面的加速器事件一样的逻辑, 稍后看具体的事件源头
DPIJni.cpp
DPIJni.h
IMEJni.cpp
IMEJni.h
Java_org_cocos2dx_lib_Cocos2dxAccelerometer.cpp
Java_org_cocos2dx_lib_Cocos2dxBitmap.cpp
Java_org_cocos2dx_lib_Cocos2dxBitmap.h
Java_org_cocos2dx_lib_Cocos2dxHelper.cpp
Java_org_cocos2dx_lib_Cocos2dxHelper.h
Java_org_cocos2dx_lib_Cocos2dxRenderer.cpp
JniHelper.cpp
JniHelper.h
TouchesJni.cpp
|
上面一些非重点的代码java的C++的,我们都过了一遍,涉及的内容都和jni相关包括事件源头的对接,各种跨平台实现细节和输入弹框等。重点代码则是上面的几个标记为TODO的相关类, 接下来重点分析:
A. Cocos2dxActivity.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
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
|
1. oncreate
@Override
protected
void
onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//这里问题1的得到解答
//在manifest中配置的元数据信息,so库的名称
//该库在这里得到了加载
onLoadNativeLibraries();
sContext =
this
;
this
.mHandler =
new
Cocos2dxHandler(
this
);
//helper和这个activity绑定了
Cocos2dxHelper.init(
this
);
//这里问题2得到解答
//这个native方法的调用过程中
//调用了 cocos_android_app_init(env, thiz);初始化了一个applicaton
this
.mGLContextAttrs = getGLContextAttrs();
//初始化,下面细看
this
.init();
//接下来的两个helper用来动态往mFrameLayout中添加或删除相应的view
if
(mVideoHelper == null) {
mVideoHelper =
new
Cocos2dxVideoHelper(
this
, mFrameLayout);
}
if
(mWebViewHelper == null){
mWebViewHelper =
new
Cocos2dxWebViewHelper(mFrameLayout);
}
}
2. init
public
void
init() {
//创建父容器FrameLayout
// FrameLayout
ViewGroup.LayoutParams framelayout_params =
new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mFrameLayout =
new
FrameLayout(
this
);
mFrameLayout.setLayoutParams(framelayout_params);
//添加了一个编辑框,但是是干嘛用的?问题3
// Cocos2dxEditText layout
ViewGroup.LayoutParams edittext_layout_params =
new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
Cocos2dxEditText edittext =
new
Cocos2dxEditText(
this
);
edittext.setLayoutParams(edittext_layout_params);
// ...add to FrameLayout
mFrameLayout.addView(edittext);
//添加一个glSurfaceView到容器
// Cocos2dxGLSurfaceView
this
.mGLSurfaceView =
this
.onCreateView();
// ...add to FrameLayout
mFrameLayout.addView(
this
.mGLSurfaceView);
// Switch to supported OpenGL (ARGB888) mode on emulator
if
(isAndroidEmulator())
this
.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
//设置glSurfaceView的render
this
.mGLSurfaceView.setCocos2dxRenderer(
new
Cocos2dxRenderer());
this
.mGLSurfaceView.setCocos2dxEditText(edittext);
//通过activity展现出来
// Set framelayout as the content view
setContentView(mFrameLayout);
}
|
B. Cocos2dxGLSurfaceView.java
1
2
3
4
5
|
//这个类的代码就不贴了, 不过看了之后应该一些疑惑就得到了解答
//加速器事件,touch事件,key事件的分发都从这里继续派发
//输入法的弹出或者关闭处理也在这里,这里解答了问题3,用那个编辑框来做输入法弹出相关的逻辑
//因为InputMethodManager的showSoftInput,hideSoftInputFromWindow需要相应的参数
//同时,注意这点在onResume时设置的renderMode, setRenderMode(RENDERMODE_CONTINUOUSLY);
|
C. Cocos2dxRenderer.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
//这个类关注几个callback就好
1. onSurfaceCreated
这里调用了一个本地方法nativeInit, 负责给导演设置了glview并调用了application的run方法
联想到linux的实现,看样子android的大循环也开启了, 但令人感到奇怪的是,android的application
的run方法只调用了applicationDidFinishLaunching而没哟类似linux的大循环。。。问题4
吼吼,继续走起
2. onSurfaceChanged
//屏幕方向变化等导致的回调
3. onDrawFrame
@Override
public
void
onDrawFrame(final GL10 gl) {
/*
* No need to use algorithm in default(60 FPS) situation,
* since onDrawFrame() was called by system 60 times per second by default.
*/
//android本身是一秒种onDrawFrame才被调用60次,
//也就是fps大于等于60次的都按fps=60来算了,高了也做不到,受限于onDrawFrame这个方法了
if
(sAnimationInterval <= 1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND) {
Cocos2dxRenderer.nativeRender();
}
else
{
//fps小于60的情况
final
long
now = System.nanoTime();
final
long
interval = now -
this
.mLastTickInNanoSeconds;
if
(interval < Cocos2dxRenderer.sAnimationInterval) {
try
{
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
}
catch
(final Exception e) {
}
}
/*
* Render time MUST be counted in, or the FPS will slower than appointed.
*/
this
.mLastTickInNanoSeconds = System.nanoTime();
Cocos2dxRenderer.nativeRender();
}
}
4. Cocos2dxRenderer.nativeRender
JNIEXPORT
void
JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) {
cocos2d::Director::getInstance()->mainLoop();
}
//豁然开朗
//onDrawFrame相当于一个循环了,mainLoop在这个循环中被调用
//逻辑本质上和linux的分析是一样的
//问题4得到解答
|
D. javaactivity-android.cpp
1
|
//在上面的分析中这个文件已经都涉及到了
|
小结
-
在proj.androd工程里面,几个注意的细节:manifest里面定义了so库的名称并在cocos提供的Cocos2dxActivity onCreate里得到加载;jni里面的main.cpp里面有个奇怪的方法并在那里new了一个application对象,而这个方法同样是被Cocos2dxActivity onCreate方法间接调用到的。
-
在目录cocos/platform/android/下,有用信息很丰富,包含了:
-
很多跨平台实现细节里面的关于android平台的特地实现,如application, fileUtil, glView等
-
对接android平台的事件源,在java层设置事件监听,监听器被回调,jni调用到native层,native层通过事件分发器发送事件。这个过程基本都和glSurfaceView关联了。这里的事件包括加速器事件,touch事件,key事件。
-
对比linux平台的那个大循环,android的大循环本质思路还是一样的。只是那个大循环被Cocos2dxRenderer.java onDrawFrame代替。关于glSurfaceView GLSurfaceView.Renderer的更多信息请参考扩展阅读里面的链接。
-
提供了android平台上关于音频播放相关的两个封装。而且是供native方法调用的。具体用法暂没细看。
-
提供了android平台上播放视频和打开网页相关的分装,通过动态往Cocos2dxActivity的contentView里面添加删除videoView或者webView来实现。具体用法暂没细看。
-
提供了本地数据库存储的包装实现。
-
提供了很多helper类或者功能,弹出对话框,弹出输入法框,获取应用包名等。
-
提一提android程序是怎么退出的:menuCloseCallback --> Director::getInstance()->end() --> (android平台的实现)GLViewImpl::end() --> (Java_org_cocos2dx_lib_Cocos2dxHelper.cpp)terminateProcessJNI --> (Cocos2dxHelper.java) terminateProcess --> android.os.Process.killProcess(android.os.Process.myPid());
-
那android程序怎么起来的呢。。。Zygote and fork, that's a long story
-
看这部分代码有个细节要注意,这里涉及到jni,但jni也没那么可怕,记住调用方向就好,java调用c++的方法时该方法要用native修饰,c++调用java一般是通过jnihelper来调用java层的xxHelper的static方法。
-
关于在Cocos2dxActivity contenView里面有一个隐藏的Cocos2dxEditText这里应该还有不少故事。
扩展阅读
http://developer.android.com/reference/android/opengl/GLSurfaceView.html
http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html
OpenGL例子:https://github.com/cheyiliu/test4opengles
http://developer.android.com/training/articles/perf-jni.html