iOS 集成 Bugly 二三事

Bugly 官网

腾讯Bugly,为移动开发者提供专业的异常上报和运营统计,帮助开发者快速发现并解决异常,同时掌握产品运营动态,及时跟进用户反馈。

最近 iOS 项目中集成了 Bugly ,集成该框架的过程中,90%的问题通过仔细阅读 Bugly 官方文档 都可以解决。

💡 本文并不会教你如何注册申请 Bugly 帐号,也不会教你如何集成 Bugly SDK,因为官方文档是最权威的,这里只是记录几个注意点(传说中的坑!)。

初始化 Bugly 的注意点

方式一,最简单

在工程AppDelegate.mapplication:didFinishLaunchingWithOptions:方法中初始化:

#import "AppDelegate.h"
#import <Bugly/Bugly.h>

// Bugly 帐号中创建产品后,产品信息中的 AppId
static NSString *const KBuglyAppId = @"**********"; 

@implementation AppDelegate
  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Bugly startWithAppId:KBuglyAppId];
    return YES;
}

方式二,官方文档中的"高级功能"

Bugly支持读取 Info.plist 文件读取SDK初始化参数,可配置的参数如下:

- Appid
    - Key: BuglyAppIDString
    - Value: 字符串类型
- 渠道标识
    - Key: BuglyAppChannelString
    - Value: 字符串类型
- 版本信息
    - Key: BuglyAppVersionString
    - Value: 字符串类型
- 开启Debug信息显示
    - Key: BuglyDebugEnable
    - Value: BOOL类型

我们设置 Info.plist 文件如下:

image

如下初始化方式,则会读取Info.plist内添加的key-value配置进行SDK初始化:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 读取Info.plist中的参数初始化SDK
    [Bugly startWithAppId:nil];
    return YES;
}

以上方式初始化 Bugly 确实没问题,可是默认的 BuglyConfig 还有几个监控开关没开,我也想顺便开启一下:

// 可能存在问题的代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  
    BuglyConfig *config = [[BuglyConfig alloc] init];
    config.blockMonitorEnable = YES; // 卡顿监控开关,默认关闭
    config.blockMonitorTimeout = 5;
    config.unexpectedTerminatingDetectionEnable = YES; // 非正常退出事件记录开关,默认关闭

    // 读取Info.plist中的参数初始化SDK
    [Bugly startWithAppId:nil config:config];
    
    return YES;
}

⚠️ 注意,这样初始化就会有问题,如果配置了Info.plist字段,又在初始化时传入了自定义的 BuglyConfig 实例,那么在 Info.plist 中配置的 BuglyAppChannelStringBuglyAppVersionStringBuglyDebugEnable 会因为被覆盖而失效。

方式三,自定义配置

如果需要自定义配置 BuglyConfig 实例,这里就不建议不同时配置Info.plist字段(或者可以只配置BuglyAppIDString字段):

完整代码:

#import "AppDelegate.h"
#import <Bugly/Bugly.h>

static NSString *const KBuglyAppId = @"**********";

@implementation AppDelegate

#pragma mark - UIApplicationDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [self p_configureForBugly]; 
  
    return YES;
}

#pragma mark - Private

- (void)p_configureForBugly {
    BuglyConfig *config = [[BuglyConfig alloc] init];
    config.channel = @"App Store";
    config.blockMonitorEnable = YES; // 卡顿监控开关,默认关闭
    config.blockMonitorTimeout = 5;
    config.unexpectedTerminatingDetectionEnable = YES; // 非正常退出事件记录开关,默认关闭
    config.delegate = self;

#ifdef DEBUG
    config.debugMode = YES; // debug 模式下,开启调试模式
    config.reportLogLevel = BuglyLogLevelVerbose; // 设置打印日志级别
#else
    config.debugMode = NO; // release 模式下,关闭调试模式
    config.reportLogLevel = BuglyLogLevelWarn; // 设置自定义日志上报的级别,默认不上报自定义日志
#endif
    
    [Bugly startWithAppId:KBuglyAppId config:config];
}

⚠️ 如果你配置完 Bugly 之后,

BLYLogError(fmt, ...)
BLYLogWarn(fmt, ...)
BLYLogInfo(fmt, ...)
BLYLogDebug(fmt, ...)
BLYLogVerbose(fmt, ...)

如上的日志不会在控制台输出,或者部分类型日志不会输出,那你应该注意到需要设置这段代码:

#ifdef DEBUG
    config.debugMode = YES; // debug 模式下,开启调试模式
    config.reportLogLevel = BuglyLogLevelVerbose; // 设置打印日志级别
#else
    config.debugMode = NO; // release 模式下,关闭调试模式
    config.reportLogLevel = BuglyLogLevelWarn; // 设置自定义日志上报的级别,默认不上报自定义日志
#endif

关于 SDK 回调问题

BuglyConfig.h文件中还有一个可以遵守的协议 BuglyDelegate 用于在系统崩溃时可以同时上传自定义数据。

@protocol BuglyDelegate <NSObject>

@optional
/**
 *  发生异常时回调
 *
 *  @param exception 异常信息
 *
 *  @return 返回需上报记录,随异常上报一起上报
 */
- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception;

@end

我遇到的问题是,出于代码清晰的目的,将应用初始化配置、第三方框架初始化配置、推送、分享相关的代码都放在分类中了:

image

并且在分类中遵守了 <BuglyDelegate> 协议,也实现了简单的回调方法:

- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception {
    return @"需要上传的数据...";
}

正常情况下,应用发生崩溃后,Bugly 会立即上报异常,同时在「崩溃分析」-「跟踪数据」-「附件信息」中显示回调方法中上传的数据文件 crash_attach.log

image

实际上把回调代码写在分类中时,应用发生崩溃时,并不会触发协议方法。所以务必要把所有与 Bugly 初始化及回调代码写在 AppDelegate.m 文件中

最后,附上 Bugly 集成的完整正确代码示例:

#import "AppDelegate.h"
#import <Bugly/Bugly.h>

static NSString *const KBuglyAppId = @"**********";

@interface AppDelegate () <BuglyDelegate>

@end

@implementation AppDelegate

#pragma mark - UIApplicationDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [self p_configureForBugly];
  
    return YES;
}

#pragma mark - Private

- (void)p_configureForBugly {
    BuglyConfig *config = [[BuglyConfig alloc] init];
    config.channel = @"App Store";
    config.blockMonitorEnable = YES; // 卡顿监控开关,默认关闭
    config.blockMonitorTimeout = 5;
    config.unexpectedTerminatingDetectionEnable = YES; // 非正常退出事件记录开关,默认关闭
    config.delegate = self;

#ifdef DEBUG
    config.debugMode = YES; // debug 模式下,开启调试模式
    config.reportLogLevel = BuglyLogLevelVerbose; // 设置自定义日志上报的级别,默认不上报自定义日志
#else
    config.debugMode = NO; // release 模式下,关闭调试模式
    config.reportLogLevel = BuglyLogLevelWarn;
#endif
    
    [Bugly startWithAppId:KBuglyAppId config:config];
}

#pragma mark - BuglyDelegate

- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception {
    NSDictionary *dictionary = @{@"Name":exception.name,
                                 @"Reason":exception.reason};
    return [NSString stringWithFormat:@"Exception:%@",dictionary];
}

@end

过早的优化是万恶之源。——高德纳

对依赖进行抽象化和封装

参考对 Flurry 的封装方法

#import <Foundation/Foundation.h>

/**
 封装 Flurry 埋点
 */
@interface HPInstrumentation : NSObject

+(void)startWithAPIKey:(NSString *)apiKey;
+(void)logEvent:(NSString *)name;
+(void)logEvent:(NSString *)name withParams:(NSDictionary *)params;

+(void)logPageViewForTabBarController:(UITabBarController *)vc;

@end

#import "HPInstrumentation.h"
#import "Flurry.h"

@implementation HPInstrumentation

+(void)startWithAPIKey:(NSString *)apiKey
{
    [Flurry startSession:apiKey];
}

+(void)logEvent:(NSString *)name
{
    NSLog(@"<HPInst> %@", name);
    [Flurry logEvent:name];
}

+(void)logEvent:(NSString *)name withParams:(NSDictionary *)params
{
    NSLog(@"<HPInst> %@ -> %@", name, params);
    [Flurry logEvent:name withParameters:params];
}

+(void)logPageViewForTabBarController:(UITabBarController *)vc {
    NSLog(@"<HPInst> PV: %@", [vc class]);
    [Flurry logAllPageViewsForTarget:vc];
}

@end

尝试对 Bugly 进行封装

#import <Foundation/Foundation.h>

/**
 对依赖进行抽象化和封装
 如果直接在项目中使用崩溃报告系统,那么埋点会分散在项目中的各个角落,不利于后期替换或更改。
 低耦合:增加一个中间层之后,可以随时对依赖的第三方框架进行切换,无须再去修改分散在各个类中的代码。
 */
@interface HQLInstrumentation : NSObject

+ (void)logEvent:(NSString *)name;
+ (void)logEvent:(NSString *)name withParamenters:(NSString *)parameters;

@end

#import "HQLInstrumentation.h"
#import <Bugly/Bugly.h>

@implementation HQLInstrumentation

+ (void)logEvent:(NSString *)name {
    [BuglyLog log:@"%@", name];
}

+ (void)logEvent:(NSString *)name withParamenters:(NSString *)parameters {
    [BuglyLog log:@"%@:%@",name,parameters];
}

@end

相关框架

  • JJException - 保护 Objective-C 应用不闪退的框架。
  • KSCrash - iOS崩溃报告框架
  • PLCrashReporter - Reliable, open-source crash reporting for iOS and Mac OS X.

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容