
- Removed YuMi/Library/ (138 MB, not tracked) - Removed YuMi/Resources/ (23 MB, not tracked) - Removed old version assets (566 files, not tracked) - Excluded Pods/, xcuserdata/ and other build artifacts - Clean repository optimized for company server deployment
407 lines
13 KiB
Objective-C
407 lines
13 KiB
Objective-C
//
|
||
// BuglyManager.m
|
||
// YuMi
|
||
//
|
||
// Created by BuglyManager
|
||
// Copyright © 2024 YuMi. All rights reserved.
|
||
//
|
||
|
||
#import "BuglyManager.h"
|
||
#import <Bugly/Bugly.h>
|
||
#import "TurboModeStateManager.h"
|
||
|
||
@interface BuglyManager () <BuglyDelegate>
|
||
|
||
@property (nonatomic, strong) NSString *appId;
|
||
@property (nonatomic, assign) BOOL isConfigured;
|
||
|
||
// 卡顿计数相关
|
||
@property (nonatomic, assign) NSInteger lagCount;
|
||
@property (nonatomic, assign) BOOL isInRoom;
|
||
@property (nonatomic, assign) BOOL isTurboModeEnabled;
|
||
|
||
@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;
|
||
_lagCount = 0;
|
||
_isInRoom = NO;
|
||
_isTurboModeEnabled = NO;
|
||
|
||
// 监听 turbo mode 状态变化
|
||
[self setupTurboModeNotifications];
|
||
|
||
// 🔧 修复:初始化时获取当前 turbo mode 状态
|
||
[self updateTurboModeState];
|
||
}
|
||
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 - 测试方法
|
||
|
||
- (void)simulateLagDetection {
|
||
NSLog(@"[BuglyManager] 🧪 模拟卡顿检测(测试按钮触发)");
|
||
|
||
// 模拟卡顿检测,触发计数逻辑
|
||
[self handleLagCountWithDuration:3.0 stackTrace:@"模拟卡顿 - 测试按钮触发"];
|
||
}
|
||
|
||
#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];
|
||
});
|
||
}
|
||
|
||
// 🔧 新增:卡顿计数逻辑
|
||
[self handleLagCountWithDuration:duration stackTrace:stackTrace];
|
||
}
|
||
|
||
#pragma mark - 卡顿计数逻辑
|
||
|
||
- (void)handleLagCountWithDuration:(NSTimeInterval)duration stackTrace:(NSString *)stackTrace {
|
||
// 规则2:当 turbo mode 开启时,不计数
|
||
if (self.isTurboModeEnabled) {
|
||
NSLog(@"[BuglyManager] 🎮 Turbo Mode 已开启,跳过卡顿计数");
|
||
return;
|
||
}
|
||
|
||
// 规则1:只有在房间内才计数
|
||
if (!self.isInRoom) {
|
||
NSLog(@"[BuglyManager] 🏠 不在房间内,跳过卡顿计数");
|
||
return;
|
||
}
|
||
|
||
// 增加计数
|
||
self.lagCount++;
|
||
NSLog(@"[BuglyManager] 📊 卡顿计数: %ld/3", (long)self.lagCount);
|
||
|
||
// 检查是否达到3次
|
||
if (self.lagCount >= 3) {
|
||
NSLog(@"[BuglyManager] 🚨 累计卡顿3次,触发 Turbo Mode Tips");
|
||
|
||
// 发送通知给 Tips Manager
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"BuglyManagerDidDetectLag"
|
||
object:nil
|
||
userInfo:@{@"duration": @(duration),
|
||
@"stackTrace": stackTrace ?: @"",
|
||
@"lagCount": @(self.lagCount),
|
||
@"shouldShowTips": @YES}];
|
||
});
|
||
|
||
// 重置计数
|
||
self.lagCount = 0;
|
||
} else {
|
||
// 未达到3次,只发送计数通知
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"BuglyManagerDidDetectLag"
|
||
object:nil
|
||
userInfo:@{@"duration": @(duration),
|
||
@"stackTrace": stackTrace ?: @"",
|
||
@"lagCount": @(self.lagCount),
|
||
@"shouldShowTips": @NO}];
|
||
});
|
||
}
|
||
}
|
||
|
||
- (void)setupTurboModeNotifications {
|
||
// 监听 turbo mode 状态变化
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(turboModeStateChanged:)
|
||
name:@"TurboModeStateChanged"
|
||
object:nil];
|
||
|
||
// 监听房间进入/退出
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(roomDidEnter:)
|
||
name:@"RoomDidEnter"
|
||
object:nil];
|
||
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(roomDidExit:)
|
||
name:@"RoomDidExit"
|
||
object:nil];
|
||
}
|
||
|
||
- (void)turboModeStateChanged:(NSNotification *)notification {
|
||
NSNumber *enabled = notification.userInfo[@"enabled"];
|
||
if (enabled) {
|
||
self.isTurboModeEnabled = [enabled boolValue];
|
||
NSLog(@"[BuglyManager] 🎮 Turbo Mode 状态变化: %@", enabled.boolValue ? @"开启" : @"关闭");
|
||
|
||
// 规则2:当 turbo mode 开启时,计数复位为0
|
||
if (enabled.boolValue) {
|
||
self.lagCount = 0;
|
||
NSLog(@"[BuglyManager] 🔄 Turbo Mode 开启,卡顿计数复位为0");
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)roomDidEnter:(NSNotification *)notification {
|
||
self.isInRoom = YES;
|
||
|
||
// 🔧 修复:进入房间时主动获取当前 turbo mode 状态
|
||
[self updateTurboModeState];
|
||
|
||
NSLog(@"[BuglyManager] 🏠 用户进入房间,开始卡顿监控 - Turbo Mode: %@",
|
||
self.isTurboModeEnabled ? @"开启" : @"关闭");
|
||
}
|
||
|
||
- (void)roomDidExit:(NSNotification *)notification {
|
||
self.isInRoom = NO;
|
||
// 规则3:当用户退出房间时,计数复位为0
|
||
self.lagCount = 0;
|
||
NSLog(@"[BuglyManager] 🚪 用户退出房间,卡顿计数复位为0");
|
||
}
|
||
|
||
#pragma mark - 状态更新方法
|
||
|
||
- (void)updateTurboModeState {
|
||
// 从 TurboModeStateManager 获取当前状态
|
||
BOOL currentTurboModeState = [[TurboModeStateManager sharedManager] isTurboModeEnabled];
|
||
|
||
if (self.isTurboModeEnabled != currentTurboModeState) {
|
||
self.isTurboModeEnabled = currentTurboModeState;
|
||
NSLog(@"[BuglyManager] 🔄 主动更新 Turbo Mode 状态: %@",
|
||
currentTurboModeState ? @"开启" : @"关闭");
|
||
|
||
// 如果 turbo mode 开启,计数复位为0
|
||
if (currentTurboModeState) {
|
||
self.lagCount = 0;
|
||
NSLog(@"[BuglyManager] 🔄 Turbo Mode 开启,卡顿计数复位为0");
|
||
}
|
||
}
|
||
}
|
||
|
||
- (NSString *)getAppChannel {
|
||
// 这里应该调用项目中的工具方法获取渠道信息
|
||
// 暂时返回默认值
|
||
return @"AppStore";
|
||
}
|
||
|
||
#pragma mark - Dealloc
|
||
|
||
- (void)dealloc {
|
||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||
}
|
||
|
||
- (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
|