CocosCreator Andorid工程的启动过程

写在前面

本篇内容主要是关于用cocoscreator构建的Android工程,在运行apk时候的启动流程。
CocosCreator版本:2.3.1

正文

1、主Activity入口在AndroidMainifest.xml中定义

<activity>
            android:name="org.cocos2dx.javascript.AppActivity"
            ...
activity>            

2、Cocos2dxActivity的onCreate()方法

AppActivity继承Cocos2dxActivity,在它的onCreate()方法并没有处理太多东西,而是调用了父类的onCreate()方法。代码如下:

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        Log.d(TAG, "Cocos2dxActivity onCreate: " + this + ", savedInstanceState: " + savedInstanceState);
        super.onCreate(savedInstanceState);

        // Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
        if (!isTaskRoot()) {
            // Android launched another instance of the root activity into an existing task
            //  so just quietly finish and go away, dropping the user back into the activity
            //  at the top of the stack (ie: the last state of this task)
            finish();
            Log.w(TAG, "[Workaround] Ignore the activity started from icon!");
            return;
        }

        Utils.setActivity(this);

        Utils.hideVirtualButton();

        Cocos2dxHelper.registerBatteryLevelReceiver(this);

        // 把工程中libs下面的so文件load进来,定义在AndroidManifest, meta-data标签下,android.app.lib_name. 最终在包的data/data/com.XXX.XXX/lib下面
        onLoadNativeLibraries();

        sContext = this;
        this.mHandler = new Cocos2dxHandler(this);  // 处理安卓的弹窗等
        
        Cocos2dxHelper.init(this);
        CanvasRenderingContext2DImpl.init(this);
        
        this.mGLContextAttrs = getGLContextAttrs(); // 获取OpenGLES相关属性
        this.init(); // 初始化

        if (mVideoHelper == null) {
            mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);
        }

        if(mWebViewHelper == null){
            mWebViewHelper = new Cocos2dxWebViewHelper(mFrameLayout);
        }

        Window window = this.getWindow();
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
    }
    protected void onLoadNativeLibraries() {
        try {
            ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;
            // 获取在AndroidManifest.xml中定义.so文件名,并调用System.loadLibrary加载
            String libName = bundle.getString("android.app.lib_name");
            System.loadLibrary(libName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在AndroidManifest.xml的定义:

        
        <meta-data android:name="android.app.lib_name"
                   android:value="cocos2djs" />

3、Cocos2dxActivity的init()方法

    public void init() {
        ViewGroup.LayoutParams frameLayoutParams =
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                           ViewGroup.LayoutParams.MATCH_PARENT);
        mFrameLayout = new FrameLayout(this);
        mFrameLayout.setLayoutParams(frameLayoutParams);

        // 添加一个surfaceView,surfaceView是什么,下面讲
        Cocos2dxRenderer renderer = this.addSurfaceView();
        this.addDebugInfo(renderer);

        // Should create EditBox after adding SurfaceView, or EditBox will be hidden by SurfaceView.
        mEditBox = new Cocos2dxEditBox(this, mFrameLayout);

        // Set frame layout as the content view
        setContentView(mFrameLayout);
    }

addSurfaceView():

    private Cocos2dxRenderer addSurfaceView() {
        // 创建一个surfaceView
        this.mGLSurfaceView = this.onCreateView();
        this.mGLSurfaceView.setPreserveEGLContextOnPause(true);
        // Should set to transparent, or it will hide EditText
        // https://stackoverflow.com/questions/2978290/androids-edittext-is-hidden-when-the-virtual-keyboard-is-shown-and-a-surfacevie
        mGLSurfaceView.setBackgroundColor(Color.TRANSPARENT);
        // Switch to supported OpenGL (ARGB888) mode on emulator
        if (isAndroidEmulator())
            this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);

        // 注册自主实现的渲染器,渲染器又用来干嘛的,下面讲
        Cocos2dxRenderer renderer = new Cocos2dxRenderer();
        this.mGLSurfaceView.setCocos2dxRenderer(renderer);

        // 将新建的surfaceView添加到mFrameLayout中
        mFrameLayout.addView(this.mGLSurfaceView);

        return renderer;
    }
    
    public Cocos2dxGLSurfaceView onCreateView() {
    	// Cocos2dxGLSurfaceView 继承于 android.opengl.GLSurfaceView
        Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
        //this line is need on some device if we specify an alpha bits
        if(this.mGLContextAttrs[3] > 0) glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

        Cocos2dxEGLConfigChooser chooser = new Cocos2dxEGLConfigChooser(this.mGLContextAttrs);
        glSurfaceView.setEGLConfigChooser(chooser);

        return glSurfaceView;
    }

4、GLSurfaceView和GLSurfaceView.Render

Android提供了两个基本的类GLSurfaceViewGLSurfaceView.Render来让我们使用OpenGL ES API来创建和操纵图形。

GLSurfaceView

它是一个视图类,你可以调用OpenGL API在上面绘制图形和操纵物体,功能和SurfaceView相似。其中Cocos2dxGLSurfaceView 就是继承这个类,并且扩展这个类重写onTouchEvent、onKeyDown、onKeyUp等函数。

GLSurfaceView.Render

这个接口定义了在一个OpenGL的GLSurfaceView中绘制图形所需要的的方法,我们必须在一个单独的类中为这些接口提供实现,并使用GLSurfaceView.setRenderer()方法将它依附到GLSurfaceView实例对象上。Cocos2dxRenderer就是继承此类。
我们需要实现GLSurfaceView.Render的以下方法:

  • onSurfaceCreated():系统在创建GLSurfaceView时调用它一次。我们可以使用它来设置OpenGL的环境变量,或是初始化OpenGL的图形物体。
  • onSurfaceChanged():系统在GLSurfaceView的几何属性发生改变时调用该方法,包括大小或是设备屏幕的方向发生变化。例如,系统在屏幕从直立变为水平使调用它。这个方法主要用来对GLSurfaceView容器的变化进行响应。
  • onDrawFrame():系统在每次重绘GLSurfaceView时调用这个方法。这个方法主要完成绘制图形的操作。

接下来继续看Cocos2dxRenderer类

    @Override
    public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
        mNativeInitCompleted = false;
        // 这里调用了一个定义为native的函数,它是通过jni来访问c++实现的方法,具体下面讲
        Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight, mDefaultResourcePath);
        mOldNanoTime = System.nanoTime();
        this.mLastTickInNanoSeconds = System.nanoTime();
        mNativeInitCompleted = true;
        if (mGameEngineInitializedListener != null) {
            Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mGameEngineInitializedListener.onGameEngineInitialized();
                }
            });
        }
    }
    @Override
    public void onSurfaceChanged(final GL10 GL10, final int width, final int height) {
        // 同样的调用了c++的方法
        Cocos2dxRenderer.nativeOnSurfaceChanged(width, height);
    }
    @Override
    public void onDrawFrame(final GL10 gl) {
        if (mNeedToPause)
            return;

        if (mNeedShowFPS) {
            /////////////////////////////////////////////////////////////////////
            //IDEA: show FPS in Android Text control rather than outputing log.
            ++mFrameCount;
            long nowFpsTime = System.nanoTime();
            long fpsTimeInterval = nowFpsTime - mOldNanoTime;
            if (fpsTimeInterval > 1000000000L) {
                double frameRate = 1000000000.0 * mFrameCount / fpsTimeInterval;
                Cocos2dxHelper.OnGameInfoUpdatedListener listener = Cocos2dxHelper.getOnGameInfoUpdatedListener();
                if (listener != null) {
                    listener.onFPSUpdated((float) frameRate);
                }
                mFrameCount = 0;
                mOldNanoTime = System.nanoTime();
            }
            /////////////////////////////////////////////////////////////////////
        }
        /*
         * No need to use algorithm in default(60 FPS) situation,
         * since onDrawFrame() was called by system 60 times per second by default.
         */
        if (sAnimationInterval <= INTERVAL_60_FPS) {
            // 同样的调用了c++的方法
            Cocos2dxRenderer.nativeRender();
        } else {
            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();
        }
    }

5、c++中实现的nativeInit函数

可以看出,上述说的三个方法关键的地方就是分别调用了nativeInitnativeOnSurfaceChangednativeRender,这些方法都是在C++定义和实现的,这些方法的实现放在frameworks/cocos2d-x/cocos/platform/android/jni/JniImp.cpp中。

    JNIEXPORT void JNICALL JNI_RENDER(nativeInit)(JNIEnv*  env, jobject thiz, jint w, jint h, jstring jDefaultResourcePath)
    {
        g_width = w;
        g_height = h;
        
        // 这个方法new了一个AppDelegate
        // auto app = new AppDelegate(width, height);
        g_app = cocos_android_app_init(env, w, h);

        g_isGameFinished = false;
        ccInvalidateStateCache();
        std::string defaultResourcePath = JniHelper::jstring2string(jDefaultResourcePath);
        LOGD("nativeInit: %d, %d, %s", w, h, defaultResourcePath.c_str());
        

        if (!defaultResourcePath.empty())
            FileUtils::getInstance()->setDefaultResourceRootPath(defaultResourcePath);

        se::ScriptEngine* se = se::ScriptEngine::getInstance();
        se->addRegisterCallback(setCanvasCallback);

        EventDispatcher::init();

		// 程序开始运行,android的Application实现放在CCApplication-android.cpp中,start的代码如下:
        g_app->start();
        g_isStarted = true;
    }
void Application::start()
{
	// applicationDidFinishLaunching具体的实现在frameworks/runtime-src/Classes/AppDelegate.cpp中
    if(!applicationDidFinishLaunching())
        return;
}

bool AppDelegate::applicationDidFinishLaunching()
{
    se::ScriptEngine* se = se::ScriptEngine::getInstance();

    jsb_set_xxtea_key("65dd8463-fe52-43");
    jsb_init_file_operation_delegate();

#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    // Enable debugger here
    jsb_enable_debugger("0.0.0.0", 6086, false);
#endif

    se->setExceptionCallback([](const char* location, const char* message, const char* stack){
        // Send exception information to server like Tencent Bugly.

    });

    jsb_register_all_modules();

    se->start();

    se::AutoHandleScope hs;
    // 通过jsb调用js脚本,main.js是入口脚本
    jsb_run_script("jsb-adapter/jsb-builtin.js");
    jsb_run_script("main.js");

    se->addAfterCleanupHook([](){
        JSBClassType::destroy();
    });

    return true;
}

以上就是CocosCreator2.3.1版本构建的Android工程启动的流程,如果有哪里不对的欢迎指出!

参考链接:
https://www.cnblogs.com/Monte/p/6735061.html
https://www.jb51.net/article/96074.htm

你可能感兴趣的:(CocosCreator)