Quitting your game without killing the Android process

I’m back with a small article on how to improve Android Cocos2D-X based games. To quit an Android game when pressing Back, the engine sample tells you to call

  Director::getInstance()->end();

Now this the job in most cases, but has one major drawback: it doesn’t follow Android guidelines for finishing an Activity. Instead, it kills the whole Linux process hosting the Android game. This has implications if your game includes Android services (eg. for push notifications), because it kills the service as well. Therefore, your push notifications will not work properly.

So I had to come up with a fix. I implemented this C++ function which calls a native Java method:

#include "platform/android/jni/JniHelper.h"
#include <jni.h>
...
void DeviceManager::quitGame()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    return;
#elif(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    JniMethodInfo minfo;
    bool result = JniHelper::getStaticMethodInfo(minfo, "com.monocube.framework.device.DeviceManager", "sendToBack", "()V");
    if (result)
    {
        minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
        minfo.env->DeleteLocalRef(minfo.classID);
    }
#elif(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#else
    CCDirector::getInstance()->end();
#endif
}

The code is part of my custom game framework, built on top of Cocos2D-X. The code skips iOS, Windows Phone, and Windows Store apps, as they don’t have a quit button. The interesting part is the Android one. It uses JniHelper from Cocos2D-X to call “sendToBack”, a Java method defined by me in the class “com.monocube.framework.device.DeviceManager”. This looks like this:

    public static void sendToBack() {
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mActivity.moveTaskToBack(true);
                    }
                });
            }
        });
    }

“mActivity” is the Cocos2D-X game activity, so you need a reference to it in your class. As the call from C++ is run on the OpenGL thread, you need to make sure the Android code is run on the UI Thread. Therefore the call to “moveTaskToBack” is run within a Runnable object on the UI thread. In effect, this will not quit your game, but rather send it to the back of the activity stack. This works well for Cocos2D-X game, which usually have just one Activity.

That’s it for now, I hope this helps.

Leave a Reply

Your email address will not be published. Required fields are marked *