SellyCloudSDK_demo/Example/SellyCloudSDK/CrashHandler.m

133 lines
4.5 KiB
Objective-C
Raw Permalink 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.

//
// 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);
}