1010#import " CrashOpsController.h"
1111#import " DebugToastMessage.h"
1212
13- #import " ZZZipArchive .h"
13+ #import " ModulesAnalytics .h"
1414
1515#import " AppleCrashReportGenerator.h"
1616
2828#import " CrashOpsExtendedViewController+UIViewController.h"
2929
3030typedef void (^FilesUploadCompletion)(NSInteger filesCount);
31-
3231typedef void (^LogsUploadCompletion)(NSArray *reports);
3332
3433@interface CrashOpsController ()
@@ -195,6 +194,7 @@ +(BOOL)isRunningOnSimulator {
195194#endif
196195}
197196
197+ // / Indicator for debug mode, it also can be turned on via config PLIST file
198198+ (BOOL )isDebugModeEnabled {
199199 return _shared.isDebugModeEnabled ;
200200}
@@ -257,7 +257,14 @@ - (void) setupIfNeeded {
257257 crashMonitorAPI->setEnabled (YES );
258258 }
259259
260- [self sendPresence ];
260+ [self sendPresence: ^(BOOL didSucceed) {
261+ if (didSucceed) {
262+ dispatch_after (dispatch_time (DISPATCH_TIME_NOW, (int64_t )(10 * NSEC_PER_SEC)), dispatch_get_main_queue (), ^{
263+ [ModulesAnalytics initiateWithController: self ];
264+ });
265+ }
266+ }];
267+
261268 [self uploadLogs ];
262269 } else {
263270 if (co_oldHandler != nil ) {
@@ -311,27 +318,22 @@ - (void) onAppLaunched {
311318 // CODebugLogArgs(@"App loaded, isJailbroken = %d", CrashOpsController.isJailbroken);
312319}
313320
314- -(void ) sendPresence {
315- if (!isEnabled) return ;
316- if (![[CrashOpsController shared ].appKey length ]) return ;
321+ -(NSDictionary *) generateSessionDetails {
322+ if (!isEnabled) return @{} ;
323+ if (![[CrashOpsController shared ].appKey length ]) return @{} ;
317324
318- if (didSendPresence) return ;
319- didSendPresence = YES ;
320-
321- NSUInteger timestamp = (NSUInteger )_timestamp_milliseconds ();
325+ NSUInteger timestamp = (NSUInteger )_co_timestamp_milliseconds ();
322326
323327 NSMutableDictionary *deviceInfo = [[CrashOpsController getDeviceInfo ] mutableCopy ];
324328 NSDictionary *ksCrashSystemInfo = [[KSCrash sharedInstance ] systemInfo ];
325329
326330 if ([ksCrashSystemInfo count ]) {
327331 NSArray *keys = @[@" cpuType" , @" cpuSubType" , @" cpuArchitecture" , @" storageSize" , @" memorySize" , @" usableMemory" , @" freeMemory" , @" kernelVersion" , @" isJailbroken" ];
328332 for (NSString *key in keys) {
329- BOOL didAdd = [deviceInfo
330- co_setOptionalObject: [ksCrashSystemInfo objectForKey: key]
331- forKey: key];
333+ BOOL didAdd = [deviceInfo co_setOptionalObject: [ksCrashSystemInfo objectForKey: key] forKey: key];
332334
333335 if (!didAdd) {
334- CODebugLog (@" Hmmmm..." );
336+ CODebugLog (@" Hmmmm... Failed to add 'ksCrashSystemInfo' " );
335337 }
336338 }
337339 }
@@ -366,10 +368,37 @@ -(void) sendPresence {
366368 @" iosVersion" : [CrashOpsController iosVersion ],
367369 };
368370
369- NSMutableURLRequest *request = [CrashOpsController prepareRequestWithBody: sessionDetails forEndpoint: @" ping" ];
371+ return sessionDetails;
372+ }
373+
374+ -(void ) sendPresence : (void (^)(BOOL didSucceed))onDone {
375+ if (!onDone) {
376+ return ;
377+ }
378+
379+ if (!isEnabled) {
380+ onDone (NO );
381+ return ;
382+ }
383+
384+ if (![[CrashOpsController shared ].appKey length ]) {
385+ onDone (NO );
386+ return ;
387+ }
388+
389+ if (didSendPresence) {
390+ onDone (NO );
391+ return ;
392+ }
393+
394+ didSendPresence = YES ;
395+
396+ NSDictionary *sessionDetails = [self generateSessionDetails ];
397+ NSMutableURLRequest *request = [ModulesAnalytics prepareRequestWithBody: sessionDetails forEndpoint: @" ping" ];
370398
371399 if (!request) {
372400 [CrashOpsController logInternalError: [NSString stringWithFormat: @" Failed to make request for sending ping: %@ " , sessionDetails]];
401+ onDone (NO );
373402 return ;
374403 }
375404
@@ -379,7 +408,7 @@ -(void) sendPresence {
379408 NSString *responseString = [[NSString alloc ] initWithData: returnedData encoding: NSUTF8StringEncoding];
380409 CODebugLogArgs (@" %@ " , responseString);
381410
382- BOOL wasRequestSuccessful = false ;
411+ BOOL wasRequestSuccessful = NO ;
383412 NSInteger responseStatusCode = 100 ;
384413 if (response && [response isKindOfClass: [NSHTTPURLResponse class ]]) {
385414 responseStatusCode = ((NSHTTPURLResponse *)response).statusCode ;
@@ -404,6 +433,8 @@ -(void) sendPresence {
404433
405434 [CrashOpsController logInternalError: [NSString stringWithFormat: @" Failed to send session details, response string: %@ , file path: %@ " , responseString, sessionDetails]];
406435 }
436+
437+ onDone (wasRequestSuccessful);
407438 }];
408439 }];
409440
@@ -627,7 +658,7 @@ - (void) uploadCrashes:(FilesUploadCompletion) onDone {
627658 [jsonDictionary co_setOptionalObject: allTraces forKey: @" screenTraces" ];
628659 }
629660
630- NSMutableURLRequest *request = [CrashOpsController prepareRequestWithBody: jsonDictionary forEndpoint: @" reports" ];
661+ NSMutableURLRequest *request = [ModulesAnalytics prepareRequestWithBody: jsonDictionary forEndpoint: @" reports" ];
631662
632663 if (!request) {
633664 [CrashOpsController logInternalError: [NSString stringWithFormat: @" Failed to make request for file upload, file path: %@ " , reportPath]];
@@ -793,7 +824,7 @@ - (void) uploadErrors:(FilesUploadCompletion) onDone {
793824 continue ;
794825 }
795826
796- NSMutableURLRequest *request = [CrashOpsController prepareRequestWithBody: jsonDictionary forEndpoint: @" reports" ];
827+ NSMutableURLRequest *request = [ModulesAnalytics prepareRequestWithBody: jsonDictionary forEndpoint: @" reports" ];
797828
798829 if (!request) {
799830 [CrashOpsController logInternalError: [NSString stringWithFormat: @" Failed to make request for file upload, file path: %@ " , reportPath]];
@@ -877,6 +908,7 @@ - (NSMutableDictionary *) prepareCrashLogsToUpload: (NSArray *) fileUrlsList {
877908
878909 NSDictionary *kzCrashDictionary = [CrashOpsController toJsonDictionary: logFileJson];
879910 NSMutableDictionary *crashOpsDictionary = [CrashOpsController addCrashOpsConstantFields: kzCrashDictionary];
911+ crashOpsDictionary[@" isFatal" ] = @YES ;
880912
881913 BOOL didAdd = [allReports co_setOptionalObject: crashOpsDictionary forKey: logFileUrlPath];
882914 if (!didAdd) {
@@ -1007,30 +1039,6 @@ + (NSMutableDictionary *) addCrashOpsConstantFields:(NSDictionary *) reportJson
10071039 return reportCopy;
10081040}
10091041
1010- + (NSMutableURLRequest *) prepareRequestWithBody : (NSDictionary *) bodyDictionary forEndpoint : (NSString *) apiEndpoint {
1011- NSData *postBody = [CrashOpsController toJsonData: bodyDictionary];
1012- if (![postBody length ]) {
1013- return nil ;
1014- }
1015-
1016- NSString *serverUrlString = [NSString stringWithFormat: @" https://crashops.com/api/%@ " , apiEndpoint];
1017-
1018- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: serverUrlString]];
1019-
1020- [request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
1021- [request setHTTPShouldHandleCookies: NO ];
1022- [request setTimeoutInterval: 60 ];
1023- [request setHTTPMethod: @" POST" ];
1024- [request setValue: @" gzip" forHTTPHeaderField: @" Accept-Encoding" ];
1025-
1026- NSString *contentType = [NSString stringWithFormat: @" application/json; charset=utf-8" ];
1027- [request setValue: contentType forHTTPHeaderField: @" Content-Type" ];
1028-
1029- [request setHTTPBody: postBody];
1030-
1031- return request;
1032- }
1033-
10341042- (void ) configureAdvancedSettings {
10351043 KSCrash* handler = [KSCrash sharedInstance ];
10361044
@@ -1058,7 +1066,7 @@ - (void) configureAdvancedSettings {
10581066// Saves extra info for this new incident
10591067-(void ) onEventFileCreated : (NSString *) eventId {
10601068 // the `eventId` will be located under "report"->"id"
1061- NSLog (@" New event ID saved: %@ " , eventId);
1069+ CODebugLogArgs (@" New event ID saved: %@ " , eventId);
10621070
10631071 NSString *eventIdFile = [[self eventsFolderPath ] stringByAppendingPathComponent: eventId];
10641072 if (eventIdFile) {
@@ -1103,14 +1111,19 @@ -(void) passToOtherExceptionHadlers:(NSException *) exception {
11031111 Logs immediately a non-fatal error details with built-in screen traces details into a file.
11041112 Then CrashOps attempts to upload with no farther wating.
11051113 */
1106- - (BOOL ) logError : (NSDictionary *) errorDetails {
1107- if (!errorDetails) return NO ;
1108- if (![errorDetails count ]) return NO ;
1114+ - (BOOL ) logErrorWithTitle : (NSString *) errorTitle andDetails : (NSDictionary *) errorDetails {
1115+ if (![errorDetails count ]) {
1116+ errorDetails = @{};
1117+ }
1118+
1119+ if (![errorTitle length ]) {
1120+ errorTitle = @" missing title" ;
1121+ }
11091122
11101123 NSDate *now = [NSDate date ];
11111124 NSTimeInterval timeMilliseconds = [now timeIntervalSince1970 ] * 1000 ;
11121125 NSInteger timestamp = ((NSInteger ) timeMilliseconds);
1113-
1126+
11141127 NSString *sessionId = appSessionId;
11151128 [[self coGlobalOperationQueue ] addOperationWithBlock: ^{
11161129 NSString *nowString = [CrashOpsController stringFromDate: now withFormat: @" yyyy-MM-dd-HH-mm-ss-SSS_ZZZ" ];
@@ -1123,6 +1136,7 @@ - (BOOL) logError:(NSDictionary *) errorDetails {
11231136 NSArray *breadcrumbs = [ScreenTracer tracesReportForSessionId: sessionId];
11241137
11251138 NSDictionary *jsonDictionary = @{@" errorDetails" : errorDetails,
1139+ @" error" : errorTitle,
11261140 @" report" :@{@" id" : [[NSUUID UUID ] UUIDString ],
11271141 @" timestamp" : [NSNumber numberWithInteger: timestamp],
11281142 @" time" : nowString
@@ -1539,12 +1553,19 @@ +(NSData *) toJsonData:(NSDictionary *) jsonDictionary {
15391553 return nil ;
15401554 }
15411555
1556+ NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary: jsonDictionary];
1557+ for (id key in [jsonDictionary allKeys ]) {
1558+ if (!jsonDictionary[key]) {
1559+ [mutableDictionary removeObjectForKey: key];
1560+ }
1561+ }
1562+
15421563 NSData *jsonData;
15431564 NSError *error;
15441565
15451566 @try {
15461567 // Instead of NSJSONWritingPrettyPrinted, we're not using any option.
1547- jsonData = [NSJSONSerialization dataWithJSONObject: jsonDictionary options: kNilOptions error: &error];
1568+ jsonData = [NSJSONSerialization dataWithJSONObject: mutableDictionary options: kNilOptions error: &error];
15481569 } @catch (NSException *exception) {
15491570 error = [NSError errorWithDomain: kSdkName code: 1 userInfo: @{@" exception" :exception}];
15501571 } @finally {
@@ -1709,6 +1730,37 @@ + (NSString*) stringFromDate:(NSDate*) date withFormat:(NSString *) format {
17091730 return [g_dateFormatter stringFromDate: date];
17101731}
17111732
1733+ +(void ) asyncLoopArray : (NSArray *) elements iterationBody : (void (^)(id element,VoidCallback carryOn)) iterationBody onDone : (VoidCallback) onDone {
1734+ if (!onDone) {
1735+ return ;
1736+ }
1737+
1738+ if (elements.count == 0 ) {
1739+ onDone ();
1740+ return ;
1741+ }
1742+
1743+ NSArray *copied = [NSArray arrayWithArray: elements];
1744+ [CrashOpsController recursivelyIterate: copied index: 0 iterationBody: iterationBody onCompleted: ^{
1745+ onDone ();
1746+ }];
1747+ }
1748+
1749+ +(void ) recursivelyIterate : (NSArray *) elements index : (NSInteger ) index iterationBody : (void (^)(id element,id carryOn))iterationBody onCompleted : (void (^)(void )) onCompleted {
1750+ if (!onCompleted) {
1751+ return ;
1752+ }
1753+
1754+ if (index >= elements.count || index < 0 ) {
1755+ onCompleted ();
1756+ return ;
1757+ }
1758+
1759+ iterationBody ([elements objectAtIndex: index], ^{
1760+ [CrashOpsController recursivelyIterate: elements index: (index + 1 ) iterationBody: iterationBody onCompleted: onCompleted];
1761+ });
1762+ }
1763+
17121764@end
17131765
17141766@implementation NSMutableDictionary (CO_NilSafeDictionary)
0 commit comments