最开始项目使用的是自己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_shared
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libBugly.so
include $(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就好,按官方的来加反而会遇到问题
剩下就是设置环境路径和测试了,按上面的官方文档就好了。
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的总结的更多相关文章
-
Coder 投稿 | mPaaS 的多版本接入(Android)
本文作者:mPaaS 用户「Q-Coder」 同时欢迎更多的开发者向 mPaaS 投稿 原文:blog.csdn.net/yqq577/article/details/116801705 前言 对于 ...
-
iOS - swift项目接入bugly - 报错, 配置符号表,下载Java环境,
1.pod 安装,无需配置任何东西 2.终端找到路径: pod install 3.在 appdelegate 导入 import Bugly extension AppDelegate{ /// ...
-
cocos2dx 接入bugly 报错 Fail to get class by NSClassFromString(BuglyAgent)
ios 端安装文档接入库后,报错 -> static void BuglyJSAgent::reportJSError(JSContext *, const char *, JSErrorRep ...
-
腾讯bugly接入插件(CocosCreator)
下载: plugin-bugly.zip (1.4 MB) 插件开源地址: https://github.com/tidys/CocosCreatorPlugins/tree/master/packa ...
-
由源代码编译SpriteBuilder最新版本1.5.0搭配最新的Cocos2D 3.4.9
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家知道SpriteBuilder版本停留在1.4.9已经很久 ...
-
Bugly——Xuporter问题处理
Unity接入Bugly 用其原生的package文件导入,结果在Ios打包时报错,找不到相对应的库. 经过排查: 这个地方如果不加拦截的话,项目中所有的 .projmods文件都会按照xupor ...
-
【腾讯优测干货】看腾讯的技术大牛如何将Crash率从2.2%降至0.2%?
小优有话说: App Crash就像地雷. 你怕它,想当它不存在.无异于让你的用户去探雷,一旦引爆,用户就没了. 你鼓起勇气去扫雷,它却神龙见首不见尾. 你告诫自己一定开发过程中减少crash,少埋点 ...
-
【重磅推荐】腾讯Bugly2015年移动应用质量大数据报告
2015年,随着移动智能设备的普及,移动端用户的增速明显放缓:相比之下,由于云服务.众筹平台.推广平台等基础设施和服务的不断改善,极大降低了创业的门槛,越来越多人投身于移动应用的创新创业中. 想让用户 ...
-
几个移动App测试工具
介绍几款移动App测试的工具: 腾讯测试:http://bugly.qq.com/优测:http://utest.qq.com/fir.im测试:http://bughd.com/ 大致介绍如下: b ...
随机推荐
-
Consul 启动命令
服务端: nohup consul agent -server -bootstrap-expect 1 -config-dir /etc/consul.d/ -data-dir /var/opt/co ...
-
修改Apache配置文件开启gzip压缩传输
转自:http://down.chinaz.com/server/201202/1645_1.htm 最近无事研究一些Web的优化,用工具page speed检测网站时发现还没有开启gzip压缩,于是 ...
-
AngularJS(17)-Angular小程序
现在可以开始创建您的第一个 AngularJS 应用程序,一个 AngularJS 单页 Web 应用. <!DOCTYPE html> <html lang="en&qu ...
-
Intra-cluster Replication in Apache Kafka--reference
Kafka is a distributed publish-subscribe messaging system. It was originally developed at LinkedIn a ...
-
[转]Delphi导出Excel的设置操作
procedure CreatRepSheet(SheetName:String;PageSize,PageLay:Integer); {新建Excel工作簿.进行页面设置} begin {新建Exc ...
-
Java jsp 示例
<!DOCTYPE html> <!-- [ published at 2015-11-13 12:30:50 ] --> <html> <head> ...
-
hdu - 2586 (LCA板子题)
传送门 (这次的英文题面要比上一个容易看多了) (英语蒟蒻的卑微) 又是一个很裸的LCA题 (显然,这次不太容易打暴力咧) (但听说还是有大佬用dfs直接a掉了) 正好 趁这个机会复习一下LCA 这里 ...
-
Spring Cloud之踩坑01 -- Eureka高可用配置
转载:https://blog.csdn.net/dear_Alice_moon/article/details/79373955 问题描述: 在进行Eureka高可用配置时,控制台一直出现“.... ...
-
Java中常用的方法
枚举: 1:DemoEnum.valueOf(String str) 从枚举类中中找字符串,如果有则返回对应枚举值 2:DemoEnum.values() 获得枚举集合 3:DemoEnum.prop ...
-
插件写法之脚本运行环境,mac和window检测
(function(root, factroy){ /* * 在这里进行对脚本运行环境的检测判断 * 浏览器中 有window对象 * node.js服务器端 有Global对象 * * IE11 ...