前段时间在做皮肤适配的时候,遇到了一些问题,在某些机型上面,如果 hook setBackgroundColor 方法,某些情况下回概率性的崩溃。在 goolgle 上面搜索很多资料,尝试了一些方法,但是仍然会有少部分机型概率性的崩溃。再加上其他模块,比如书架等也会偶现数据库数据异常的问题。针对这些写了一个小的工具,就是当 App 在短时间内连续 crash 超过两次,下次用户进入APP时会提示用户是否重置账号,其实 APP的工作就是还原数据和屏蔽一些可能导致 crash 的功能。(PS: 其实还可以通过开关来控制,但是开关不是本部门维护的,所以… … 懂得,自己来才靠谱)
关于 crash 做了两种监听
- NSException 异常捕获
- Signal 异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| static NSUncaughtExceptionHandler * originalUncaughtExceptionHandler; - (void)_registerExceptionHandler { if (NSGetUncaughtExceptionHandler()) { originalUncaughtExceptionHandler = NSGetUncaughtExceptionHandler(); } NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); } // sigaction -- - (void)_registerSignalHandler { // 由 abort 函数调用发生的终止信号 signal(SIGABRT, signalHandler); // 由内存地址未对齐导致的终止信号 signal(SIGBUS, signalHandler); // 由浮点数异常导致的终止信号 signal(SIGFPE, signalHandler); // 由非法指令产生的终止信号 signal(SIGILL, signalHandler); // 通过端口发送消息失败导致的终止信号 signal(SIGPIPE, signalHandler); // 无效的内存导致的终止信号 signal(SIGSEGV, signalHandler); }
|
此处关于捕获需要注意判断之前是否已经有人再捕获,有的话需要保留之前捕获的现场。
每次收到异常后更新时间戳,然后在下次APP启动时判断是否需要重置账号信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| - (void)_recordContinuouslyCrash { NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; NSDictionary * storageInfo = [userDefaults objectForKey:kContinuouslyCrash]; NSMutableDictionary * crashInfo = [NSMutableDictionary dictionary]; if (storageInfo) { [crashInfo addEntriesFromDictionary:storageInfo]; } NSDate * lateCrashTime = [crashInfo objectForKey:kContinuouslyCrashLateTime]; NSDate * nowTime = [NSDate date]; // 如果 5 分钟内有连续的两次 crash,则需要进入 reset 状态 if (lateCrashTime && (nowTime.timeIntervalSince1970 - lateCrashTime.timeIntervalSince1970 <= 5 * 60)) { [crashInfo setObject:@(YES) forKey:kContinuouslyCrashNeedReset]; } [crashInfo setObject:nowTime forKey:kContinuouslyCrashLateTime]; [userDefaults setObject:crashInfo forKey:kContinuouslyCrash]; [userDefaults synchronize]; }
/// 是否有连续的 crash - (BOOL)hasContinuouslyCrash { BOOL hasContinuouslyCrash = NO; NSDictionary * crashInfo = [[NSUserDefaults standardUserDefaults] objectForKey:kContinuouslyCrash]; if (crashInfo) { id value = [crashInfo objectForKey:kContinuouslyCrashNeedReset]; if ([value respondsToSelector:@selector(boolValue)]) { hasContinuouslyCrash = [value boolValue]; } } return hasContinuouslyCrash; }
|
Demo地址