• 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)
     
    后来测试中发现光export出来是不行的,还得include,可以在bugly Android.mk中引入,也可以在项目需要引入bugly相关头文件的mk中引入,类似下图
     

    第三个问题就比较恶心一些了, 最后我是直接在项目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(" ");

        #define LOGD(fmt, args...) printf("[Debug] %s: ", LOG_TAG);
                                   printf(fmt, ##args);
                                   printf(" ");

        #define LOGE(fmt, args...) printf("[Error] %s: ", LOG_TAG);
                                   printf(fmt, ##args);
                                   printf(" ");

        #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 %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
     
    我自己做测试是通过的,截图如下:
     
    IOS接入遇到的坑,初始化注意延时处理,防止崩溃
    初始化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", " ");
       
        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还将称霸很久,一想到这样难免会感到悲伤…

  • 相关阅读:
    【Java学习系列】第3课--Java 高级教程
    【夯实PHP基础】nginx php-fpm 输出php错误日志
    【夯实Mysql基础】MySQL性能优化的21个最佳实践 和 mysql使用索引
    【架构设计】分布式文件系统 FastDFS的原理和安装使用
    【13】2016.12.13 周二--《小结2016》
    【诗词歌赋】2016.12.15 周四--文言鸿儒《年终的日常》
    【算法】(查找你附近的人) GeoHash核心原理解析及代码实现
    【夯实Nginx基础】Nginx工作原理和优化、漏洞
    【夯实PHP基础】PHP的反射机制
    HTML DOM简易学习笔记
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/5058100.html
Copyright © 2020-2023  润新知