Files
peko-ios/YuMi/Global/BuglyManager.m

263 lines
7.7 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// BuglyManager.m
// YuMi
//
// Created by BuglyManager
// Copyright © 2024 YuMi. All rights reserved.
//
#import "BuglyManager.h"
#import <Bugly/Bugly.h>
@interface BuglyManager () <BuglyDelegate>
@property (nonatomic, strong) NSString *appId;
@property (nonatomic, assign) BOOL isConfigured;
@end
@implementation BuglyManager
#pragma mark - Singleton
+ (instancetype)sharedManager {
static BuglyManager *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[BuglyManager alloc] init];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
_isConfigured = NO;
}
return self;
}
#pragma mark - BuglyDelegate
- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception {
NSString *message = [NSString stringWithFormat:@"%@ - %@", exception.name, exception.reason];
[self handleLagDetection:message];
return message;
}
#pragma mark - Public Methods
- (void)configureWithAppId:(NSString *)appId debug:(BOOL)isDebug {
if (self.isConfigured) {
NSLog(@"[BuglyManager] Bugly 已经配置,跳过重复配置");
return;
}
if (!appId || appId.length == 0) {
NSLog(@"[BuglyManager] 错误appId 不能为空");
return;
}
self.appId = appId;
// 创建 Bugly 配置
BuglyConfig *config = [[BuglyConfig alloc] init];
config.delegate = self;
// 基础配置
config.blockMonitorTimeout = 3.0; // 卡顿监控超时时间3秒
config.blockMonitorEnable = YES; // 启用卡顿监控
// 调试模式配置
if (isDebug) {
config.debugMode = NO; // 生产环境关闭调试模式
config.channel = [self getAppChannel];
config.reportLogLevel = BuglyLogLevelWarn; // 设置日志级别
} else {
config.unexpectedTerminatingDetectionEnable = YES; // 非正常退出事件记录
config.debugMode = NO;
config.channel = [self getAppChannel];
config.blockMonitorEnable = YES;
config.reportLogLevel = BuglyLogLevelWarn;
}
// 启动 Bugly
[Bugly startWithAppId:appId config:config];
self.isConfigured = YES;
NSLog(@"[BuglyManager] Bugly 配置完成 - AppID: %@, Debug: %@", appId, isDebug ? @"YES" : @"NO");
}
- (void)reportError:(NSString *)domain
code:(NSInteger)code
userInfo:(NSDictionary *)userInfo {
if (!self.isConfigured) {
NSLog(@"[BuglyManager] 错误Bugly 未配置,无法上报错误");
return;
}
if (!domain || domain.length == 0) {
domain = @"UnknownError";
}
// 创建错误对象
NSError *error = [NSError errorWithDomain:domain
code:code
userInfo:userInfo];
// 异步上报错误
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[Bugly reportError:error];
NSLog(@"[BuglyManager] 错误上报成功 - Domain: %@, Code: %ld", domain, (long)code);
});
}
- (void)reportBusinessError:(NSString *)message
code:(NSInteger)code
context:(NSDictionary *)context {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
// 添加基础信息
if (message && message.length > 0) {
[userInfo setObject:message forKey:@"error_message"];
}
[userInfo setObject:@(code) forKey:@"error_code"];
[userInfo setObject:@"BusinessError" forKey:@"error_type"];
// 添加上下文信息
if (context && context.count > 0) {
[userInfo addEntriesFromDictionary:context];
}
// 添加时间戳
[userInfo setObject:@([[NSDate date] timeIntervalSince1970]) forKey:@"timestamp"];
[self reportError:@"BusinessError" code:code userInfo:userInfo];
}
- (void)reportNetworkError:(NSString *)uid
api:(NSString *)api
code:(NSInteger)code
userInfo:(NSDictionary *)userInfo {
NSMutableDictionary *errorInfo = [NSMutableDictionary dictionary];
// 添加网络错误特有信息
if (uid && uid.length > 0) {
[errorInfo setObject:uid forKey:@"user_id"];
}
if (api && api.length > 0) {
[errorInfo setObject:api forKey:@"api_path"];
}
[errorInfo setObject:@(code) forKey:@"http_code"];
[errorInfo setObject:@"NetworkError" forKey:@"error_type"];
// 添加调用栈信息
[errorInfo setObject:[NSThread callStackSymbols] forKey:@"call_stack_symbols"];
// 合并额外信息
if (userInfo && userInfo.count > 0) {
[errorInfo addEntriesFromDictionary:userInfo];
}
[self reportError:@"NetworkError" code:code userInfo:errorInfo];
}
- (void)reportIAPError:(NSString *)uid
transactionId:(NSString *)transactionId
orderId:(NSString *)orderId
status:(NSInteger)status
context:(NSDictionary *)context {
NSMutableDictionary *errorInfo = [NSMutableDictionary dictionary];
// 添加内购错误特有信息
if (uid && uid.length > 0) {
[errorInfo setObject:uid forKey:@"user_id"];
}
if (transactionId && transactionId.length > 0) {
[errorInfo setObject:transactionId forKey:@"transaction_id"];
}
if (orderId && orderId.length > 0) {
[errorInfo setObject:orderId forKey:@"order_id"];
}
[errorInfo setObject:@(status) forKey:@"status_code"];
[errorInfo setObject:@"IAPError" forKey:@"error_type"];
// 添加状态描述
NSString *statusMsg = [self getIAPStatusMessage:status];
if (statusMsg) {
[errorInfo setObject:statusMsg forKey:@"status_message"];
}
// 合并上下文信息
if (context && context.count > 0) {
[errorInfo addEntriesFromDictionary:context];
}
// 生成错误码
NSInteger errorCode = -20000 + status;
[self reportError:@"IAPError" code:errorCode userInfo:errorInfo];
}
- (void)startLagDetection {
if (!self.isConfigured) {
NSLog(@"[BuglyManager] 错误Bugly 未配置,无法启动卡顿检测");
return;
}
NSLog(@"[BuglyManager] 手动启动卡顿检测");
// Bugly 会自动进行卡顿检测,这里主要是日志记录
}
#pragma mark - Private Methods
- (void)handleLagDetection:(NSString *)stackTrace {
NSLog(@"[BuglyManager] 🚨 检测到卡顿 - StackTrace: %@", stackTrace);
// 计算卡顿持续时间这里假设为3秒实际应该从 Bugly 配置中获取)
NSTimeInterval duration = 3.0;
// 通知代理
if (self.delegate && [self.delegate respondsToSelector:@selector(buglyManager:didDetectLag:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[(id<BuglyManagerDelegate>)self.delegate buglyManager:self didDetectLag:duration];
});
}
// TODO: 触发卡顿通知逻辑
// 1. 记录卡顿信息到本地日志
// 2. 发送本地通知
// 3. 记录到性能监控系统
// 4. 触发用户反馈机制
}
- (NSString *)getAppChannel {
// 这里应该调用项目中的工具方法获取渠道信息
// 暂时返回默认值
return @"AppStore";
}
- (NSString *)getIAPStatusMessage:(NSInteger)status {
switch (status) {
case 0:
return @"尝试验单";
case 1:
return @"验单-补单成功";
case 2:
return @"验单-补单失败";
case 3:
return @"验单-补单 id 异常";
case 4:
return @"重试次数过多";
case 5:
return @"过期交易清理";
default:
return @"未知状态";
}
}
@end