cocos2d-x 2.x版本接入bugly的总结
最开始项目使用的是自己DIY的很简陋的上报系统,后来改成google breakpad来上报,发现其实都做的不太理想,游戏引擎因为版本历史问题存在一些崩溃问题。后来3.x接入了bugly,我这边抽了几天时间也准备接入,在接入bugly之前我是想用BugTags的,说实话我特别喜欢也为这款产品点赞(它的技术人员、客服人员响应速度和服务都是很赞的,最开始公司总结5个人,我也担任过客服的角色去跟用户沟通知道这其中的不易),但是毕竟它目前为止对NDK以及Lua方面支持的比较弱,而且截图时还存在黑屏的现象,对非原生的应用不太友好,所以后来还是放弃了,转入对C++崩溃捕获更为专业的Bugly。
官方采用的是3.x版本的cocos接入和测试的,所以2.x版本上有一些问题,我们对引擎底层做了一些修改,不能直接升级引擎的版本。
主要遇到的几个坑点:
1、CrashReport.mm报错 enum error is not a class or namespace,官方应该是在支持C++11的编译器上写的代码;
2、头文件引入的问题,No such file or directory compilation terminated,主要是.mk编写的问题;
3、eclipse属性C++ builder中勾选clean后,每次build都会把libs/armeabi目录下的文件删的精光,每次生成的时候libBuly.so都被干掉了,游戏一遇到上报就直接闪退;
第一个问题处理的方法,就是不要加类名。可参考C++11FAQ http://www.stroustrup.com/C++11FAQ.html
第二个问题的解决方法就是修改bugly下的Android.mk文件,增加一行代码
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
第三个问题就比较恶心一些了, 最后我是直接在项目jni/Android.mk中再引入一个Android.mk,通过该文件去导入libBugly.so文件
2.x的cocos需要配置NDK的环境变量,项目的jni/Android.mk中添加
和
Android.mk的文件内容
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := Bugly_sharedLOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libBugly.soinclude $(PREBUILT_SHARED_LIBRARY)
armeabi中就放入从官方下载的libBugly.so文件,注意要是armeabi目录下的,别搞错了哦
说几个我主要修改的地方吧,崩溃接入其实分了三个部分:
1、Java代码异常,你在Activity的onCreate()方法中调用测试代码就可以测试了:CrashReport.testJavaCrash();
2、Lua Error,需要修改CCLuaEngine.cpp文件,执行lua出错时调用出错函数__G__TRACKBACK__;
3、C/C++异常;
第一个没什么好说的,自己看官方文档吧,很简单
第二个贴一下我修改的代码,仅供参考
主要就是利用lua_pcall最后一个参数为errFn进行的。当lua执行出错时,会调用相应的lua函数__G__TRACKBACK__,由该函数中调用bugly自己暴露出来的接口上传
第三项,因为bugly自己新起了一个线程去调用进行上报,在Android下如果游戏自己的CPP去调用BuglyReport.h中的方法就会直接崩溃,所以对官方提供的CrashReport.mm进行了修改(主要二处改动,一处是初始化仅做暴露自己接口的事情,二是对C++调用Java方法的判断)
#include <string.h> #ifdef CC_TARGET_PLATFORM#include "cocos2d.h"#endif #include "CrashReport.h" #if (BUGLY_REPORT_LUA)#include "CCLuaEngine.h"//#include "CCScriptSupport.h"#endif #define CATEGORY_LUA_EXCEPTION 6#define CATEGORY_JS_EXCEPTION 7 #define LOG_TAG "CrashReport" #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32#define LOGI CCLOG#define LOGD CCLOG#define LOGE CCLOG#endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include <android/log.h> #include <jni.h> #include "platform/android/jni/JniHelper.h" #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) #define CRASHREPORT_CLASS "com/tencent/bugly/cocos/Cocos2dxAgent" #define METHOD_INIT "initCrashReport" #define METHOD_INIT_PARAMETER "(Landroid/content/Context;Ljava/lang/String;Z)V" #define METHOD_POST_EXCEPTION "postException" #define METHOD_POST_EXCEPTION_PARAMETER "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V" #define METHOD_SET_USER_ID "setUserId" #define METHOD_SET_USER_ID_PARAMETER "(Ljava/lang/String;)V" #define METHOD_SET_LOG "setLog" #define METHOD_SET_LOG_PARAMETER "(ILjava/lang/String;Ljava/lang/String;)V" #define METHOD_SET_USER_SCENE_TAG "setUserSceneTag" #define METHOD_SET_USER_SCENE_TAG_PARAMETER "(Landroid/content/Context;I)V" #define METHOD_PUT_USER_DATA "putUserData" #define METHOD_PUT_USER_DATA_PARAMETER "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V" #define METHOD_REMOVE_USER_DATA "removeUserData" #define METHOD_REMOVE_USER_DATA_PARAMETER "(Landroid/content/Context;Ljava/lang/String;)V" #define METHOD_SET_CHANNEL "setSDKPackagePrefixName" #define METHOD_SET_CHANNEL_PARAMETER "(Ljava/lang/String;)V" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #import <Foundation/Foundation.h> #define NSStringMake(const_char_pointer) (const_char_pointer == NULL ? nil : @(const_char_pointer)) #define NSStringNonnullMake(const_char_pointer) (const_char_pointer == NULL ? @"" : @(const_char_pointer)) #define LOGI(fmt, args...) printf("[Info] %s: ", LOG_TAG);\ printf(fmt, ##args);\ printf("\n"); #define LOGD(fmt, args...) printf("[Debug] %s: ", LOG_TAG);\ printf(fmt, ##args);\ printf("\n"); #define LOGE(fmt, args...) printf("[Error] %s: ", LOG_TAG);\ printf(fmt, ##args);\ printf("\n"); #define BUGLY_AGENT_CLASS @"BuglyAgent" #define BUGLY_AGENT_METHOD_INIT @"initWithAppId:debugMode:" #define BUGLY_AGENT_METHOD_INIT_LOG @"initWithAppId:debugMode:logger:" #define BUGLY_AGENT_METHOD_USER @"setUserIdentifier:" #define BUGLY_AGENT_METHOD_CHANNEL @"setAppChannel:" #define BUGLY_AGENT_METHOD_VERSION @"setAppVersion:" #define BUGLY_AGENT_METHOD_EXCEPTION @"reportException:name:message:stackTrace:userInfo:terminateApp:" #define BUGLY_AGENT_METHOD_SCENE @"setSceneTag:" #define BUGLY_AGENT_METHOD_SCENE_VALUE @"setSceneValue:forKey:" #define BUGLY_AGENT_METHOD_SCENE_CLEAN @"removeSceneValueForKey:" #define BUGLY_AGENT_METHOD_LOG @"level:tag:log:"#endif bool CrashReport::initialized = false; void CrashReport::initCrashReport(const char* appId, bool isDebug) { CrashReport::initCrashReport(appId, isDebug, Warning);} void CrashReport::initCrashReport(const char* appId, bool isDebug, CRLogLevel level) { if (!initialized) { // #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) // LOGI("[cocos2d-x] start init."); // initialized = true; // JavaVM* jvm = cocos2d::JniHelper::getJavaVM(); // if (jvm == NULL) { // LOGE("[cocos2d-x] JavaVM is null."); // return; // } // JNIEnv* env = NULL; // jvm->GetEnv((void**)&env, JNI_VERSION_1_6); // if (env == NULL) { // LOGE("[cocos2d-x] JNIEnv is null."); // return; // } // jvm->AttachCurrentThread(&env, 0); // //get activity // LOGI("[cocos2d-x] try get org.cocos2dx.lib.Cocos2dxActivity"); // jclass activityClass = env->FindClass("org/cocos2dx/lib/Cocos2dxActivity"); // if (activityClass == NULL) { // LOGE("[cocos2d-x] Cocos2dxActivity is Null"); // return; // } // jmethodID methodActivity = env->GetStaticMethodID(activityClass, "getContext", "()Landroid/content/Context;"); // jobject activity = (jobject) env->CallStaticObjectMethod(activityClass, methodActivity); // if (activity == NULL) { // LOGE("[cocos2d-x] activity is Null"); // return; // } // //call channel set package name // #if(SDK_CHANNEL_INDEX != 0) // LOGI("[cocos2d-x] set channel: %d", SDK_CHANNEL_INDEX); // char* packageName = ""; // switch(SDK_CHANNEL_INDEX) { // case 1: // packageName = "com.tencent.bugly.msdk"; // break; // } // jmethodID setChannelMethod = env->GetStaticMethodID(env->FindClass(CRASHREPORT_CLASS), METHOD_SET_CHANNEL, METHOD_SET_CHANNEL_PARAMETER); // LOGI("set packagename: %s", packageName); // env->CallStaticVoidMethod(env->FindClass(CRASHREPORT_CLASS), setChannelMethod, env->NewStringUTF(packageName)); // #endif // //call init // LOGI("[cocos2d-x] init by bugly.jar"); // jmethodID initMethod = env->GetStaticMethodID(env->FindClass(CRASHREPORT_CLASS), METHOD_INIT, METHOD_INIT_PARAMETER); // env->CallStaticVoidMethod(env->FindClass(CRASHREPORT_CLASS), initMethod, activity, env->NewStringUTF(appId), isDebug); // // iOS // #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) // NSString* pAppId = NSStringMake(appId); // BOOL pDebug = isDebug ? YES : NO; // Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); // if (clazz) { // BOOL initLog = true; // SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_INIT_LOG); // NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; // if (signature == nil) { // selector = NSSelectorFromString(BUGLY_AGENT_METHOD_INIT); // signature = [clazz methodSignatureForSelector:selector]; // initLog = false; // } // if (signature) { // LOGI("Init the sdk with App ID: %s", appId); // NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; // [invocation setTarget:clazz]; // [invocation setSelector:selector]; // [invocation setArgument:&pAppId atIndex:2]; // [invocation setArgument:&pDebug atIndex:3]; // if (initLog) { // NSInteger pLevel = (level >= 4 ? 1 : (level == 3 ? 2 : (level == 2 ? 4 : (level == 1 ? 8 : 16)))); // [invocation setArgument:&pLevel atIndex:4]; // } // [invocation invoke]; // } // } else { // NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); // } // #endif // register lua handler#if (BUGLY_REPORT_LUA) lua_register(getLuaState(), "buglyReportLuaException", buglyReportLuaException); lua_register(getLuaState(), "buglyPutUserData", buglyLuaPutUserData); lua_register(getLuaState(), "buglyRemoveUserData", buglyLuaRemoveUserData); lua_register(getLuaState(), "buglySetUserSceneTag", buglyLuaSetUserSceneTag); lua_register(getLuaState(), "buglySetUserId", buglyLuaSetUserId); lua_register(getLuaState(), "buglyLog", buglyLuaLog); LOGI("[cocos2d-x] registered bugly lua functions, init finished");#endif #if (BUGLY_REPORT_JS) #endif initialized = true; }} void CrashReport::setUserSceneTag(int tag) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_SET_USER_SCENE_TAG, METHOD_SET_USER_SCENE_TAG_PARAMETER)) { LOGI("[cocos2d-x] set user scene tag: %d", tag); //get activity jclass activityClass = t.env->FindClass("org/cocos2dx/lib/Cocos2dxActivity"); if (activityClass == NULL) { LOGE("[cocos2d-x] Cocos2dxActivity is Null"); return; } jmethodID methodActivity = t.env->GetStaticMethodID(activityClass, "getContext", "()Landroid/content/Context;"); jobject activity = (jobject) t.env->CallStaticObjectMethod(activityClass, methodActivity); if (activity == NULL) { LOGE("[cocos2d-x] activity is Null"); return; } t.env->CallStaticVoidMethod(t.classID, t.methodID, activity, tag); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) if (tag < 0) { return; } NSUInteger pTag = tag; Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_SCENE); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGI("Set user scene tag id: %d", tag); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pTag atIndex:2]; [invocation invoke]; } } else { NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); }#endif} void CrashReport::putUserData(const char* key, const char* value) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_PUT_USER_DATA, METHOD_PUT_USER_DATA_PARAMETER)) { LOGI("[cocos2d-x] put user data: %s:%s", key, value); //get activity jclass activityClass = t.env->FindClass("org/cocos2dx/lib/Cocos2dxActivity"); if (activityClass == NULL) { LOGE("[cocos2d-x] Cocos2dxActivity is Null"); return; } jmethodID methodActivity = t.env->GetStaticMethodID(activityClass, "getContext", "()Landroid/content/Context;"); jobject activity = (jobject) t.env->CallStaticObjectMethod(activityClass, methodActivity); if (activity == NULL) { LOGE("[cocos2d-x] activity is Null"); return; } t.env->CallStaticVoidMethod(t.classID, t.methodID, activity, t.env->NewStringUTF(key), t.env->NewStringUTF(value)); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSString * pKey = NSStringNonnullMake(key); NSString * pValue = NSStringNonnullMake(value); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_SCENE_VALUE); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGI("Set user Key-Value: [%s, %s]", key, value); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pValue atIndex:2]; [invocation setArgument:&pKey atIndex:3]; [invocation invoke]; } } else { NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); }#endif} void CrashReport::removeUserData(const char* key) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_REMOVE_USER_DATA, METHOD_REMOVE_USER_DATA_PARAMETER)) { LOGI("[cocos2d-x] remove user data: %s", key); //get activity jclass activityClass = t.env->FindClass("org/cocos2dx/lib/Cocos2dxActivity"); if (activityClass == NULL) { LOGE("[cocos2d-x] Cocos2dxActivity is Null"); return; } jmethodID methodActivity = t.env->GetStaticMethodID(activityClass, "getContext", "()Landroid/content/Context;"); jobject activity = (jobject) t.env->CallStaticObjectMethod(activityClass, methodActivity); if (activity == NULL) { LOGE("[cocos2d-x] activity is Null"); return; } t.env->CallStaticVoidMethod(t.classID, t.methodID, activity, t.env->NewStringUTF(key)); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSString * pKey = NSStringNonnullMake(key); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_SCENE_CLEAN); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pKey atIndex:2]; [invocation invoke]; } } else { NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); } #endif} void CrashReport::setUserId(const char* userId) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_SET_USER_ID, METHOD_SET_USER_ID_PARAMETER)) { LOGI("[cocos2d-x] set user id: %s", userId); t.env->CallStaticVoidMethod(t.classID, t.methodID, t.env->NewStringUTF(userId)); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSString * pUserId = NSStringMake(userId); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_USER); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGI("Set user id: %s", userId); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pUserId atIndex:2]; [invocation invoke]; } } else { NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); }#endif} void CrashReport::reportException(int category, const char* type, const char* msg, const char* traceback) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_POST_EXCEPTION, METHOD_POST_EXCEPTION_PARAMETER)) { LOGI("ReportException %d %s %s %s", category, type, msg, traceback); jstring typeStr = t.env->NewStringUTF(type); jstring msgStr = t.env->NewStringUTF(msg); jstring traceStr = t.env->NewStringUTF(traceback); t.env->CallStaticVoidMethod(t.classID, t.methodID, category, typeStr, msgStr, traceStr, false); t.env->DeleteLocalRef(typeStr); t.env->DeleteLocalRef(msgStr); t.env->DeleteLocalRef(traceStr); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSUInteger pCategory = category; NSString * pType = NSStringMake(type); NSString * pMsg = NSStringMake(msg); NSString * pTraceStack = NSStringMake(traceback); NSDictionary * nullObject = nil; BOOL terminateApp = NO; Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_EXCEPTION); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGE("Report exception: %s, %s\n%s", type, msg, traceback); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pCategory atIndex:2]; [invocation setArgument:&pType atIndex:3]; [invocation setArgument:&pMsg atIndex:4]; [invocation setArgument:&pTraceStack atIndex:5]; [invocation setArgument:&nullObject atIndex:6]; [invocation setArgument:&terminateApp atIndex:7]; [invocation invoke]; } } else { NSLog(@"Warning: Fail to get class by NSSelectorFromString(%@)", BUGLY_AGENT_CLASS); }#endif} void CrashReport::setAppChannel(const char * channel){#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) LOGI("No impl");#elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSString * pUserId = NSStringMake(channel); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_CHANNEL); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGI("Set channel: %s", channel); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pUserId atIndex:2]; [invocation invoke]; } }#endif} void CrashReport::setAppVersion(const char * version){#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) LOGI("No impl");#elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) NSString * pUserId = NSStringMake(version); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_VERSION); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { LOGI("Set version: %s", version); NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pUserId atIndex:2]; [invocation invoke]; } }#endif} void CrashReport::log(CRLogLevel level, const char * tag, const char * fmts, ...) {#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) cocos2d::JniMethodInfo t; if (cocos2d::JniHelper::getStaticMethodInfo(t, CRASHREPORT_CLASS, METHOD_SET_LOG, METHOD_SET_LOG_PARAMETER)) { LOGI("[cocos2d-x] set log: %s - %s", tag, fmts); t.env->CallStaticVoidMethod(t.classID, t.methodID, (int)level, t.env->NewStringUTF(tag), t.env->NewStringUTF(fmts)); } #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) if (NULL == fmts) { return; } //Error=4,Warn=3,Info=2,Debug=1,Verbose=0 //LogError=1<<0,Warn=1<<1,Info=1<<2,Debug=1<<3,Verbose=1<<4 NSInteger pLevel = (level >= 4 ? 1 : (level == 3 ? 2 : (level == 2 ? 4 : (level == 1 ? 8 : 16)))); NSString * pTag = NSStringMake(tag); char msg[256] = {0}; va_list args; va_start(args, fmts); vsprintf(msg, fmts, args); va_end(args); NSString * pMsg = NSStringMake(msg); Class clazz = NSClassFromString(BUGLY_AGENT_CLASS); if (clazz) { SEL selector = NSSelectorFromString(BUGLY_AGENT_METHOD_LOG); NSMethodSignature* signature = [clazz methodSignatureForSelector:selector]; if (signature) { NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:clazz]; [invocation setSelector:selector]; [invocation setArgument:&pLevel atIndex:2]; [invocation setArgument:&pTag atIndex:3]; [invocation setArgument:&pMsg atIndex:4]; [invocation invoke]; } }#endif } //special for lua#if (BUGLY_REPORT_LUA) int CrashReport::buglyReportLuaException(lua_State* luaState) { const char* type = ""; const char* msg = lua_tostring(luaState, 1); const char* traceback = lua_tostring(luaState, 2); CrashReport::reportException(CATEGORY_LUA_EXCEPTION, type, msg, traceback); return 0;} int CrashReport::buglyLuaPutUserData(lua_State* luaState) { const char* key = lua_tostring(luaState, 1); const char* value = lua_tostring(luaState, 2); CrashReport::putUserData(key, value); return 0;} int CrashReport::buglyLuaRemoveUserData(lua_State* luaState) { const char* key = lua_tostring(luaState, 1); CrashReport::removeUserData(key); return 0;} int CrashReport::buglyLuaSetUserSceneTag(lua_State* luaState) { int tag = lua_tonumber(luaState, 1); CrashReport::setUserSceneTag(tag); return 0;} int CrashReport::buglyLuaSetUserId(lua_State* luaState) { const char* userId = lua_tostring(luaState, 1); CrashReport::setUserId(userId); return 0;} int CrashReport::buglyLuaLog(lua_State* luaState) { int level = lua_tonumber(luaState, 1); const char* tag = lua_tostring(luaState, 2); const char* logStr = lua_tostring(luaState, 3); CRLogLevel crLevel = Verbose; switch (level) { case 0: crLevel = Verbose; break; case 1: crLevel = Debug; break; case 2: crLevel = Info; break; case 3: crLevel = Warning; break; case 4: crLevel = Error; break; } CrashReport::log(crLevel, tag, logStr); return 0;} lua_State* CrashReport::getLuaState() { #if COCOS2D_VERSION >= 0x00030000 return cocos2d::LuaEngine::getInstance()->getLuaStack()->getLuaState(); #else return cocos2d::CCScriptEngineManager::sharedManager()->getScriptEngine()->getLuaState(); #endif} #endif // special for js#if (BUGLY_REPORT_JS) #endif
初始化Bugly,处理处理防止崩溃,修改AppController.mm //bugly#import <Bugly/CrashReporter.h>#import <Bugly/BuglyLog.h> #define BUGLY_APP_ID @"XXXXXXXXXXXXXXXXX" - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ BJMPlatformUtil::ForceToPortrait(); //NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); cocos2d::CCApplication::sharedApplication().run(); //bugly 延迟3秒初始化 [self performSelector:@selector(setupBugly) withObject:nil afterDelay:3]; return YES;} - (void)setupBugly { #if COCOS2D_DEBUG == 1 [[CrashReporter sharedInstance] enableLog:YES];#endif exp_call_back_func=&exception_callback_handler; [[CrashReporter sharedInstance] installWithAppId:BUGLY_APP_ID]; } static int exception_callback_handler() { NSLog(@"Crash occur in the app"); string strAllLog = DebugUtil::GetAllLog(); StringUtil::ReplaceParam(strAllLog, "%0d", "\n"); NSString *str = [NSString stringWithUTF8String:strAllLog.c_str()]; [[CrashReporter sharedInstance] setAttachLog:str]; return 1;}
我这里补加了,当触发上报时,把游戏内自己的LOG添加进去,调用了系统的setAttachLog方法
注意Other Link Flags不要乱加,默认加一个-ObjC就好,按官方的来加反而会遇到问题
http://bugly.qq.com/cocossdk
剩下就是设置环境路径和测试了,按上面的官方文档就好了。
Header Search Paths ~/Documents/cocos2d_2/bugly
Library Search Paths ~/Documents/cocos2d_2/bugly/ios
!!!特别要注意自己使用的是libc++还是libstdc++,不同的设置需要引入不同的framework
在使用CMD + R进行调试运行时,如果遇到错误它是直接就断点了,不然触发Bugly的上传,想测试。可以先点Stop,然后自己手动再启动一次游戏,通过Devices的日志来查看和测试上传
如果触发了Bugly的上报,你可以根据之前在AppController.mm中打印的Log来进行搜索
=======================================================
跨平台的编译,你会发现在iOS下还好,.mm就直接支持了混编。路径引入也比较简单改设置就完了,最麻烦是Android下必须要用到NDK,而这个就需要编译相关的一些知识,比如mk的编写等。像上面遇到的问题就是很多指令根本就不太了解,通过这次Bugly的接入,发现自己对GCC相关编译知识比较欠缺,所以需要好好补补,毕竟NDK还是非常重要的。fuse基本上就是通过NDK来实现各种绚丽的效果,把.ux文件直接全部转换为C++代码(这个太高难度动作了,要知道C++本身就是所有现代语言中最为复杂的,出一BUG项目想找人解决就很困难,一般人绝对hold不住),之前写过Java与C++的互调,接下来得好好准备GCC相关的学习了
今天收到一封邮件,就是自己之前处理emoji表情崩溃的问题,有人发邮件问我,一般来说我是不怎么回邮件的,但我看到它有一个附件,把log.txt发过来了,然后我花了几分钟浏览了一下错误日志,告诉他大概哪里出了问题。自己把遇到的问题分享出来,能帮忙到其它人,也算是一种幸运吧。
跨平台的开发水比较深,慎入啊,短期内我还看不到WEB成为主流或是跟Native分庭抗衡的可能,Native还将称霸很久,一想到这样难免会感到悲伤…
cocos2d-x 2.x版本接入bugly的总结相关推荐
- cocos2d中CCAnimation的使用(cocos2d 1.0以上版本)
原文地址:cocos2d中CCAnimation的使用(cocos2d 1.0以上版本)作者:七贤林子 在cocos2d 0.9及以下版本中,CCAnimation中可以使用animationWit ...
- Unity接入Bugly+符号表待上传
参考链接: Unity BuglySDK + 符号表接入_于子潇的博客-CSDN博客_bugly unity 符号表 Unity移动应用如何在Bugly上查看崩溃堆栈_linxinfa的专栏-CSDN ...
- YSDK(应用宝)最新版本接入的坑
2020年5月15日备注:根据国家广电局的要求,游戏内必须实名制以及添加未成年人防沉迷限制要求,所以应用宝进行了一波更新,笔者写这篇文档时,应用宝官方文档的版本是1.5.12. 某日,接到运营大佬的紧 ...
- cocos2d 0.99.5版本屏幕默认是横屏,怎么修改为竖屏呢?
在RootViewController.m文件里面,修改如下代码 #elif GAME_AUTOROTATION == kGameAutorotationUIViewController // ...
- 安卓 Android的Bugly SDK的接入
最近公司给了个任务,让接入Bugly SDK,Bugly是个什么东西呢? 官方是这么解释的,腾讯Bugly,为移动开发者提供专业的异常上报和运营统计,帮助开发者快速发现并解决异常,同时掌握产品运营动态 ...
- kakao登录接入V2版本记录
没有中文,全程靠google浏览器强大的翻译了!!! 后续看看要不要接入旧版的 一.首先注册kakao账号 1.注册时注意:手机号码接收时用英文,用中文被拦截了收不到验证码.英文接收的时候,读完一遍先 ...
- Bugly+Tinker实现热修复
1.使用环境 Android Studio版本(Bumblebee ):Android Studio Bumblebee | 2021.1.1 Patch 3 Build #AI-211.7628.2 ...
- Bugly Android热更新总结篇
AndroidManifest文件 新增四大组件 关于Tinker的能力,大家可以移步看下Tinker Wiki. 开发者为什么这么热衷于热更新? 热更新解决了开发者的一个痛点就是程序逻辑出现bug了 ...
- Cocos2d之Action类详解
一.声明 文章中使用到的cocos2d的源代码的版本是cocos2d-x-3.3rc0. 二.主要内容 [Action类简介] 在cocos2d中,Action类是所有动作的基类.Action类继承了 ...
最新文章
- linux下mysql修改字符集,远程连接
- powerbuider11 C/S 转换为B/S
- python学习三:列表,元组
- 对接口运用扩展方法 Applying Extension Methods to an Interface 精通ASP-NET-MVC-5-弗瑞曼 Listing 4-15...
- 【每周CV论文推荐】 初学高效率CNN模型设计应该读的文章
- linux Hello World 模块编程
- Maven : maven工程libraries没有maven dependencies
- 学python之前要学c语言吗_学Python之前需要学c语言吗
- 步进电机驱动选择 的参考
- 全局唯一序列号生成器-支持分布式
- Ubuntu(Linux)腾达U12网卡驱动的离线安装
- 跟我学折纸计算机教案,折纸活动教案
- python求两个向量的夹角
- Ardunio开发实例-L9110直流电机驱动模块
- 容器云系列之容器技术相关概念介绍
- 树莓派的img文件怎样在vmware虚拟机里面打开
- Qt显示调用dll库失败
- Only the original thread that created a view hierarchy can touch its views. 是怎么产生的
- win7系统计算机文件夹缓慢,win7系统搜索文件很慢的两种解决方法
- 如何通过Oracle官网下载jdk历史版本
热门文章
- zabbix在ubuntu16.04上的安装
- # 20155224 实验四 Android程序设计
- V4L2应用程序框架--一【转】
- 响应式web设计之CSS3 Media Queries
- python 字符串分割
- [转][C#] .net动态编译C# 和 VB
- 5 Ways to Speed Up Your Rails App
- sql出现无法启动(model数据库)
- 素数的线性筛法java,埃氏筛 线性筛(欧拉筛) 算法解析
- python文件行数运行结果_python统计文件行数