-
Notifications
You must be signed in to change notification settings - Fork 12
/
SFBCrashReporter.m
93 lines (72 loc) · 3.48 KB
/
SFBCrashReporter.m
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
* Copyright (C) 2009 - 2020 Stephen F. Booth <me@sbooth.org>
* See https://github.com/sbooth/SFBCrashReporter/blob/master/LICENSE.txt for license information
*/
#import "SFBCrashReporter.h"
#import "SFBCrashReporterWindowController.h"
@interface SFBCrashReporter (Private)
+ (NSArray<NSString *> *)crashLogDirectories;
+ (NSArray<NSString *> *)crashLogPaths;
@end
@implementation SFBCrashReporter
+ (void)checkForNewCrashes
{
// If no URL is found for the submission, we can't do anything
NSString *crashSubmissionURLString = [[NSUserDefaults standardUserDefaults] stringForKey:@"SFBCrashReporterCrashSubmissionURL"];
if(!crashSubmissionURLString) {
crashSubmissionURLString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SFBCrashReporterCrashSubmissionURL"];
if(!crashSubmissionURLString)
[NSException raise:@"Missing SFBCrashReporterCrashSubmissionURL" format:@"You must specify the URL for crash log submission as the SFBCrashReporterCrashSubmissionURL in either Info.plist or the user defaults!"];
}
// Determine when the last crash was reported
NSDate *lastCrashReportDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"SFBCrashReporterLastCrashReportDate"];
// If a crash was never reported, use now as the starting point
if(!lastCrashReportDate) {
lastCrashReportDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:lastCrashReportDate forKey:@"SFBCrashReporterLastCrashReportDate"];
}
// Determine if it is even necessary to show the window (by comparing file modification dates to the last time a crash was reported)
NSArray *crashLogPaths = [self crashLogPaths];
for(NSString *path in crashLogPaths) {
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
NSDate *fileModificationDate = [fileAttributes fileModificationDate];
// If the last time a crash was reported is earlier than the file's modification date, allow the user to report the crash
if(fileModificationDate && NSOrderedAscending == [lastCrashReportDate compare:fileModificationDate]) {
[SFBCrashReporterWindowController showWindowForCrashLogPath:path submissionURL:[NSURL URLWithString:crashSubmissionURLString]];
// Don't prompt more than once
break;
}
}
}
@end
@implementation SFBCrashReporter (Private)
+ (NSArray *)crashLogDirectories
{
NSString *crashLogDirectory = @"Logs/DiagnosticReports";
NSMutableArray *crashFolderPaths = [[NSMutableArray alloc] init];
NSArray *libraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask | NSLocalDomainMask, YES);
for(NSString *libraryPath in libraryPaths) {
NSString *path = [libraryPath stringByAppendingPathComponent:crashLogDirectory];
BOOL isDir = NO;
if([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir) {
[crashFolderPaths addObject:path];
break;
}
}
return crashFolderPaths;
}
+ (NSArray *)crashLogPaths
{
NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSArray *crashLogDirectories = [self crashLogDirectories];
NSMutableArray *paths = [[NSMutableArray alloc] init];
for(NSString *crashLogDirectory in crashLogDirectories) {
NSString *file = nil;
NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:crashLogDirectory];
while((file = [dirEnum nextObject]))
if([file hasPrefix:applicationName])
[paths addObject:[crashLogDirectory stringByAppendingPathComponent:file]];
}
return paths;
}
@end