iOS集成Bugly详解

异常上报

SDK 集成

  • 通过CocoaPods集成

新建项目

cd 项目目录
vim Podfile

#

source 'https://github.com/CocoaPods/Specs.git'

inhibit_all_warnings!

platform :ios, '7.0'

target 'BuglyDemo' do
pod 'ReactiveCocoa','2.5'
pod 'AFNetworking', '2.5.4'
pod 'MJExtension', '2.0.4'
pod 'MJRefresh','3.1.9'
pod 'SDWebImage','3.7.5'
pod 'UITableView+FDTemplateLayoutCell'
pod 'Bugly'
end

保存并执行pod install,然后用后缀为.xcworkspace的文件打开工程。

初始化SDK

导入头文件

在工程的AppDelegate.m文件导入头文件

 #import <Bugly/Bugly.h>
 //如果是Swift工程,请在对应bridging-header.h中导入

默认Debug模式,是不会生成dSYM文件,需要开启.重新编译CMD+B,修改配置如下图

这里写图片描述

Bugly后台显示异常数据

这里写图片描述

dSYM文件
iOS平台中,dSYM文件是指具有调试信息的目标文件,文件名通常为:xxx.app.dSYM。

  • 为了方便找回Crash对应的dSYM文件和还原堆栈,建议每次构建或者发布APP版本的时候,备份好dSYM文件。

这里写图片描述

生成后,在哪里可以找到dSYM文件?

这里写图片描述

这里写图片描述

这里写图片描述

保存log到本地,并上传到Bugly管理后台

1.遵守代理协议

@interface AppDelegate ()<BuglyDelegate>

2.设置代理对象

 BuglyConfig *config = [[BuglyConfig alloc] init];
 config.delegate = self;
 [Bugly startWithAppId:@"你的AppId" config:config];

3.实现代理方法attachmentForException

#pragma mark - Bugly代理 - 捕获异常,回调(@return 返回需上报记录,随 异常上报一起上报)
- (NSString *)attachmentForException:(NSException *)exception {

    #ifdef DEBUG // 调试
    return [NSString stringWithFormat:@"我是携带信息:%@",[self redirectNSLogToDocumentFolder]];
    #endif

    return nil;
}

#pragma mark - 保存日志文件
- (NSString *)redirectNSLogToDocumentFolder{
    //如果已经连接Xcode调试则不输出到文件
    if(isatty(STDOUT_FILENO)) {
        return nil;
    }
    UIDevice *device = [UIDevice currentDevice];
    if([[device model] hasSuffix:@"Simulator"]){
        //在模拟器不保存到文件中
        return nil;
    }
    //获取Document目录下的Log文件夹,若没有则新建
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *logDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Log"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL fileExists = [fileManager fileExistsAtPath:logDirectory];
    if (!fileExists) {
        [fileManager createDirectoryAtPath:logDirectory  withIntermediateDirectories:YES attributes:nil error:nil];
    }
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; //每次启动后都保存一个新的日志文件中
    NSString *dateStr = [formatter stringFromDate:[NSDate date]];
    NSString *logFilePath = [logDirectory stringByAppendingFormat:@"/%@.txt",dateStr];
    // freopen 重定向输出输出流,将log输入到文件
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);

    return [[NSString alloc] initWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:nil];

}

Bugly iOS 符号表配置

什么是符号表?

符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:

<起始地址> <结束地址> <函数> [<文件名:行号>]

为什么要配置符号表?
为了能快速并准确地定位用户APP发生Crash的代码位置,Bugly使用符号表对APP发生Crash的程序堆栈进行解析和还原。

自动配置:XCode + sh脚本

这里写图片描述

到官方文档下载自动配置符号表工具包,解压如下:

这里写图片描述

使用文档中的方式一进行配置(默认方式)

配置Xcode编译执行脚本

  • 在Xcode工程对应Target的Build Phases中新增Run Scrpit Phase

这里写图片描述

打开工具包中的dSYM_upload.sh,复制所有内容,在新增的Run Scrpit Phase中粘贴

这里写图片描述

修改新增的Run Scrpit中的 <YOUR_APP_ID> 为您的App ID<YOUR_APP_KEY>为您的App Key<YOUR_BUNDLE_ID> 为App的Bundle Id

这里写图片描述

脚本默认在Debug模式及模拟器编译情况下不会上传符号表,在需要上传的时候,请修改下列选项

  • Debug模式编译是否上传,1=上传 0=不上传,默认不上传
UPLOAD_DEBUG_SYMBOLS=0
  • 模拟器编译是否上传,1=上传 0=不上传,默认不上传
UPLOAD_SIMULATOR_SYMBOLS=0

至此,自动上传符号表脚本配置完毕,Bugly 会在每次 Xcode 工程编译后自动完成符号表配置工作。

应用升级&热更新

介绍:
Bugly 应用升级服务为您的应用版本配置升级提醒,并可对用户范围及数量进行精准控制,多纬度数据监控,实时了解版本转化率。

不过看文档介绍没有iOS端的应用升级。

注意Bugly使用的是JSpatch来做热更新的,可能导致上线审核时被拒绝。

因为苹果公司对热更新的强烈抵制,所以Bugly才把异常上报功能和热更新的SDK分开集成。

所以有迫切迭代上线应用的小伙伴慎用!!!
所以有迫切迭代上线应用的小伙伴慎用!!!
所以有迫切迭代上线应用的小伙伴慎用!!!

因为BuglyHotfix SDK v2.0 及以上版本不包含 JSPatch,所以JSPatch要单独集成
这里写图片描述

SDK 集成

pod 'BuglyHotfix'
  • 注意点

BuglyHotfix iOS SDK 最低兼容 iOS 系统版本 iOS 7.0
BuglyHotfix 已经包含 Bugly 的所有功能,如果已经集成 Bugly SDK,请移除 Bugly 并替换成 BuglyHotfix 。

JSPatch 集成

JSPatch下载
把下列文件拖入 Xcode 工程内(请勾选Copy items if needed选项)

JPEngine.h
JPEngine.m
JSPatch.js

在工程内的Prefix Header(后缀为.pch)的文件内 #include “BuglyHotfixConfuse_pch.h” ,如工程内没有 pch 文件请参见这篇文章配置。

初始化SDK

#import "AppDelegate.h"
#import <BuglyHotfix/Bugly.h>
#import <BuglyHotfix/BuglyMender.h>
#import "JPEngine.h"

@interface AppDelegate ()<BuglyDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self configBugly];
    return YES;
}
- (void)configBugly {
    //初始化 Bugly 异常上报
    BuglyConfig *config = [[BuglyConfig alloc] init];
    config.delegate = self;
    config.debugMode = YES;
    config.reportLogLevel = BuglyLogLevelInfo;
    [Bugly startWithAppId:@"b950788e02"
#if DEBUG
        developmentDevice:YES
#endif
                   config:config];

    //捕获 JSPatch 异常并上报
    [JPEngine handleException:^(NSString *msg) {
        NSException *jspatchException = [NSException exceptionWithName:@"Hotfix Exception" reason:msg userInfo:nil];
        [Bugly reportException:jspatchException];
    }];
    //检测补丁策略
    [[BuglyMender sharedMender] checkRemoteConfigWithEventHandler:^(BuglyHotfixEvent event, NSDictionary *patchInfo) {
        //有新补丁或本地补丁状态正常
        if (event == BuglyHotfixEventPatchValid || event == BuglyHotfixEventNewPatch) {
            //获取本地补丁路径
            NSString *patchDirectory = [[BuglyMender sharedMender] patchDirectory];
            if (patchDirectory) {
                //指定执行的 js 脚本文件名
                NSString *patchFileName = @"main.js";
                NSString *patchFile = [patchDirectory stringByAppendingPathComponent:patchFileName];
                //执行补丁加载并上报激活状态
                if ([[NSFileManager defaultManager] fileExistsAtPath:patchFile] &&
                    [JPEngine evaluateScriptWithPath:patchFile] != nil) {
                    BLYLogInfo(@"evaluateScript success");
                    [[BuglyMender sharedMender] reportPatchStatus:BuglyHotfixPatchStatusActiveSucess];
                }else {
                    BLYLogInfo(@"evaluateScript failed");
                    [[BuglyMender sharedMender] reportPatchStatus:BuglyHotfixPatchStatusActiveFail];
                }
            }
        }
    }];
}
#pragma mark - Bugly代理 - 捕获异常,回调(@return 返回需上报记录,随 异常上报一起上报)
- (NSString *)attachmentForException:(NSException *)exception {

#ifdef DEBUG // 调试
    return [NSString stringWithFormat:@"我是携带信息:%@",[self redirectNSLogToDocumentFolder]];
#endif

    return nil;
}

#pragma mark - 保存日志文件
- (NSString *)redirectNSLogToDocumentFolder{
    //如果已经连接Xcode调试则不输出到文件
    if(isatty(STDOUT_FILENO)) {
        return nil;
    }
    UIDevice *device = [UIDevice currentDevice];
    if([[device model] hasSuffix:@"Simulator"]){
        //在模拟器不保存到文件中
        return nil;
    }
    //获取Document目录下的Log文件夹,若没有则新建
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *logDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Log"];
    NSLog(@"%@",paths);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL fileExists = [fileManager fileExistsAtPath:logDirectory];
    if (!fileExists) {
        [fileManager createDirectoryAtPath:logDirectory  withIntermediateDirectories:YES attributes:nil error:nil];
    }
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; //每次启动后都保存一个新的日志文件中
    NSString *dateStr = [formatter stringFromDate:[NSDate date]];
    NSString *logFilePath = [logDirectory stringByAppendingFormat:@"/%@.txt",dateStr];
    // freopen 重定向输出输出流,将log输入到文件
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);

    return [[NSString alloc] initWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:nil];

}

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/81703692