初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
/****************************************************************************
Copyright (c) 2010-2012 cocos2d-x.org
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/android/jni/JniHelper.h"
#include <android/log.h>
#include <string.h>
#include <pthread.h>
#include "base/ccUTF8.h"
#define LOG_TAG "JniHelper"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static pthread_key_t g_key;
jclass _getClassID(const char *className) {
if (nullptr == className) {
return nullptr;
}
JNIEnv* env = cocos2d::JniHelper::getEnv();
jstring _jstrClassName = env->NewStringUTF(className);
jclass _clazz = (jclass) env->CallObjectMethod(cocos2d::JniHelper::classloader,
cocos2d::JniHelper::loadclassMethod_methodID,
_jstrClassName);
if (nullptr == _clazz || env->ExceptionCheck()) {
LOGE("Classloader failed to find class of %s", className);
env->ExceptionClear();
_clazz = nullptr;
}
env->DeleteLocalRef(_jstrClassName);
return _clazz;
}
void _detachCurrentThread(void* a) {
cocos2d::JniHelper::getJavaVM()->DetachCurrentThread();
}
namespace cocos2d {
JavaVM* JniHelper::_psJavaVM = nullptr;
jmethodID JniHelper::loadclassMethod_methodID = nullptr;
jobject JniHelper::classloader = nullptr;
std::function<void()> JniHelper::classloaderCallback = nullptr;
jobject JniHelper::_activity = nullptr;
JavaVM* JniHelper::getJavaVM() {
pthread_t thisthread = pthread_self();
LOGD("JniHelper::getJavaVM(), pthread_self() = %ld", thisthread);
return _psJavaVM;
}
void JniHelper::setJavaVM(JavaVM *javaVM) {
pthread_t thisthread = pthread_self();
LOGD("JniHelper::setJavaVM(%p), pthread_self() = %ld", javaVM, thisthread);
_psJavaVM = javaVM;
pthread_key_create(&g_key, _detachCurrentThread);
}
JNIEnv* JniHelper::cacheEnv(JavaVM* jvm) {
JNIEnv* _env = nullptr;
// get jni environment
jint ret = jvm->GetEnv((void**)&_env, JNI_VERSION_1_4);
switch (ret) {
case JNI_OK :
// Success!
pthread_setspecific(g_key, _env);
return _env;
case JNI_EDETACHED :
// Thread not attached
if (jvm->AttachCurrentThread(&_env, nullptr) < 0)
{
LOGE("Failed to get the environment using AttachCurrentThread()");
return nullptr;
} else {
// Success : Attached and obtained JNIEnv!
pthread_setspecific(g_key, _env);
return _env;
}
case JNI_EVERSION :
// Cannot recover from this error
LOGE("JNI interface version 1.4 not supported");
default :
LOGE("Failed to get the environment using GetEnv()");
return nullptr;
}
}
JNIEnv* JniHelper::getEnv() {
JNIEnv *_env = (JNIEnv *)pthread_getspecific(g_key);
if (_env == nullptr)
_env = JniHelper::cacheEnv(_psJavaVM);
return _env;
}
jobject JniHelper::getActivity() {
return _activity;
}
bool JniHelper::setClassLoaderFrom(jobject activityinstance) {
JniMethodInfo _getclassloaderMethod;
if (!JniHelper::getMethodInfo_DefaultClassLoader(_getclassloaderMethod,
"android/content/Context",
"getClassLoader",
"()Ljava/lang/ClassLoader;")) {
return false;
}
jobject _c = cocos2d::JniHelper::getEnv()->CallObjectMethod(activityinstance,
_getclassloaderMethod.methodID);
if (nullptr == _c) {
return false;
}
JniMethodInfo _m;
if (!JniHelper::getMethodInfo_DefaultClassLoader(_m,
"java/lang/ClassLoader",
"loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;")) {
return false;
}
JniHelper::classloader = cocos2d::JniHelper::getEnv()->NewGlobalRef(_c);
JniHelper::loadclassMethod_methodID = _m.methodID;
JniHelper::_activity = cocos2d::JniHelper::getEnv()->NewGlobalRef(activityinstance);
if (JniHelper::classloaderCallback != nullptr){
JniHelper::classloaderCallback();
}
return true;
}
bool JniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode) {
if ((nullptr == className) ||
(nullptr == methodName) ||
(nullptr == paramCode)) {
return false;
}
JNIEnv *env = JniHelper::getEnv();
if (!env) {
LOGE("Failed to get JNIEnv");
return false;
}
jclass classID = _getClassID(className);
if (! classID) {
LOGE("Failed to find class %s", className);
env->ExceptionClear();
return false;
}
jmethodID methodID = env->GetStaticMethodID(classID, methodName, paramCode);
if (! methodID) {
LOGE("Failed to find static method id of %s", methodName);
env->ExceptionClear();
return false;
}
methodinfo.classID = classID;
methodinfo.env = env;
methodinfo.methodID = methodID;
return true;
}
bool JniHelper::getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode) {
if ((nullptr == className) ||
(nullptr == methodName) ||
(nullptr == paramCode)) {
return false;
}
JNIEnv *env = JniHelper::getEnv();
if (!env) {
return false;
}
jclass classID = env->FindClass(className);
if (! classID) {
LOGE("Failed to find class %s", className);
env->ExceptionClear();
return false;
}
jmethodID methodID = env->GetMethodID(classID, methodName, paramCode);
if (! methodID) {
LOGE("Failed to find method id of %s", methodName);
env->ExceptionClear();
return false;
}
methodinfo.classID = classID;
methodinfo.env = env;
methodinfo.methodID = methodID;
return true;
}
bool JniHelper::getMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode) {
if ((nullptr == className) ||
(nullptr == methodName) ||
(nullptr == paramCode)) {
return false;
}
JNIEnv *env = JniHelper::getEnv();
if (!env) {
return false;
}
jclass classID = _getClassID(className);
if (! classID) {
LOGE("Failed to find class %s", className);
env->ExceptionClear();
return false;
}
jmethodID methodID = env->GetMethodID(classID, methodName, paramCode);
if (! methodID) {
LOGE("Failed to find method id of %s", methodName);
env->ExceptionClear();
return false;
}
methodinfo.classID = classID;
methodinfo.env = env;
methodinfo.methodID = methodID;
return true;
}
std::string JniHelper::jstring2string(jstring jstr) {
if (jstr == nullptr) {
return "";
}
JNIEnv *env = JniHelper::getEnv();
if (!env) {
return "";
}
std::string strValue = cocos2d::StringUtils::getStringUTFCharsJNI(env, jstr);
return strValue;
}
jstring JniHelper::convert(JniHelper::LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const char* x) {
jstring ret = nullptr;
if (x)
ret = cocos2d::StringUtils::newStringUTFJNI(t.env, x);
localRefs[t.env].push_back(ret);
return ret;
}
jstring JniHelper::convert(JniHelper::LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const std::string& x) {
return convert(localRefs, t, x.c_str());
}
void JniHelper::deleteLocalRefs(JNIEnv* env, JniHelper::LocalRefMapType &localRefs) {
if (!env) {
return;
}
for (const auto& ref : localRefs[env]) {
env->DeleteLocalRef(ref);
}
localRefs[env].clear();
}
void JniHelper::reportError(const std::string& className, const std::string& methodName, const std::string& signature) {
LOGE("Failed to find static java method. Class name: %s, method name: %s, signature: %s ", className.c_str(), methodName.c_str(), signature.c_str());
}
} //namespace cocos2d

View File

@@ -0,0 +1,399 @@
/****************************************************************************
Copyright (c) 2010-2012 cocos2d-x.org
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __ANDROID_JNI_HELPER_H__
#define __ANDROID_JNI_HELPER_H__
#include <jni.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>
#include "base/ccMacros.h"
#include "math/Vec3.h"
//The macro must be used this way to find the native method. The principle is not well understood.
#define JNI_METHOD2(CLASS2,FUNC2) Java_##CLASS2##_##FUNC2
#define JNI_METHOD1(CLASS1,FUNC1) JNI_METHOD2(CLASS1,FUNC1)
NS_CC_BEGIN
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
class CC_DLL JniHelper
{
public:
typedef std::unordered_map<JNIEnv *, std::vector<jobject >> LocalRefMapType;
static void setJavaVM(JavaVM *javaVM);
static JavaVM* getJavaVM();
static JNIEnv* getEnv();
static jobject getActivity();
static bool setClassLoaderFrom(jobject activityInstance);
static bool getStaticMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode);
static std::string jstring2string(jstring str);
static jmethodID loadclassMethod_methodID;
static jobject classloader;
static std::function<void()> classloaderCallback;
template <typename... Ts>
static jobject newObject(const std::string& className, Ts... xs)
{
jobject ret = nullptr;
static const char* methodName = "<init>";
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName, signature.c_str())) {
LocalRefMapType localRefs;
ret = t.env->NewObject(t.classID, t.methodID, convert(t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static void callObjectVoidMethod(jobject object,
const std::string& className,
const std::string& methodName,
Ts... xs) {
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
t.env->CallVoidMethod(object, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
}
template <typename... Ts>
static float callObjectFloatMethod(jobject object,
const std::string& className,
const std::string& methodName,
Ts... xs) {
float ret = 0.0f;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")F";
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
ret = t.env->CallFloatMethod(object, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static jbyteArray callObjectByteArrayMethod(jobject object,
const std::string& className,
const std::string& methodName,
Ts... xs) {
jbyteArray ret = nullptr;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[B";
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
ret = (jbyteArray)t.env->CallObjectMethod(object, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static void callStaticVoidMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
t.env->CallStaticVoidMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
}
template <typename... Ts>
static bool callStaticBooleanMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
jboolean jret = JNI_FALSE;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")Z";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
jret = t.env->CallStaticBooleanMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return (jret == JNI_TRUE);
}
template <typename... Ts>
static int callStaticIntMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
jint ret = 0;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")I";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
ret = t.env->CallStaticIntMethod(t.classID, t.methodID, convert(t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static float callStaticFloatMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
jfloat ret = 0.0;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")F";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
ret = t.env->CallStaticFloatMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static float* callStaticFloatArrayMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
static float ret[32];
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[F";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
jfloatArray array = (jfloatArray) t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
jsize len = t.env->GetArrayLength(array);
if (len <= 32) {
jfloat* elems = t.env->GetFloatArrayElements(array, 0);
if (elems) {
memcpy(ret, elems, sizeof(float) * len);
t.env->ReleaseFloatArrayElements(array, elems, 0);
};
}
t.env->DeleteLocalRef(array);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
return &ret[0];
} else {
reportError(className, methodName, signature);
}
return nullptr;
}
template <typename... Ts>
static Vec3 callStaticVec3Method(const std::string& className,
const std::string& methodName,
Ts... xs) {
Vec3 ret;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[F";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
jfloatArray array = (jfloatArray) t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
jsize len = t.env->GetArrayLength(array);
if (len == 3) {
jfloat* elems = t.env->GetFloatArrayElements(array, 0);
ret.x = elems[0];
ret.y = elems[1];
ret.z = elems[2];
t.env->ReleaseFloatArrayElements(array, elems, 0);
}
t.env->DeleteLocalRef(array);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static double callStaticDoubleMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
jdouble ret = 0.0;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")D";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
ret = t.env->CallStaticDoubleMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
t.env->DeleteLocalRef(t.classID);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
template <typename... Ts>
static std::string callStaticStringMethod(const std::string& className,
const std::string& methodName,
Ts... xs) {
std::string ret;
cocos2d::JniMethodInfo t;
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")Ljava/lang/String;";
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
LocalRefMapType localRefs;
jstring jret = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
ret = cocos2d::JniHelper::jstring2string(jret);
t.env->DeleteLocalRef(t.classID);
t.env->DeleteLocalRef(jret);
deleteLocalRefs(t.env, localRefs);
} else {
reportError(className, methodName, signature);
}
return ret;
}
private:
static JNIEnv* cacheEnv(JavaVM* jvm);
static bool getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode);
static JavaVM* _psJavaVM;
static jobject _activity;
static jstring convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const char* x);
static jstring convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const std::string& x);
template <typename T>
static T convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo&, T x) {
return x;
}
static void deleteLocalRefs(JNIEnv* env, LocalRefMapType &localRefs);
static std::string getJNISignature() {
return "";
}
static std::string getJNISignature(bool) {
return "Z";
}
// jchar is unsigned 16 bits, we do char => jchar conversion on purpose
static std::string getJNISignature(char) {
return "C";
}
static std::string getJNISignature(jshort) {
return "S";
}
static std::string getJNISignature(jint) {
return "I";
}
static std::string getJNISignature(jlong) {
return "J";
}
static std::string getJNISignature(jfloat) {
return "F";
}
static std::string getJNISignature(jdouble) {
return "D";
}
static std::string getJNISignature(jbyteArray) {
return "[B";
}
static std::string getJNISignature(const char*) {
return "Ljava/lang/String;";
}
static std::string getJNISignature(const std::string&) {
return "Ljava/lang/String;";
}
template <typename T>
static std::string getJNISignature(T x) {
// This template should never be instantiated
static_assert(sizeof(x) == 0, "Unsupported argument type");
return "";
}
template <typename T, typename... Ts>
static std::string getJNISignature(T x, Ts... xs) {
return getJNISignature(x) + getJNISignature(xs...);
}
static void reportError(const std::string& className, const std::string& methodName, const std::string& signature);
};
NS_CC_END
#endif // __ANDROID_JNI_HELPER_H__

View File

@@ -0,0 +1,680 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "JniImp.h"
#include <unordered_map>
#include <android/log.h>
#include <android/asset_manager_jni.h>
#include <jni.h>
#include <mutex>
#include "JniHelper.h"
#include "platform/CCApplication.h"
#include "scripting/js-bindings/jswrapper/SeApi.h"
#include "scripting/js-bindings/event/EventDispatcher.h"
#include "platform/android/CCFileUtils-android.h"
#include "base/CCScheduler.h"
#include "base/CCAutoreleasePool.h"
#include "base/CCGLUtils.h"
#define JNI_IMP_LOG_TAG "JniImp"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,JNI_IMP_LOG_TAG,__VA_ARGS__)
#ifndef ORG_RENDER_CLASS_NAME
#define ORG_RENDER_CLASS_NAME org_cocos2dx_lib_Cocos2dxRenderer
#endif
#define JNI_RENDER(FUNC) JNI_METHOD1(ORG_RENDER_CLASS_NAME,FUNC)
#ifndef ORG_ACTIVITY_CLASS_NAME
#define ORG_ACTIVITY_CLASS_NAME org_cocos2dx_lib_Cocos2dxActivity
#endif
#define JNI_ACTIVITY(FUNC) JNI_METHOD1(ORG_ACTIVITY_CLASS_NAME,FUNC)
#ifndef ORG_ACCELEROMETER_CLASS_NAME
#define ORG_ACCELEROMETER_CLASS_NAME org_cocos2dx_lib_Cocos2dxAccelerometer
#endif
#define JNI_ACCELEROMETER(FUNC) JNI_METHOD1(ORG_ACCELEROMETER_CLASS_NAME,FUNC)
#ifndef ORG_HELPER_CLASS_NAME
#define ORG_HELPER_CLASS_NAME org_cocos2dx_lib_Cocos2dxHelper
#endif
#define JNI_HELPER(FUNC) JNI_METHOD1(ORG_HELPER_CLASS_NAME,FUNC)
#ifndef ORG_AUDIOFOCUS_CLASS_NAME
#define ORG_AUDIOFOCUS_CLASS_NAME org_cocos2dx_lib_Cocos2dxAudioFocusManager
#endif
#define JNI_AUDIO(FUNC) JNI_METHOD1(ORG_AUDIOFOCUS_CLASS_NAME,FUNC)
#ifndef JCLS_HELPER
#define JCLS_HELPER "org/cocos2dx/lib/Cocos2dxHelper"
#endif
#ifndef JCLS_RENDERER
#define JCLS_RENDERER "org/cocos2dx/lib/Cocos2dxRenderer"
#endif
#define KEYCODE_BACK 0x04
#define KEYCODE_MENU 0x52
#define KEYCODE_DPAD_UP 0x13
#define KEYCODE_DPAD_DOWN 0x14
#define KEYCODE_DPAD_LEFT 0x15
#define KEYCODE_DPAD_RIGHT 0x16
#define KEYCODE_ENTER 0x42
#define KEYCODE_DPAD_CENTER 0x17
using namespace cocos2d;
extern uint32_t __jsbInvocationCount;
namespace
{
bool __isOpenDebugView = false;
bool __isGLOptModeEnabled = true;
std::string g_apkPath;
EditTextCallback s_editTextCallback = nullptr;
void* s_ctx = nullptr;
int g_deviceSampleRate = 44100;
int g_deviceAudioBufferSizeInFrames = 192;
int g_width = 0;
int g_height = 0;
bool g_isStarted = false;
bool g_isGameFinished = false;
int g_SDKInt = 0;
cocos2d::Application* g_app = nullptr;
bool setCanvasCallback(se::Object* global)
{
se::AutoHandleScope scope;
se::ScriptEngine* se = se::ScriptEngine::getInstance();
char commandBuf[200] = {0};
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
sprintf(commandBuf, "window.innerWidth = %d; window.innerHeight = %d;",
g_width / devicePixelRatio,
g_height / devicePixelRatio);
se->evalString(commandBuf);
glViewport(0, 0, g_width / devicePixelRatio, g_height / devicePixelRatio);
glDepthMask(GL_TRUE);
return true;
}
}
void cocos_jni_env_init (JNIEnv* env);
Application* cocos_android_app_init(JNIEnv* env, int width, int height);
extern "C"
{
void getSDKInt(JNIEnv* env)
{
if (env && g_SDKInt == 0)
{
// VERSION is a nested class within android.os.Build (hence "$" rather than "/")
jclass versionClass = env->FindClass("android/os/Build$VERSION");
if (NULL == versionClass)
return;
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
if (NULL == sdkIntFieldID)
return;
g_SDKInt = env->GetStaticIntField(versionClass, sdkIntFieldID);
}
}
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JniHelper::setJavaVM(vm);
cocos_jni_env_init(JniHelper::getEnv());
getSDKInt(JniHelper::getEnv());
return JNI_VERSION_1_4;
}
/*****************************************************
* Cocos2dxActivity native functions implementation.
*****************************************************/
JNIEXPORT jintArray JNICALL JNI_ACTIVITY(getGLContextAttrs)(JNIEnv* env, jobject thiz)
{
//REFINE
int tmp[7] = {8, 8, 8,
8, 0, 0, 0};
jintArray glContextAttrsJava = env->NewIntArray(7);
env->SetIntArrayRegion(glContextAttrsJava, 0, 7, tmp);
return glContextAttrsJava;
}
/*****************************************************
* Cocos2dxRenderer native functions implementation.
*****************************************************/
JNIEXPORT void JNICALL JNI_RENDER(nativeInit)(JNIEnv* env, jobject thiz, jint w, jint h, jstring jDefaultResourcePath)
{
g_width = w;
g_height = h;
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();
g_app->start();
g_isStarted = true;
}
JNIEXPORT void JNICALL JNI_RENDER(nativeRender)(JNIEnv* env)
{
if (g_isGameFinished)
{
// with Application destructor called, native resource will be released
delete g_app;
g_app = nullptr;
JniHelper::callStaticVoidMethod(JCLS_HELPER, "endApplication");
return;
}
if (!g_isStarted)
{
auto scheduler = Application::getInstance()->getScheduler();
scheduler->removeAllFunctionsToBePerformedInCocosThread();
scheduler->unscheduleAll();
se::ScriptEngine::getInstance()->cleanup();
cocos2d::PoolManager::getInstance()->getCurrentPool()->clear();
//REFINE: Wait HttpClient, WebSocket, Audio thread to exit
ccInvalidateStateCache();
se::ScriptEngine* se = se::ScriptEngine::getInstance();
se->addRegisterCallback(setCanvasCallback);
EventDispatcher::init();
if(!g_app->applicationDidFinishLaunching())
{
g_isGameFinished = true;
return;
}
g_isStarted = true;
}
static std::chrono::steady_clock::time_point prevTime;
static std::chrono::steady_clock::time_point now;
static float dt = 0.f;
static float dtSum = 0.f;
static uint32_t jsbInvocationTotalCount = 0;
static uint32_t jsbInvocationTotalFrames = 0;
bool downsampleEnabled = g_app->isDownsampleEnabled();
if (downsampleEnabled)
g_app->getRenderTexture()->prepare();
g_app->getScheduler()->update(dt);
EventDispatcher::dispatchTickEvent(dt);
if (downsampleEnabled)
g_app->getRenderTexture()->draw();
PoolManager::getInstance()->getCurrentPool()->clear();
now = std::chrono::steady_clock::now();
dt = std::chrono::duration_cast<std::chrono::microseconds>(now - prevTime).count() / 1000000.f;
prevTime = std::chrono::steady_clock::now();
if (__isOpenDebugView)
{
dtSum += dt;
++jsbInvocationTotalFrames;
jsbInvocationTotalCount += __jsbInvocationCount;
if (dtSum > 1.0f)
{
dtSum = 0.0f;
setJSBInvocationCountJNI(jsbInvocationTotalCount / jsbInvocationTotalFrames);
jsbInvocationTotalCount = 0;
jsbInvocationTotalFrames = 0;
}
}
__jsbInvocationCount = 0;
}
JNIEXPORT void JNICALL JNI_RENDER(nativeOnPause)()
{
if (g_isGameFinished) {
return;
}
if (g_app)
g_app->onPause();
}
JNIEXPORT void JNICALL JNI_RENDER(nativeOnResume)()
{
if (g_isGameFinished) {
return;
}
if (g_app)
g_app->onResume();
}
JNIEXPORT void JNICALL JNI_RENDER(nativeInsertText)(JNIEnv* env, jobject thiz, jstring text)
{
//REFINE
}
JNIEXPORT void JNICALL JNI_RENDER(nativeDeleteBackward)(JNIEnv* env, jobject thiz)
{
//REFINE
}
JNIEXPORT jstring JNICALL JNI_RENDER(nativeGetContentText)()
{
//REFINE
}
JNIEXPORT void JNICALL JNI_RENDER(nativeOnSurfaceChanged)(JNIEnv* env, jobject thiz, jint w, jint h)
{
//REFINE
}
/***********************************************************
* Cocos2dxAccelerometer native functions implementation.
***********************************************************/
JNIEXPORT void JNICALL JNI_ACCELEROMETER(onSensorChanged)(JNIEnv* env, jobject thiz, jfloat x, jfloat y, jfloat z, jlong timeStamp)
{
//REFINE
}
/***********************************************************
* Touches native functions implementation.
***********************************************************/
static void dispatchTouchEventWithOnePoint(JNIEnv* env, cocos2d::TouchEvent::Type type, jint id, jfloat x, jfloat y)
{
if (g_isGameFinished) {
return;
}
cocos2d::TouchEvent touchEvent;
touchEvent.type = type;
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
cocos2d::TouchInfo touchInfo;
touchInfo.index = id;
touchInfo.x = x / devicePixelRatio;
touchInfo.y = y / devicePixelRatio;
touchEvent.touches.push_back(touchInfo);
cocos2d::EventDispatcher::dispatchTouchEvent(touchEvent);
}
static void dispatchTouchEventWithPoints(JNIEnv* env, cocos2d::TouchEvent::Type type, jintArray ids, jfloatArray xs, jfloatArray ys)
{
if (g_isGameFinished) {
return;
}
cocos2d::TouchEvent touchEvent;
touchEvent.type = type;
int size = env->GetArrayLength(ids);
jint id[size];
jfloat x[size];
jfloat y[size];
env->GetIntArrayRegion(ids, 0, size, id);
env->GetFloatArrayRegion(xs, 0, size, x);
env->GetFloatArrayRegion(ys, 0, size, y);
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
for(int i = 0; i < size; i++)
{
cocos2d::TouchInfo touchInfo;
touchInfo.index = id[i];
touchInfo.x = x[i] / devicePixelRatio;
touchInfo.y = y[i] / devicePixelRatio;
touchEvent.touches.push_back(touchInfo);
}
cocos2d::EventDispatcher::dispatchTouchEvent(touchEvent);
}
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesBegin)(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y)
{
if (g_isGameFinished) {
return;
}
dispatchTouchEventWithOnePoint(env, cocos2d::TouchEvent::Type::BEGAN, id, x, y);
}
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesEnd)(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y)
{
if (g_isGameFinished) {
return;
}
dispatchTouchEventWithOnePoint(env, cocos2d::TouchEvent::Type::ENDED, id, x, y);
}
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesMove)(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
{
if (g_isGameFinished) {
return;
}
dispatchTouchEventWithPoints(env, cocos2d::TouchEvent::Type::MOVED, ids, xs, ys);
}
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesCancel)(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
{
if (g_isGameFinished) {
return;
}
dispatchTouchEventWithPoints(env, cocos2d::TouchEvent::Type::CANCELLED, ids, xs, ys);
}
JNIEXPORT jboolean JNICALL JNI_RENDER(nativeKeyEvent)(JNIEnv * env, jobject thiz, jint keyCode, jboolean isPressed)
{
if (g_isGameFinished) {
return JNI_TRUE;
}
int keyInWeb = -1;
// key values in web, refer to http://docs.cocos.com/creator/api/en/enums/KEY.html
switch(keyCode)
{
case KEYCODE_BACK:
keyInWeb = 6;
break;
case KEYCODE_ENTER:
keyInWeb = 13;
break;
case KEYCODE_MENU:
keyInWeb = 18;
break;
case KEYCODE_DPAD_UP:
keyInWeb = 1003;
break;
case KEYCODE_DPAD_DOWN:
keyInWeb = 1004;
break;
case KEYCODE_DPAD_LEFT:
keyInWeb = 1000;
break;
case KEYCODE_DPAD_RIGHT:
keyInWeb = 1001;
break;
case KEYCODE_DPAD_CENTER:
keyInWeb = 1005;
break;
default:
keyInWeb = 0; // If the key can't be identified, this value is 0
}
KeyboardEvent event;
event.key = keyInWeb;
event.action = isPressed ? KeyboardEvent::Action::PRESS : KeyboardEvent::Action::RELEASE;
EventDispatcher::dispatchKeyboardEvent(event);
return JNI_TRUE;
}
/***********************************************************
* Cocos2dxHelper native functions implementation.
***********************************************************/
JNIEXPORT void JNICALL JNI_HELPER(nativeSetApkPath)(JNIEnv* env, jobject thiz, jstring apkPath)
{
g_apkPath = JniHelper::jstring2string(apkPath);
}
JNIEXPORT void JNICALL JNI_HELPER(nativeSetContext)(JNIEnv* env, jobject thiz, jobject context, jobject assetManager)
{
JniHelper::setClassLoaderFrom(context);
FileUtilsAndroid::setassetmanager(AAssetManager_fromJava(env, assetManager));
}
JNIEXPORT void JNICALL JNI_HELPER(nativeSetAudioDeviceInfo)(JNIEnv* env, jobject thiz, jboolean isSupportLowLatency, jint deviceSampleRate, jint deviceAudioBufferSizeInFrames)
{
g_deviceSampleRate = deviceSampleRate;
g_deviceAudioBufferSizeInFrames = deviceAudioBufferSizeInFrames;
LOGD("nativeSetAudioDeviceInfo: sampleRate: %d, bufferSizeInFrames: %d", g_deviceSampleRate, g_deviceAudioBufferSizeInFrames);
}
JNIEXPORT void JNICALL JNI_HELPER(nativeSetEditTextDialogResult)(JNIEnv* env, jobject obj, jbyteArray text)
{
jsize size = env->GetArrayLength(text);
if (size > 0)
{
jbyte * data = (jbyte*)env->GetByteArrayElements(text, 0);
char* buffer = (char*)malloc(size+1);
if (buffer != nullptr)
{
memcpy(buffer, data, size);
buffer[size] = '\0';
// pass data to edittext's delegate
if (s_editTextCallback)
s_editTextCallback(buffer, s_ctx);
free(buffer);
}
env->ReleaseByteArrayElements(text, data, 0);
}
else
{
if (s_editTextCallback)
s_editTextCallback("", s_ctx);
}
}
/***********************************************************
* Cocos2dxAudioFocusManager native functions implementation.
***********************************************************/
JNIEXPORT void JNICALL JNI_AUDIO(nativeOnAudioFocusChange)(JNIEnv* env, jobject thiz, jint focusChange)
{
// cocos_audioengine_focus_change(focusChange);
}
} // end of extern "C"
void restartJSVM()
{
g_isStarted = false;
}
/***********************************************************
* Functions invoke from cpp to Java.
***********************************************************/
std::string getApkPathJNI()
{
return g_apkPath;
}
std::string getPackageNameJNI()
{
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getPackageName");
}
int getObbAssetFileDescriptorJNI(const std::string& path, long* startOffset, long* size)
{
JniMethodInfo methodInfo;
int fd = 0;
if (JniHelper::getStaticMethodInfo(methodInfo, JCLS_HELPER, "getObbAssetFileDescriptor", "(Ljava/lang/String;)[J"))
{
jstring stringArg = methodInfo.env->NewStringUTF(path.c_str());
jlongArray newArray = (jlongArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, stringArg);
jsize theArrayLen = methodInfo.env->GetArrayLength(newArray);
if (3 == theArrayLen)
{
jboolean copy = JNI_FALSE;
jlong *array = methodInfo.env->GetLongArrayElements(newArray, &copy);
fd = static_cast<int>(array[0]);
*startOffset = array[1];
*size = array[2];
methodInfo.env->ReleaseLongArrayElements(newArray, array, 0);
}
methodInfo.env->DeleteLocalRef(methodInfo.classID);
methodInfo.env->DeleteLocalRef(stringArg);
}
return fd;
}
int getDeviceSampleRateJNI()
{
return g_deviceSampleRate;
}
int getDeviceAudioBufferSizeInFramesJNI()
{
return g_deviceAudioBufferSizeInFrames;
}
void convertEncodingJNI(const std::string& src, int byteSize, const std::string& fromCharset, std::string& dst, const std::string& newCharset)
{
JniMethodInfo methodInfo;
if (JniHelper::getStaticMethodInfo(methodInfo, JCLS_HELPER, "conversionEncoding", "([BLjava/lang/String;Ljava/lang/String;)[B"))
{
jbyteArray strArray = methodInfo.env->NewByteArray(byteSize);
methodInfo.env->SetByteArrayRegion(strArray, 0, byteSize, reinterpret_cast<const jbyte*>(src.c_str()));
jstring stringArg1 = methodInfo.env->NewStringUTF(fromCharset.c_str());
jstring stringArg2 = methodInfo.env->NewStringUTF(newCharset.c_str());
jbyteArray newArray = (jbyteArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, strArray, stringArg1, stringArg2);
jsize theArrayLen = methodInfo.env->GetArrayLength(newArray);
methodInfo.env->GetByteArrayRegion(newArray, 0, theArrayLen, (jbyte*)dst.c_str());
methodInfo.env->DeleteLocalRef(strArray);
methodInfo.env->DeleteLocalRef(stringArg1);
methodInfo.env->DeleteLocalRef(stringArg2);
methodInfo.env->DeleteLocalRef(newArray);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
}
std::string getCurrentLanguageJNI()
{
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getCurrentLanguage");
}
std::string getCurrentLanguageCodeJNI()
{
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getCurrentLanguageCode");
}
std::string getSystemVersionJNI()
{
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getSystemVersion");
}
bool openURLJNI(const std::string& url)
{
return JniHelper::callStaticBooleanMethod(JCLS_HELPER, "openURL", url);
}
void copyTextToClipboardJNI(const std::string& text)
{
JniHelper::callStaticVoidMethod(JCLS_HELPER, "copyTextToClipboard", text);
}
void setPreferredFramesPerSecondJNI(int fps)
{
JniHelper::callStaticVoidMethod(JCLS_RENDERER, "setPreferredFramesPerSecond", fps);
}
void setGameInfoDebugViewTextJNI(int index, const std::string& text)
{
if (!__isOpenDebugView)
return;
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setGameInfoDebugViewText", index, text);
}
void setJSBInvocationCountJNI(int count)
{
if (!__isOpenDebugView)
return;
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setJSBInvocationCount", count);
}
void openDebugViewJNI()
{
if (!__isOpenDebugView)
{
LOGD("openDebugViewJNI ...");
__isOpenDebugView = true;
JniHelper::callStaticVoidMethod(JCLS_HELPER, "openDebugView");
if (!__isGLOptModeEnabled)
{
JniHelper::callStaticVoidMethod(JCLS_HELPER, "disableBatchGLCommandsToNative");
}
}
}
void disableBatchGLCommandsToNativeJNI()
{
__isGLOptModeEnabled = false;
if (__isOpenDebugView)
{
JniHelper::callStaticVoidMethod(JCLS_HELPER, "disableBatchGLCommandsToNative");
}
}
void exitApplication()
{
g_isGameFinished = true;
}
bool getApplicationExited()
{
return g_isGameFinished;
}
int getAndroidSDKInt()
{
return g_SDKInt;
}

View File

@@ -0,0 +1,54 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <string>
typedef void (*EditTextCallback)(const std::string& text, void* ctx);
extern bool getApplicationExited();
extern void restartJSVM();
extern void exitApplication();
extern std::string getApkPathJNI();
extern std::string getPackageNameJNI();
extern int getObbAssetFileDescriptorJNI(const std::string& path, long* startOffset, long* size);
extern void convertEncodingJNI(const std::string& src, int byteSize, const std::string& fromCharset, std::string& dst, const std::string& newCharset);
extern int getDeviceSampleRateJNI();
extern int getDeviceAudioBufferSizeInFramesJNI();
extern std::string getCurrentLanguageJNI();
extern std::string getCurrentLanguageCodeJNI();
extern std::string getSystemVersionJNI();
extern bool openURLJNI(const std::string& url);
extern void copyTextToClipboardJNI(const std::string& text);
extern void setPreferredFramesPerSecondJNI(int fps);
extern void setGameInfoDebugViewTextJNI(int index, const std::string& text);
extern void setJSBInvocationCountJNI(int count);
extern void openDebugViewJNI();
extern void disableBatchGLCommandsToNativeJNI();
extern int getAndroidSDKInt();