Skip to content

cocos2d x 3.3 017 为android平台提供的封装

cheyiliu edited this page Feb 4, 2015 · 5 revisions

proj.android分析

AndroidManifest.xml

//1. use opengl es 2.0
<uses-feature android:glEsVersion="0x00020000" />

//2. 问题1,在哪里用到的这个so?
        <!-- Tell Cocos2dxActivity the name of our .so -->
        <meta-data android:name="android.app.lib_name"
                   android:value="cpp_empty_test" />

//3. 支持的屏幕尺寸
 <supports-screens android:anyDensity="true"
                      android:smallScreens="true"
                      android:normalScreens="true"
                      android:largeScreens="true"
                      android:xlargeScreens="true"/>

assets目录

  • 从Resources拷贝的资源

jni目录

  • 除了make file外, 有个main.cpp, 内容如下
//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 代码如下
//看样子,料全在基类了
public class AppActivity extends Cocos2dxActivity {
}

小结下proj.android

  • 留了两个问题待解答,别的没啥

cocos针对android平台的封装

cocos/platform/android/目录下都有什么

  • ControllerManualAdapter //粗略过了下代码,和游戏手柄相关,略
  • java代码
//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
//application 在android平台相关的实现,跨平台实现细节,针对平台的具体实现
//更多信息请参考 https://github.com/cheyiliu/All-in-One/wiki/cocos2d-x-3.3-015-%E7%A8%8B%E5%BA%8F%E5%85%A5%E5%8F%A3main
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. 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
//这个类的代码就不贴了, 不过看了之后应该一些疑惑就得到了解答
//加速器事件,touch事件,key事件的分发都从这里继续派发
//输入法的弹出或者关闭处理也在这里,这里解答了问题3,用那个编辑框来做输入法弹出相关的逻辑
//因为InputMethodManager的showSoftInput,hideSoftInputFromWindow需要相应的参数
//同时,注意这点在onResume时设置的renderMode, setRenderMode(RENDERMODE_CONTINUOUSLY);


C. Cocos2dxRenderer.java
//这个类关注几个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
//在上面的分析中这个文件已经都涉及到了

小结

  • 在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这里应该还有不少故事。

扩展阅读

Clone this wiki locally