initial commit
This commit is contained in:
132
Example/SellyCloudSDK/CrashHandler.m
Normal file
132
Example/SellyCloudSDK/CrashHandler.m
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user