寫在前面
本篇內容主要是關於用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的定義:
<!-- Tell Cocos2dxActivity the name of our .so -->
<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提供了兩個基本的類GLSurfaceView
和GLSurfaceView.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函數
可以看出,上述說的三個方法關鍵的地方就是分別調用了nativeInit
、nativeOnSurfaceChanged
、nativeRender
,這些方法都是在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