133 lines
4.5 KiB
Objective-C
133 lines
4.5 KiB
Objective-C
//
|
||
// CrashHandler.m
|
||
// SellyCloudSDK_Example
|
||
//
|
||
// Created by Caleb on 24/10/25.
|
||
// Copyright © 2025 Caleb. All rights reserved.
|
||
//
|
||
|
||
#import "CrashHandler.h"
|
||
#include <libkern/OSAtomic.h>
|
||
#include <execinfo.h>
|
||
#include <signal.h>
|
||
#import <CocoaLumberjack/CocoaLumberjack.h>
|
||
|
||
@interface CrashHandler ()
|
||
|
||
@end
|
||
|
||
void HandleException(NSException *exception);
|
||
void SignalHandler(int signal);
|
||
|
||
@implementation CrashHandler
|
||
|
||
+ (void)load {
|
||
[self installCrashHandler];
|
||
}
|
||
|
||
+ (void)installCrashHandler {
|
||
// 1. 捕获 Objective-C 异常
|
||
NSSetUncaughtExceptionHandler(&HandleException);
|
||
|
||
// 2. 捕获 Unix 信号
|
||
signal(SIGABRT, SignalHandler);
|
||
signal(SIGILL, SignalHandler);
|
||
signal(SIGSEGV, SignalHandler);
|
||
signal(SIGFPE, SignalHandler);
|
||
signal(SIGBUS, SignalHandler);
|
||
signal(SIGPIPE, SignalHandler);
|
||
}
|
||
|
||
+ (NSString *)crashLogPath {
|
||
NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
|
||
return [doc stringByAppendingPathComponent:@"crash.log"];
|
||
}
|
||
|
||
+ (void)saveCrashToLocal:(NSString *)txt {
|
||
// DDLogInfo(@"####crashed:");
|
||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||
BOOL isDir = NO;
|
||
BOOL dataIsDir = NO;
|
||
// fileExistsAtPath 判断一个文件或目录是否有效,isDirectory判断是否一个目录
|
||
NSString* dirPath = [applicationDocumentsDirectory() stringByAppendingPathComponent:@"ErrorLog"];
|
||
NSString* filePath = [dirPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.txt", CarshDate()]];
|
||
BOOL existed = [fileManager fileExistsAtPath:dirPath isDirectory:&isDir];
|
||
BOOL dataExisted = [fileManager fileExistsAtPath:filePath isDirectory:&dataIsDir];
|
||
if (!(isDir == YES && existed == YES)) { //如果文件夹不存在
|
||
[fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||
}
|
||
if (!(dataIsDir == YES && dataExisted == YES)) {
|
||
[txt writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||
}
|
||
}
|
||
|
||
// 沙盒地址
|
||
NSString* applicationDocumentsDirectory(void)
|
||
{
|
||
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
|
||
}
|
||
|
||
NSString* CarshDate(void)
|
||
{
|
||
NSDateFormatter* formatter = [NSDateFormatter new];
|
||
[formatter setDateFormat:@"yyyy-MM-dd_HHmmss"];
|
||
|
||
return [formatter stringFromDate:[NSDate date]];
|
||
}
|
||
|
||
@end
|
||
|
||
// 崩溃时的回调函数
|
||
void HandleException(NSException* exception)
|
||
{
|
||
NSArray* arr = [exception callStackSymbols];
|
||
// 崩溃的原因 可以有崩溃的原因(数组越界,字典nil,调用未知方法...) 崩溃的控制器以及方法
|
||
NSString* reason = [exception reason];
|
||
NSString* name = [exception name];
|
||
NSDictionary* userInfo = [exception userInfo];
|
||
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||
// app名称
|
||
NSString* app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
|
||
// app版本
|
||
NSString* app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
|
||
// app build版本
|
||
NSString* app_build = [infoDictionary objectForKey:@"CFBundleVersion"];
|
||
//手机型号
|
||
NSString* phoneModel = [[UIDevice currentDevice] model];
|
||
//手机系统版本
|
||
NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];
|
||
|
||
NSString* txt = [NSString stringWithFormat:@"========异常错误报告========\n\n"
|
||
@"手机型号:%@ 版本:%@\n"
|
||
@"App名称:%@ 版本:%@(%@)\n\n"
|
||
@"name:%@\n"
|
||
@"userInfo:%@\n\n"
|
||
@"reason:\n%@\n\n"
|
||
@"callStackSymbols:\n%@",
|
||
phoneModel, phoneVersion,
|
||
app_Name, app_Version, app_build,
|
||
name, userInfo, reason,
|
||
[arr componentsJoinedByString:@"\n"]];
|
||
|
||
[CrashHandler saveCrashToLocal:txt];
|
||
}
|
||
|
||
|
||
void SignalHandler(int signal) {
|
||
// 获取调用栈
|
||
void *callstack[128];
|
||
int frames = backtrace(callstack, 128);
|
||
char **strs = backtrace_symbols(callstack, frames);
|
||
|
||
NSMutableString *stackStr = [NSMutableString string];
|
||
for (int i = 0; i < frames; i++) {
|
||
[stackStr appendFormat:@"%s\n", strs[i]];
|
||
}
|
||
|
||
NSString *content = [NSString stringWithFormat:@"Signal %d was raised.\nStack:\n%@", signal, stackStr];
|
||
NSString *path = [CrashHandler crashLogPath];
|
||
[content writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||
|
||
free(strs);
|
||
}
|