From ec8298359c0fe5ca9f3570c6e8945d04f3210768 Mon Sep 17 00:00:00 2001 From: Alexander Chocron Date: Tue, 14 Nov 2017 11:24:57 -0800 Subject: [PATCH 01/13] Fix issues with manual crash processing for react native --- .../AppCenterCrashes/MSCrashes.mm | 63 +++---- .../AppCenterCrashesTests/MSCrashesTests.mm | 157 ++++++++---------- 2 files changed, 107 insertions(+), 113 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index 6f773acfa0..d0949e5dbc 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -84,7 +84,7 @@ static void plcr_post_crash_callback(siginfo_t *info, ucontext_t *uap, void *con } static PLCrashReporterCallbacks plCrashCallbacks = { - .version = 0, .context = NULL, .handleSignal = plcr_post_crash_callback}; + .version = 0, .context = NULL, .handleSignal = plcr_post_crash_callback}; /** * C++ Exception Handler @@ -153,7 +153,7 @@ + (void)generateTestCrash { } } else { MSLogWarning([MSCrashes logTag], @"GenerateTestCrash was just called in an App Store environment. The call will " - @"be ignored"); + @"be ignored"); } } } @@ -213,7 +213,7 @@ - (instancetype)init { _logBufferDir = [MSCrashesUtil logBufferDir]; _analyzerInProgressFile = [_crashesDir URLByAppendingPathComponent:kMSAnalyzerFilename]; _didCrashInLastSession = NO; - _delayedProcessingSemaphore = dispatch_semaphore_create(1); + _delayedProcessingSemaphore = dispatch_semaphore_create(0); _automaticProcessing = YES; #if !TARGET_OS_TV _enableMachExceptionHandler = YES; @@ -245,7 +245,6 @@ - (instancetype)init { #pragma mark - MSServiceAbstract - (void)applyEnabledState:(BOOL)isEnabled { - [super applyEnabledState:isEnabled]; // Enabling. if (isEnabled) { @@ -294,11 +293,14 @@ - (void)applyEnabledState:(BOOL)isEnabled { if (self.crashFiles.count > 0) { [self startDelayedCrashProcessing]; } + else { + dispatch_semaphore_signal(self.delayedProcessingSemaphore); + } // More details on log if a debugger is attached. if ([MSAppCenter isDebuggerAttached]) { MSLogInfo([MSCrashes logTag], @"Crashes service has been enabled but the service cannot detect crashes due to " - "running the application with a debugger attached."); + "running the application with a debugger attached."); } else { MSLogInfo([MSCrashes logTag], @"Crashes service has been enabled."); } @@ -433,12 +435,12 @@ - (void)onEnqueuingLog:(id)log withInternalId:(NSString *)internalId { // Overwrite the oldest buffered log. msCrashesLogBuffer[indexToDelete].buffer = - std::string(&reinterpret_cast(serializedLog.bytes)[0], - &reinterpret_cast(serializedLog.bytes)[serializedLog.length]); + std::string(&reinterpret_cast(serializedLog.bytes)[0], + &reinterpret_cast(serializedLog.bytes)[serializedLog.length]); msCrashesLogBuffer[indexToDelete].internalId = internalId.UTF8String; NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; msCrashesLogBuffer[indexToDelete].timestamp = - [[NSString stringWithFormat:@"%f", now] cStringUsingEncoding:NSUTF8StringEncoding]; + [[NSString stringWithFormat:@"%f", now] cStringUsingEncoding:NSUTF8StringEncoding]; MSLogVerbose([MSCrashes logTag], @"Overwrote buffered log at index %ld.", indexToDelete); // We're done, no need to iterate any more. But no need to `return;` as we're at the end of the buffer. @@ -541,9 +543,9 @@ - (void)configureCrashReporterWithUncaughtExceptionHandlerEnabled:(BOOL)enableUn #endif PLCrashReporterSymbolicationStrategy symbolicationStrategy = PLCrashReporterSymbolicationStrategyNone; MSPLCrashReporterConfig *config = - [[MSPLCrashReporterConfig alloc] initWithSignalHandlerType:signalHandlerType - symbolicationStrategy:symbolicationStrategy - shouldRegisterUncaughtExceptionHandler:enableUncaughtExceptionHandler]; + [[MSPLCrashReporterConfig alloc] initWithSignalHandlerType:signalHandlerType + symbolicationStrategy:symbolicationStrategy + shouldRegisterUncaughtExceptionHandler:enableUncaughtExceptionHandler]; self.plCrashReporter = [[MSPLCrashReporter alloc] initWithConfiguration:config]; /* @@ -595,7 +597,6 @@ - (void)configureCrashReporterWithUncaughtExceptionHandlerEnabled:(BOOL)enableUn #pragma mark - Crash processing - (void)startDelayedCrashProcessing { - /* * FIXME: If application is crashed and relaunched from multitasking view, the SDK starts faster than normal launch * and application state is not updated from inactive to active at this time. Give more delay here for a workaround @@ -607,21 +608,24 @@ - (void)startDelayedCrashProcessing { */ // This must be performed asynchronously to prevent a deadlock with 'unprocessedCrashReports'. - dispatch_semaphore_wait(self.delayedProcessingSemaphore, DISPATCH_TIME_FOREVER); dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (1 * NSEC_PER_SEC)); dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self startCrashProcessing]; - dispatch_semaphore_signal(self.delayedProcessingSemaphore); + @try { + [self startCrashProcessing]; + } + @finally { + dispatch_semaphore_signal(self.delayedProcessingSemaphore); + } }); } - (void)startCrashProcessing { - // FIXME: There is no life cycle for app extensions yet so force start crash processing until then. - if ([MSUtility applicationState] != MSApplicationStateActive && - [MSUtility applicationState] != MSApplicationStateUnknown) { - return; - } + if (self.automaticProcessing && + ([MSUtility applicationState] != MSApplicationStateActive && + [MSUtility applicationState] != MSApplicationStateUnknown)) { + return; + } MSLogDebug([MSCrashes logTag], @"Start delayed CrashManager processing"); // Was our own exception handler successfully added? @@ -637,10 +641,10 @@ - (void)startCrashProcessing { */ if (self.exceptionHandler != currentHandler) { MSLogWarning([MSCrashes logTag], @"Another exception handler was added. If " - @"this invokes any kind of exit() after processing the " - @"exception, which causes any subsequent error handler " - @"not to be invoked, these crashes will NOT be reported " - @"to App Center!"); + @"this invokes any kind of exit() after processing the " + @"exception, which causes any subsequent error handler " + @"not to be invoked, these crashes will NOT be reported " + @"to App Center!"); } } if (!self.sendingInProgress && self.crashFiles.count > 0) { @@ -869,7 +873,7 @@ - (void)handleLatestCrashReport { // Try loading the crash report NSData *crashData = - [[NSData alloc] initWithData:[self.plCrashReporter loadPendingCrashReportDataAndReturnError:&error]]; + [[NSData alloc] initWithData:[self.plCrashReporter loadPendingCrashReportDataAndReturnError:&error]]; if (crashData == nil) { MSLogError([MSCrashes logTag], @"Couldn't load crash report: %@", error.localizedDescription); } else { @@ -900,10 +904,10 @@ - (NSMutableArray *)persistedCrashReports { if ([self.crashesDir checkResourceIsReachableAndReturnError:nil]) { NSArray *files = - [self.fileManager contentsOfDirectoryAtURL:self.crashesDir - includingPropertiesForKeys:@[ NSURLNameKey, NSURLFileSizeKey, NSURLIsRegularFileKey ] - options:NSDirectoryEnumerationOptions(0) - error:&error]; + [self.fileManager contentsOfDirectoryAtURL:self.crashesDir + includingPropertiesForKeys:@[ NSURLNameKey, NSURLFileSizeKey, NSURLIsRegularFileKey ] + options:NSDirectoryEnumerationOptions(0) + error:&error]; if (!files) { MSLogError([MSCrashes logTag], @"Couldn't get files in the directory \"%@\": %@", self.crashesDir, error.localizedDescription); @@ -1196,3 +1200,4 @@ - (void)trackModelException:(MSException *)exception { } @end + diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index d82d9d6f8d..144b9d54a9 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -25,7 +25,7 @@ static NSString *const kMSTestAppSecret = @"TestAppSecret"; static NSString *const kMSCrashesServiceName = @"Crashes"; static NSString *const kMSFatal = @"fatal"; -static NSString *const kMSTypeHandledError = @"handledError"; +static NSString *const kMSTypeHandledError = @"handled_error"; static NSString *const kMSUserConfirmationKey = @"MSUserConfirmation"; static unsigned int kMaxAttachmentsPerCrashReport = 2; @@ -79,8 +79,8 @@ - (void)testNewInstanceWasInitialisedCorrectly { [NSThread sleepForTimeInterval:0.05]; NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; NSArray *files = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; assertThat(files, hasCountOf(ms_crashes_log_buffer_size)); } @@ -123,7 +123,7 @@ - (void)testDelegateMethodsAreCalled { [MSAppCenter sharedInstance].sdkConfigured = NO; [MSAppCenter start:kMSTestAppSecret withServices:@[ [MSCrashes class] ]]; NSMutableDictionary *channelsInLogManager = - (static_cast([MSCrashes sharedInstance].logManager)).channels; + (static_cast([MSCrashes sharedInstance].logManager)).channels; MSChannelDefault *channelMock = channelsInLogManager[groupId] = OCMPartialMock(channelsInLogManager[groupId]); OCMStub([channelMock enqueueItem:OCMOCK_ANY withCompletion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { id log = nil; @@ -170,9 +170,9 @@ - (void)testSettingUserConfirmationHandler { // When MSUserConfirmationHandler userConfirmationHandler = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return NO; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return NO; + }; [MSCrashes setUserConfirmationHandler:userConfirmationHandler]; // Then @@ -219,9 +219,9 @@ - (void)testProcessCrashes { // When self.sut = [MSCrashes new]; MSUserConfirmationHandler userConfirmationHandlerYES = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return YES; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return YES; + }; self.sut.userConfirmationHandler = userConfirmationHandlerYES; [self.sut startCrashProcessing]; @@ -242,9 +242,9 @@ - (void)testProcessCrashes { // When self.sut = [MSCrashes new]; MSUserConfirmationHandler userConfirmationHandlerNO = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return NO; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return NO; + }; self.sut.userConfirmationHandler = userConfirmationHandlerNO; [self.sut startCrashProcessing]; @@ -262,18 +262,17 @@ - (void)testProcessCrashesWithErrorAttachments { NSData *validData = [validString dataUsingEncoding:NSUTF8StringEncoding]; NSData *emptyData = [@"" dataUsingEncoding:NSUTF8StringEncoding]; NSArray *invalidLogs = @[ - [self attachmentWithAttachmentId:nil attachmentData:validData contentType:validString], - [self attachmentWithAttachmentId:@"" attachmentData:validData contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:nil contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:emptyData contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:validData contentType:nil], - [self attachmentWithAttachmentId:validString attachmentData:validData contentType:@""] - ]; - for (NSUInteger i = 0; i < invalidLogs.count; i++) { + [self attachmentWithAttachmentId:nil attachmentData:validData contentType:validString], + [self attachmentWithAttachmentId:@"" attachmentData:validData contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:nil contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:emptyData contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:validData contentType:nil], + [self attachmentWithAttachmentId:validString attachmentData:validData contentType:@""] + ]; + for(NSUInteger i = 0; i < invalidLogs.count; i++) { OCMReject([logManagerMock processLog:invalidLogs[i] forGroupId:OCMOCK_ANY]); } - MSErrorAttachmentLog *validLog = - [self attachmentWithAttachmentId:validString attachmentData:validData contentType:validString]; + MSErrorAttachmentLog *validLog = [self attachmentWithAttachmentId:validString attachmentData:validData contentType:validString]; NSMutableArray *logs = invalidLogs.mutableCopy; [logs addObject:validLog]; id crashesDelegateMock = OCMProtocolMock(@protocol(MSCrashesDelegate)); @@ -281,7 +280,7 @@ - (void)testProcessCrashesWithErrorAttachments { OCMStub([crashesDelegateMock crashes:OCMOCK_ANY shouldProcessErrorReport:OCMOCK_ANY]).andReturn(YES); [[MSCrashes sharedInstance] setDelegate:crashesDelegateMock]; - // Then + //Then OCMExpect([logManagerMock processLog:validLog forGroupId:OCMOCK_ANY]); [[MSCrashes sharedInstance] startCrashProcessing]; OCMVerifyAll(logManagerMock); @@ -347,8 +346,8 @@ - (void)testSetupLogBufferWorks { // Then NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; NSArray *first = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; XCTAssertTrue(first.count == ms_crashes_log_buffer_size); for (NSString *path in first) { unsigned long long fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize]; @@ -360,8 +359,8 @@ - (void)testSetupLogBufferWorks { // Then NSArray *second = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; for (int i = 0; i < ms_crashes_log_buffer_size; i++) { XCTAssertTrue([first[i] isEqualToString:second[i]]); } @@ -371,7 +370,7 @@ - (void)testCreateBufferFile { // When NSString *testName = @"afilename"; NSString *filePath = [[self.sut.logBufferDir path] - stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; + stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; [self.sut createBufferFileAtURL:[NSURL fileURLWithPath:filePath]]; // Then @@ -385,7 +384,7 @@ - (void)testEmptyLogBufferFiles { NSString *dataString = @"SomeBufferedData"; NSData *someData = [dataString dataUsingEncoding:NSUTF8StringEncoding]; NSString *filePath = [[self.sut.logBufferDir path] - stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; + stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; #if TARGET_OS_OSX [someData writeToFile:filePath atomically:YES]; @@ -506,7 +505,7 @@ - (void)testInitializationPriorityCorrect { // The Mach exception handler is not supported on tvOS. #if TARGET_OS_TV -- (void)testMachExceptionHandlerDisabledOnTvOS { +- (void) testMachExceptionHandlerDisabledOnTvOS { // Then XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); @@ -565,16 +564,14 @@ - (void)testAbstractErrorLogSerialization { - (void)testWarningMessageAboutTooManyErrorAttachments { - NSString *expectedMessage = - [NSString stringWithFormat:@"A limit of %u attachments per error report might be enforced by server.", - kMaxAttachmentsPerCrashReport]; + NSString *expectedMessage = [NSString stringWithFormat:@"A limit of %u attachments per error report might be enforced by server.", kMaxAttachmentsPerCrashReport]; __block bool warningMessageHasBeenPrinted = false; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" [MSLogger setLogHandler:^(MSLogMessageProvider messageProvider, MSLogLevel logLevel, NSString *tag, const char *file, const char *function, uint line) { - if (warningMessageHasBeenPrinted) { + if(warningMessageHasBeenPrinted) { return; } NSString *message = messageProvider(); @@ -599,13 +596,13 @@ - (void)testTrackModelException { __block MSException *exception; id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); OCMStub([logManagerMock processLog:[OCMArg isKindOfClass:[MSAbstractLog class]] forGroupId:OCMOCK_ANY]) - .andDo(^(NSInvocation *invocation) { - MSHandledErrorLog *log; - [invocation getArgument:&log atIndex:2]; - type = log.type; - errorId = log.errorId; - exception = log.exception; - }); + .andDo(^(NSInvocation *invocation) { + MSHandledErrorLog *log; + [invocation getArgument:&log atIndex:2]; + type = log.type; + errorId = log.errorId; + exception = log.exception; + }); [MSAppCenter configureWithAppSecret:kMSTestAppSecret]; [self.sut startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; @@ -633,10 +630,8 @@ - (void)testSendOrAwaitWhenAlwaysSendIsTrue { OCMStub([crashes shouldAlwaysSend]).andReturn(YES); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) - withLogManager:logManagerMock - withCrashes:crashes]; + numInvocations++; + }) withLogManager:logManagerMock withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -657,10 +652,8 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyAlwaysSend { OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) - withLogManager:logManagerMock - withCrashes:crashes]; + numInvocations++; + }) withLogManager:logManagerMock withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reports = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -687,10 +680,8 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifySend { OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) - withLogManager:logManagerMock - withCrashes:crashes]; + numInvocations++; + }) withLogManager:logManagerMock withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -714,13 +705,12 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyDontSend { MSCrashes *crashes = OCMPartialMock([MSCrashes new]); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); [crashes setAutomaticProcessing:NO]; + [crashes applyEnabledState:YES]; OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block int numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) - withLogManager:logManagerMock - withCrashes:crashes]; + numInvocations++; + }) withLogManager:logManagerMock withCrashes:crashes]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; // When @@ -759,13 +749,11 @@ - (void)testSendErrorAttachments { __block NSMutableArray *enqueuedAttachments = [[NSMutableArray alloc] init]; NSMutableArray *attachments = [[NSMutableArray alloc] init]; [self setProcessLogImplementation:(^(NSInvocation *invocation) { - numInvocations++; - MSErrorAttachmentLog *attachmentLog; - [invocation getArgument:&attachmentLog atIndex:2]; - [enqueuedAttachments addObject:attachmentLog]; - }) - withLogManager:logManagerMock - withCrashes:crashes]; + numInvocations++; + MSErrorAttachmentLog *attachmentLog; + [invocation getArgument:&attachmentLog atIndex:2]; + [enqueuedAttachments addObject:attachmentLog]; + }) withLogManager:logManagerMock withCrashes:crashes]; [self startCrashes:crashes withReports:NO withLogManager:logManagerMock]; // When @@ -787,6 +775,7 @@ - (void)testGetUnprocessedCrashReports { MSCrashes *crashes = OCMPartialMock([MSCrashes new]); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); [crashes setAutomaticProcessing:NO]; + NSArray *reports = [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; // When @@ -794,9 +783,9 @@ - (void)testGetUnprocessedCrashReports { // Then XCTAssertEqual([reports count], [retrievedReports count]); - for (MSErrorReport *retrievedReport in retrievedReports) { + for (MSErrorReport* retrievedReport in retrievedReports) { BOOL foundReport = NO; - for (MSErrorReport *report in reports) { + for (MSErrorReport* report in reports) { if ([report.incidentIdentifier isEqualToString:retrievedReport.incidentIdentifier]) { foundReport = YES; break; @@ -819,9 +808,9 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { // Then XCTAssertEqual([reports count], [retrievedReports count]); - for (MSErrorReport *retrievedReport in retrievedReports) { + for (MSErrorReport* retrievedReport in retrievedReports) { BOOL foundReport = NO; - for (MSErrorReport *report in reports) { + for (MSErrorReport* report in reports) { if ([report.incidentIdentifier isEqualToString:retrievedReport.incidentIdentifier]) { foundReport = YES; break; @@ -833,15 +822,13 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { #pragma mark Helper -/* +/** * Start Crashes (self.sut) with zero or one crash files on disk. */ -- (NSMutableArray *)startCrashes:(MSCrashes *)crashes - withReports:(BOOL)startWithReports - withLogManager:(id)logManager { - NSMutableArray *reports = [NSMutableArray new]; +- (NSMutableArray *)startCrashes:(MSCrashes*)crashes withReports:(BOOL)startWithReports withLogManager:(id)logManager { + NSMutableArray *reports = [NSMutableArray new]; if (startWithReports) { - for (NSString *fileName in @[ @"live_report_exception" ]) { + for (NSString* fileName in @[@"live_report_exception"]) { XCTAssertTrue([MSCrashesTestUtil copyFixtureCrashReportWithFileName:fileName]); NSData *data = [MSCrashesTestUtil dataOfFixtureCrashReportWithFileName:fileName]; NSError *error; @@ -849,19 +836,21 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { [reports addObject:[MSErrorLogFormatter errorReportFromCrashReport:report]]; } } - [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; + }); + + // [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; if (startWithReports) { - assertThat(crashes.crashFiles, hasCountOf(1)); + //assertThat(crashes.crashFiles, hasCountOf(1)); } return reports; } -/* +/** * Attaches the given block to the given logManager's "processLog" method when invoked with Crash's groupId. */ -- (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation - withLogManager:(id)logManager - withCrashes:(MSCrashes *)crashes { +- (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation withLogManager:(id)logManager withCrashes:(MSCrashes*)crashes { id delegateMock = OCMProtocolMock(@protocol(MSCrashesDelegate)); NSString *groupId = [crashes groupId]; OCMStub([logManager processLog:OCMOCK_ANY forGroupId:groupId]).andDo(invocation); @@ -870,13 +859,12 @@ - (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" -- (NSArray *)attachmentsWithCrashes:(MSCrashes *)crashes - forErrorReport:(MSErrorReport *)errorReport { +- (NSArray *)attachmentsWithCrashes:(MSCrashes *)crashes forErrorReport:(MSErrorReport *)errorReport { id deviceMock = OCMPartialMock([MSDevice new]); OCMStub([deviceMock isValid]).andReturn(YES); NSMutableArray *logs = [NSMutableArray new]; - for (unsigned int i = 0; i < kMaxAttachmentsPerCrashReport + 1; ++i) { + for(unsigned int i = 0; i < kMaxAttachmentsPerCrashReport + 1; ++i) { NSString *text = [NSString stringWithFormat:@"%d", i]; MSErrorAttachmentLog *log = [[MSErrorAttachmentLog alloc] initWithFilename:text attachmentText:text]; log.timestamp = [NSDate dateWithTimeIntervalSince1970:42]; @@ -916,3 +904,4 @@ - (NSMutableArray *)idListFromReports:(NSArray *)reports { } @end + From 2d6dd4672bf81264a0bc6891c8ac35e2a2673ce7 Mon Sep 17 00:00:00 2001 From: Alexander Chocron Date: Tue, 14 Nov 2017 11:43:50 -0800 Subject: [PATCH 02/13] Fix a test and remove try/finally --- AppCenterCrashes/AppCenterCrashes/MSCrashes.mm | 11 ++++++----- .../AppCenterCrashesTests/MSCrashesTests.mm | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index d0949e5dbc..82b64a693b 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -245,7 +245,8 @@ - (instancetype)init { #pragma mark - MSServiceAbstract - (void)applyEnabledState:(BOOL)isEnabled { - + [super applyEnabledState:isEnabled]; + // Enabling. if (isEnabled) { id crashSetupDelegate = [MSWrapperCrashesHelper getCrashHandlerSetupDelegate]; @@ -610,17 +611,17 @@ - (void)startDelayedCrashProcessing { // This must be performed asynchronously to prevent a deadlock with 'unprocessedCrashReports'. dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (1 * NSEC_PER_SEC)); dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - @try { [self startCrashProcessing]; - } - @finally { + dispatch_semaphore_signal(self.delayedProcessingSemaphore); - } }); } - (void)startCrashProcessing { // FIXME: There is no life cycle for app extensions yet so force start crash processing until then. + // Also force start crash processing when automatic processing is disabled. Though it sounds + // counterintuitive, this is important because there are scenarios in some wrappers (i.e. RN) where + // the application state is not ready by the time crash processing needs to happen. if (self.automaticProcessing && ([MSUtility applicationState] != MSApplicationStateActive && [MSUtility applicationState] != MSApplicationStateUnknown)) { diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 144b9d54a9..bbc1fa631d 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -840,9 +840,8 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; }); - // [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; if (startWithReports) { - //assertThat(crashes.crashFiles, hasCountOf(1)); + assertThat(crashes.crashFiles, hasCountOf(1)); } return reports; } From 41f37119298017b6a4bbb38013b7fc935bbbdfc6 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 14 Nov 2017 11:43:50 -0800 Subject: [PATCH 03/13] Remove unused sendingInProgress flag from MSCrashes --- .../AppCenterCrashes/Internals/MSCrashesPrivate.h | 5 ----- AppCenterCrashes/AppCenterCrashes/MSCrashes.mm | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h b/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h index 2466f2437c..51c60886b2 100644 --- a/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h +++ b/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h @@ -116,11 +116,6 @@ typedef struct MSCrashesCallbacks { */ @property(nonatomic) NSUncaughtExceptionHandler *exceptionHandler; -/** - * A flag that indicates that crashes are currently sent to the backend. - */ -@property(nonatomic) BOOL sendingInProgress; - /** * Temporary storage for crashes logs to handle user confirmation and callbacks. */ diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index 6f773acfa0..215a680a96 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -643,7 +643,7 @@ - (void)startCrashProcessing { @"to App Center!"); } } - if (!self.sendingInProgress && self.crashFiles.count > 0) { + if (self.crashFiles.count > 0) { [self processCrashReports]; } } From 66192d06740047b370dfcfb0b947436b6d37093f Mon Sep 17 00:00:00 2001 From: Alexander Chocron Date: Tue, 14 Nov 2017 11:45:22 -0800 Subject: [PATCH 04/13] Fix testtrackmodelexception --- AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index bbc1fa631d..3649809231 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -25,7 +25,7 @@ static NSString *const kMSTestAppSecret = @"TestAppSecret"; static NSString *const kMSCrashesServiceName = @"Crashes"; static NSString *const kMSFatal = @"fatal"; -static NSString *const kMSTypeHandledError = @"handled_error"; +static NSString *const kMSTypeHandledError = @"handledError"; static NSString *const kMSUserConfirmationKey = @"MSUserConfirmation"; static unsigned int kMaxAttachmentsPerCrashReport = 2; From a358e16334856973d9ea6c424e727b3dfc0e64cf Mon Sep 17 00:00:00 2001 From: Alexander Chocron Date: Tue, 14 Nov 2017 12:21:02 -0800 Subject: [PATCH 05/13] Fix potential overflow bug --- AppCenterCrashes/AppCenterCrashes/MSCrashes.mm | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index 82b64a693b..b19b398cc2 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -113,6 +113,12 @@ @interface MSCrashes () */ @property BOOL didCrashInLastSession; +/** + * Indicates if the delayedProcessingSemaphore will need to be released + * anymore. Useful for preventing overflows. + */ +@property BOOL shouldReleaseProcessingSemaphore; + /** * Detail information about the last crash. */ @@ -215,6 +221,7 @@ - (instancetype)init { _didCrashInLastSession = NO; _delayedProcessingSemaphore = dispatch_semaphore_create(0); _automaticProcessing = YES; + _shouldReleaseProcessingSemaphore = YES; #if !TARGET_OS_TV _enableMachExceptionHandler = YES; #endif @@ -611,9 +618,15 @@ - (void)startDelayedCrashProcessing { // This must be performed asynchronously to prevent a deadlock with 'unprocessedCrashReports'. dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (1 * NSEC_PER_SEC)); dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self startCrashProcessing]; + [self startCrashProcessing]; - dispatch_semaphore_signal(self.delayedProcessingSemaphore); + // Only release once to avoid releasing an unbounded number of times. + @synchronized(self) { + if (self.shouldReleaseProcessingSemaphore) { + dispatch_semaphore_signal(self.delayedProcessingSemaphore); + self.shouldReleaseProcessingSemaphore = NO; + } + } }); } @@ -895,7 +908,6 @@ - (void)handleLatestCrashReport { // Purge the report marker at the end of the routine. [self removeAnalyzerFile]; } - [self.plCrashReporter purgePendingCrashReport]; } From 7faca6daedcc592d3e63d2d30251d1ff7c470ad8 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 14 Nov 2017 13:40:25 -0800 Subject: [PATCH 06/13] Fix failing unit tests. --- .../AppCenterCrashesTests/MSCrashesTests.mm | 156 ++++++++++-------- 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 3649809231..8a808a6abb 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -79,8 +79,8 @@ - (void)testNewInstanceWasInitialisedCorrectly { [NSThread sleepForTimeInterval:0.05]; NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; NSArray *files = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; assertThat(files, hasCountOf(ms_crashes_log_buffer_size)); } @@ -123,7 +123,7 @@ - (void)testDelegateMethodsAreCalled { [MSAppCenter sharedInstance].sdkConfigured = NO; [MSAppCenter start:kMSTestAppSecret withServices:@[ [MSCrashes class] ]]; NSMutableDictionary *channelsInLogManager = - (static_cast([MSCrashes sharedInstance].logManager)).channels; + (static_cast([MSCrashes sharedInstance].logManager)).channels; MSChannelDefault *channelMock = channelsInLogManager[groupId] = OCMPartialMock(channelsInLogManager[groupId]); OCMStub([channelMock enqueueItem:OCMOCK_ANY withCompletion:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { id log = nil; @@ -170,9 +170,9 @@ - (void)testSettingUserConfirmationHandler { // When MSUserConfirmationHandler userConfirmationHandler = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return NO; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return NO; + }; [MSCrashes setUserConfirmationHandler:userConfirmationHandler]; // Then @@ -219,9 +219,9 @@ - (void)testProcessCrashes { // When self.sut = [MSCrashes new]; MSUserConfirmationHandler userConfirmationHandlerYES = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return YES; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return YES; + }; self.sut.userConfirmationHandler = userConfirmationHandlerYES; [self.sut startCrashProcessing]; @@ -242,9 +242,9 @@ - (void)testProcessCrashes { // When self.sut = [MSCrashes new]; MSUserConfirmationHandler userConfirmationHandlerNO = - ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { - return NO; - }; + ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { + return NO; + }; self.sut.userConfirmationHandler = userConfirmationHandlerNO; [self.sut startCrashProcessing]; @@ -262,17 +262,18 @@ - (void)testProcessCrashesWithErrorAttachments { NSData *validData = [validString dataUsingEncoding:NSUTF8StringEncoding]; NSData *emptyData = [@"" dataUsingEncoding:NSUTF8StringEncoding]; NSArray *invalidLogs = @[ - [self attachmentWithAttachmentId:nil attachmentData:validData contentType:validString], - [self attachmentWithAttachmentId:@"" attachmentData:validData contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:nil contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:emptyData contentType:validString], - [self attachmentWithAttachmentId:validString attachmentData:validData contentType:nil], - [self attachmentWithAttachmentId:validString attachmentData:validData contentType:@""] - ]; - for(NSUInteger i = 0; i < invalidLogs.count; i++) { + [self attachmentWithAttachmentId:nil attachmentData:validData contentType:validString], + [self attachmentWithAttachmentId:@"" attachmentData:validData contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:nil contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:emptyData contentType:validString], + [self attachmentWithAttachmentId:validString attachmentData:validData contentType:nil], + [self attachmentWithAttachmentId:validString attachmentData:validData contentType:@""] + ]; + for (NSUInteger i = 0; i < invalidLogs.count; i++) { OCMReject([logManagerMock processLog:invalidLogs[i] forGroupId:OCMOCK_ANY]); } - MSErrorAttachmentLog *validLog = [self attachmentWithAttachmentId:validString attachmentData:validData contentType:validString]; + MSErrorAttachmentLog *validLog = + [self attachmentWithAttachmentId:validString attachmentData:validData contentType:validString]; NSMutableArray *logs = invalidLogs.mutableCopy; [logs addObject:validLog]; id crashesDelegateMock = OCMProtocolMock(@protocol(MSCrashesDelegate)); @@ -280,7 +281,7 @@ - (void)testProcessCrashesWithErrorAttachments { OCMStub([crashesDelegateMock crashes:OCMOCK_ANY shouldProcessErrorReport:OCMOCK_ANY]).andReturn(YES); [[MSCrashes sharedInstance] setDelegate:crashesDelegateMock]; - //Then + // Then OCMExpect([logManagerMock processLog:validLog forGroupId:OCMOCK_ANY]); [[MSCrashes sharedInstance] startCrashProcessing]; OCMVerifyAll(logManagerMock); @@ -346,8 +347,8 @@ - (void)testSetupLogBufferWorks { // Then NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; NSArray *first = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; XCTAssertTrue(first.count == ms_crashes_log_buffer_size); for (NSString *path in first) { unsigned long long fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize]; @@ -359,8 +360,8 @@ - (void)testSetupLogBufferWorks { // Then NSArray *second = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) - error:&error]; + contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) + error:&error]; for (int i = 0; i < ms_crashes_log_buffer_size; i++) { XCTAssertTrue([first[i] isEqualToString:second[i]]); } @@ -370,7 +371,7 @@ - (void)testCreateBufferFile { // When NSString *testName = @"afilename"; NSString *filePath = [[self.sut.logBufferDir path] - stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; + stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; [self.sut createBufferFileAtURL:[NSURL fileURLWithPath:filePath]]; // Then @@ -384,7 +385,7 @@ - (void)testEmptyLogBufferFiles { NSString *dataString = @"SomeBufferedData"; NSData *someData = [dataString dataUsingEncoding:NSUTF8StringEncoding]; NSString *filePath = [[self.sut.logBufferDir path] - stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; + stringByAppendingPathComponent:[testName stringByAppendingString:@".mscrasheslogbuffer"]]; #if TARGET_OS_OSX [someData writeToFile:filePath atomically:YES]; @@ -505,7 +506,7 @@ - (void)testInitializationPriorityCorrect { // The Mach exception handler is not supported on tvOS. #if TARGET_OS_TV -- (void) testMachExceptionHandlerDisabledOnTvOS { +- (void)testMachExceptionHandlerDisabledOnTvOS { // Then XCTAssertFalse([[MSCrashes sharedInstance] isMachExceptionHandlerEnabled]); @@ -564,14 +565,16 @@ - (void)testAbstractErrorLogSerialization { - (void)testWarningMessageAboutTooManyErrorAttachments { - NSString *expectedMessage = [NSString stringWithFormat:@"A limit of %u attachments per error report might be enforced by server.", kMaxAttachmentsPerCrashReport]; + NSString *expectedMessage = + [NSString stringWithFormat:@"A limit of %u attachments per error report might be enforced by server.", + kMaxAttachmentsPerCrashReport]; __block bool warningMessageHasBeenPrinted = false; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" [MSLogger setLogHandler:^(MSLogMessageProvider messageProvider, MSLogLevel logLevel, NSString *tag, const char *file, const char *function, uint line) { - if(warningMessageHasBeenPrinted) { + if (warningMessageHasBeenPrinted) { return; } NSString *message = messageProvider(); @@ -596,13 +599,13 @@ - (void)testTrackModelException { __block MSException *exception; id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); OCMStub([logManagerMock processLog:[OCMArg isKindOfClass:[MSAbstractLog class]] forGroupId:OCMOCK_ANY]) - .andDo(^(NSInvocation *invocation) { - MSHandledErrorLog *log; - [invocation getArgument:&log atIndex:2]; - type = log.type; - errorId = log.errorId; - exception = log.exception; - }); + .andDo(^(NSInvocation *invocation) { + MSHandledErrorLog *log; + [invocation getArgument:&log atIndex:2]; + type = log.type; + errorId = log.errorId; + exception = log.exception; + }); [MSAppCenter configureWithAppSecret:kMSTestAppSecret]; [self.sut startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; @@ -630,8 +633,10 @@ - (void)testSendOrAwaitWhenAlwaysSendIsTrue { OCMStub([crashes shouldAlwaysSend]).andReturn(YES); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) withLogManager:logManagerMock withCrashes:crashes]; + numInvocations++; + }) + withLogManager:logManagerMock + withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -652,8 +657,10 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyAlwaysSend { OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) withLogManager:logManagerMock withCrashes:crashes]; + numInvocations++; + }) + withLogManager:logManagerMock + withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reports = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -680,8 +687,10 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifySend { OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) withLogManager:logManagerMock withCrashes:crashes]; + numInvocations++; + }) + withLogManager:logManagerMock + withCrashes:crashes]; [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; @@ -709,8 +718,10 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyDontSend { OCMStub([crashes shouldAlwaysSend]).andReturn(NO); __block int numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { - numInvocations++; - }) withLogManager:logManagerMock withCrashes:crashes]; + numInvocations++; + }) + withLogManager:logManagerMock + withCrashes:crashes]; NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; // When @@ -749,11 +760,13 @@ - (void)testSendErrorAttachments { __block NSMutableArray *enqueuedAttachments = [[NSMutableArray alloc] init]; NSMutableArray *attachments = [[NSMutableArray alloc] init]; [self setProcessLogImplementation:(^(NSInvocation *invocation) { - numInvocations++; - MSErrorAttachmentLog *attachmentLog; - [invocation getArgument:&attachmentLog atIndex:2]; - [enqueuedAttachments addObject:attachmentLog]; - }) withLogManager:logManagerMock withCrashes:crashes]; + numInvocations++; + MSErrorAttachmentLog *attachmentLog; + [invocation getArgument:&attachmentLog atIndex:2]; + [enqueuedAttachments addObject:attachmentLog]; + }) + withLogManager:logManagerMock + withCrashes:crashes]; [self startCrashes:crashes withReports:NO withLogManager:logManagerMock]; // When @@ -783,9 +796,9 @@ - (void)testGetUnprocessedCrashReports { // Then XCTAssertEqual([reports count], [retrievedReports count]); - for (MSErrorReport* retrievedReport in retrievedReports) { + for (MSErrorReport *retrievedReport in retrievedReports) { BOOL foundReport = NO; - for (MSErrorReport* report in reports) { + for (MSErrorReport *report in reports) { if ([report.incidentIdentifier isEqualToString:retrievedReport.incidentIdentifier]) { foundReport = YES; break; @@ -808,9 +821,9 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { // Then XCTAssertEqual([reports count], [retrievedReports count]); - for (MSErrorReport* retrievedReport in retrievedReports) { + for (MSErrorReport *retrievedReport in retrievedReports) { BOOL foundReport = NO; - for (MSErrorReport* report in reports) { + for (MSErrorReport *report in reports) { if ([report.incidentIdentifier isEqualToString:retrievedReport.incidentIdentifier]) { foundReport = YES; break; @@ -825,10 +838,12 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { /** * Start Crashes (self.sut) with zero or one crash files on disk. */ -- (NSMutableArray *)startCrashes:(MSCrashes*)crashes withReports:(BOOL)startWithReports withLogManager:(id)logManager { - NSMutableArray *reports = [NSMutableArray new]; +- (NSMutableArray *)startCrashes:(MSCrashes *)crashes + withReports:(BOOL)startWithReports + withLogManager:(id)logManager { + NSMutableArray *reports = [NSMutableArray new]; if (startWithReports) { - for (NSString* fileName in @[@"live_report_exception"]) { + for (NSString *fileName in @[ @"live_report_exception" ]) { XCTAssertTrue([MSCrashesTestUtil copyFixtureCrashReportWithFileName:fileName]); NSData *data = [MSCrashesTestUtil dataOfFixtureCrashReportWithFileName:fileName]; NSError *error; @@ -836,20 +851,31 @@ - (void)testStartingCrashesWithoutAutomaticProcessing { [reports addObject:[MSErrorLogFormatter errorReportFromCrashReport:report]]; } } + + XCTestExpectation *expectation = [self expectationWithDescription:@"Start the Crashes module"]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [crashes startWithLogManager:logManager appSecret:kMSTestAppSecret]; + [expectation fulfill]; }); + [self waitForExpectationsWithTimeout:1.0 + handler:^(NSError *error) { + if (startWithReports) { + assertThat(crashes.crashFiles, hasCountOf(1)); + } + if (error) { + XCTFail(@"Expectation Failed with error: %@", error); + } + }]; - if (startWithReports) { - assertThat(crashes.crashFiles, hasCountOf(1)); - } return reports; } /** * Attaches the given block to the given logManager's "processLog" method when invoked with Crash's groupId. */ -- (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation withLogManager:(id)logManager withCrashes:(MSCrashes*)crashes { +- (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation + withLogManager:(id)logManager + withCrashes:(MSCrashes *)crashes { id delegateMock = OCMProtocolMock(@protocol(MSCrashesDelegate)); NSString *groupId = [crashes groupId]; OCMStub([logManager processLog:OCMOCK_ANY forGroupId:groupId]).andDo(invocation); @@ -858,12 +884,13 @@ - (void)setProcessLogImplementation:(void (^)(NSInvocation *))invocation withLog #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" -- (NSArray *)attachmentsWithCrashes:(MSCrashes *)crashes forErrorReport:(MSErrorReport *)errorReport { +- (NSArray *)attachmentsWithCrashes:(MSCrashes *)crashes + forErrorReport:(MSErrorReport *)errorReport { id deviceMock = OCMPartialMock([MSDevice new]); OCMStub([deviceMock isValid]).andReturn(YES); NSMutableArray *logs = [NSMutableArray new]; - for(unsigned int i = 0; i < kMaxAttachmentsPerCrashReport + 1; ++i) { + for (unsigned int i = 0; i < kMaxAttachmentsPerCrashReport + 1; ++i) { NSString *text = [NSString stringWithFormat:@"%d", i]; MSErrorAttachmentLog *log = [[MSErrorAttachmentLog alloc] initWithFilename:text attachmentText:text]; log.timestamp = [NSDate dateWithTimeIntervalSince1970:42]; @@ -903,4 +930,3 @@ - (NSMutableArray *)idListFromReports:(NSArray *)reports { } @end - From c1a9ae3cf6afc55048d58111a1903ab85b90655d Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 14 Nov 2017 17:04:06 -0800 Subject: [PATCH 07/13] Bump version to 1.0.1 --- AppCenter.podspec | 2 +- CHANGELOG.md | 10 +++++++++- Config/Version.xcconfig | 2 +- Documentation/iOS/AppCenter/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterCrashes/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterDistribute/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterPush/.jazzy.yaml | 2 +- Documentation/macOS/AppCenter/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterCrashes/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterPush/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenter/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenterCrashes/.jazzy.yaml | 2 +- 15 files changed, 23 insertions(+), 15 deletions(-) diff --git a/AppCenter.podspec b/AppCenter.podspec index 1145754e47..3a4003fb87 100644 --- a/AppCenter.podspec +++ b/AppCenter.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AppCenter' - s.version = '1.0.0' + s.version = '1.0.1' s.summary = 'Visual Studio App Center is your continuous integration, delivery and learning solution for iOS and macOS apps.' s.description = <<-DESC diff --git a/CHANGELOG.md b/CHANGELOG.md index a4d378b272..71529651c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # App Center SDK for iOS and macOS Change Log +## Version 1.0.1 + +This version contains a bugfix that is specifically for the AppCenter SDK for React Native. + +### AppCenterCrashes + +* **[Fix]** Fixes an issue that impacted the App Center SDK for React Native. + ## Version 1.0.0 ### General Availability (GA) Announcement. @@ -8,7 +16,7 @@ This version contains **breaking changes** due to the renaming from Mobile Cente ### AppCenter * **[Feature]** Now supports macOS (preview). -* **[Fix]** Don't send startService log while SDK is disabled. +* **[Fix]** Don't send startService log while SDK is disabled. ### AppCenterAnalytics diff --git a/Config/Version.xcconfig b/Config/Version.xcconfig index 35007feb95..cf13071e70 100644 --- a/Config/Version.xcconfig +++ b/Config/Version.xcconfig @@ -1,2 +1,2 @@ BUILD_NUMBER = 1 -VERSION_STRING = 1.0.0 +VERSION_STRING = 1.0.1 diff --git a/Documentation/iOS/AppCenter/.jazzy.yaml b/Documentation/iOS/AppCenter/.jazzy.yaml index 59ca500c75..62e8d5d9dd 100644 --- a/Documentation/iOS/AppCenter/.jazzy.yaml +++ b/Documentation/iOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenter -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml index 5310a4d693..e88afb7084 100644 --- a/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterCrashes/.jazzy.yaml b/Documentation/iOS/AppCenterCrashes/.jazzy.yaml index c6d21b65aa..aa2334ab2f 100644 --- a/Documentation/iOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/iOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterDistribute/.jazzy.yaml b/Documentation/iOS/AppCenterDistribute/.jazzy.yaml index 1922a8eb6f..1628348eed 100644 --- a/Documentation/iOS/AppCenterDistribute/.jazzy.yaml +++ b/Documentation/iOS/AppCenterDistribute/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterDistribute -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterPush/.jazzy.yaml b/Documentation/iOS/AppCenterPush/.jazzy.yaml index e551a202d7..bfe4cfca80 100644 --- a/Documentation/iOS/AppCenterPush/.jazzy.yaml +++ b/Documentation/iOS/AppCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterPush -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenter/.jazzy.yaml b/Documentation/macOS/AppCenter/.jazzy.yaml index 550734bdad..89300efd32 100644 --- a/Documentation/macOS/AppCenter/.jazzy.yaml +++ b/Documentation/macOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenter -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml index f16a597181..447f294aca 100644 --- a/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterCrashes/.jazzy.yaml b/Documentation/macOS/AppCenterCrashes/.jazzy.yaml index 11c68b5bd2..33dda23b8b 100644 --- a/Documentation/macOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/macOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterPush/.jazzy.yaml b/Documentation/macOS/AppCenterPush/.jazzy.yaml index e60d9ae2bd..01cae40913 100644 --- a/Documentation/macOS/AppCenterPush/.jazzy.yaml +++ b/Documentation/macOS/AppCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterPush -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenter/.jazzy.yaml b/Documentation/tvOS/AppCenter/.jazzy.yaml index d6e62ac602..71ab5f7db3 100644 --- a/Documentation/tvOS/AppCenter/.jazzy.yaml +++ b/Documentation/tvOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenter -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml index 361152704a..a1e0f3eb43 100644 --- a/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml b/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml index f2c8c05301..ac0e99c59f 100644 --- a/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.0 +module_version: 1.0.1 author: Microsoft Corp author_url: http://www.microsoft.com From 11690feca3e313113550fcafdc09bd31afd0beaf Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Tue, 14 Nov 2017 17:11:58 -0800 Subject: [PATCH 08/13] Spaces are awesome =) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71529651c5..4155afcc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Version 1.0.1 -This version contains a bugfix that is specifically for the AppCenter SDK for React Native. +This version contains a bugfix that is specifically for the App Center SDK for React Native. ### AppCenterCrashes From 232057ccbd71b31f9f3dfc18da53814ebf0d550b Mon Sep 17 00:00:00 2001 From: Matt Gibbs Date: Tue, 14 Nov 2017 17:26:23 -0800 Subject: [PATCH 09/13] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5a01155162..112bc8663d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -[![Build Status](https://www.bitrise.io/app/e5b1a2ef546331fb.svg?token=Orwi_AVAExLTuN1ZAzvbFQ&branch=develop)](https://www.bitrise.io/app/e5b1a2ef546331fb) [![codecov](https://codecov.io/gh/Microsoft/AppCenter-SDK-Apple/branch/develop/graph/badge.svg?token=6dlCB5riVi)](https://codecov.io/gh/Microsoft/AppCenter-SDK-Apple) [![CocoaPods](https://img.shields.io/cocoapods/v/AppCenter.svg)](https://cocoapods.org/pods/AppCenter) [![CocoaPods](https://img.shields.io/cocoapods/dt/AppCenter.svg)](https://cocoapods.org/pods/AppCenter) From 717d54dfa47e6c140ed03117e879c3257d3cab19 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 14 Nov 2017 17:53:09 -0800 Subject: [PATCH 10/13] Change script to use new GitHub URL --- bitrise/publish-podspec.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitrise/publish-podspec.sh b/bitrise/publish-podspec.sh index 48b97be232..ead44fb974 100755 --- a/bitrise/publish-podspec.sh +++ b/bitrise/publish-podspec.sh @@ -28,7 +28,7 @@ if [ "$1" == "internal" ] || [ "$1" == "test" ]; then sed "s/\(s\.version[[:space:]]*=[[:space:]]\)\'.*\'$/\1'$SDK_PUBLISH_VERSION'/1" AppCenter.podspec > AppCenter.podspec.tmp; mv AppCenter.podspec.tmp AppCenter.podspec # Change download URL in podspec - sed "s/https:\/\/github\.com\/microsoft\/app-center-sdk-ios\/releases\/download\/#{s.version}\(\/AppCenter-SDK-Apple-\)\(\#{s.version}\)\(.zip\)/https:\/\/mobilecentersdkdev\.blob\.core\.windows\.net\/sdk\1\2+$BITRISE_GIT_COMMIT\3/1" AppCenter.podspec > AppCenter.podspec.tmp; mv AppCenter.podspec.tmp AppCenter.podspec + sed "s/https:\/\/github\.com\/microsoft\/AppCenter-SDK-Apple\/releases\/download\/#{s.version}\(\/AppCenter-SDK-Apple-\)\(\#{s.version}\)\(.zip\)/https:\/\/mobilecentersdkdev\.blob\.core\.windows\.net\/sdk\1\2+$BITRISE_GIT_COMMIT\3/1" AppCenter.podspec > AppCenter.podspec.tmp; mv AppCenter.podspec.tmp AppCenter.podspec fi From db811b5560276fa7791c7ccaeadccb92d795288a Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 14 Nov 2017 18:07:29 -0800 Subject: [PATCH 11/13] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4155afcc44..7b6df0b26f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ This version contains a bugfix that is specifically for the App Center SDK for R ## Version 1.0.0 ### General Availability (GA) Announcement. -This version contains **breaking changes** due to the renaming from Mobile Center to App Center. When you update to this release, existing telemetry and crash log information will not be migrated and will be discarded. This version introduces macOS support (preview). +This version contains **breaking changes** due to the renaming from Mobile Center to App Center. In the unlikely event there was data on the device not sent prior to the update, that data will be discarded. This version introduces macOS support (preview). ### AppCenter From 9578cc11b05284bac334ee3a41af1ca6cdeebcb7 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 14 Nov 2017 22:33:30 -0800 Subject: [PATCH 12/13] Support tvOS in podspec --- AppCenter.podspec | 10 ++++++++-- README.md | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/AppCenter.podspec b/AppCenter.podspec index 61529ba62d..293afc5dde 100644 --- a/AppCenter.podspec +++ b/AppCenter.podspec @@ -9,10 +9,10 @@ Pod::Spec.new do |s| The App Center SDK uses a modular architecture so you can use any or all of the following services: - 1. App Center Analytics (iOS and macOS): + 1. App Center Analytics (iOS, macOS and tvOS): App Center Analytics helps you understand user behavior and customer engagement to improve your app. The SDK automatically captures session count, device properties like model, OS version, etc. You can define your own custom events to measure things that matter to you. All the information captured is available in the App Center portal for you to analyze the data. - 2. App Center Crashes (iOS and macOS): + 2. App Center Crashes (iOS, macOS and tvOS): App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. 3. App Center Distribute (iOS only): @@ -31,6 +31,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' + s.tvos.deployment_target = '10.0' s.source = { :http => "https://github.com/microsoft/AppCenter-SDK-Apple/releases/download/#{s.version}/AppCenter-SDK-Apple-#{s.version}.zip" } s.preserve_path = "AppCenter-SDK-Apple/LICENSE" @@ -41,8 +42,10 @@ Pod::Spec.new do |s| ss.frameworks = 'Foundation', 'SystemConfiguration' ss.ios.frameworks = 'CoreTelephony', 'UIKit' ss.osx.frameworks = 'AppKit' + ss.tvos.frameworks = 'UIKit' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenter.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenter.framework" + ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenter.framework" ss.libraries = 'sqlite3' end @@ -51,8 +54,10 @@ Pod::Spec.new do |s| ss.frameworks = 'Foundation' ss.ios.frameworks = 'UIKit' ss.osx.frameworks = 'AppKit' + ss.tvos.frameworks = 'UIKit' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenterAnalytics.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenterAnalytics.framework" + ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenterAnalytics.framework" end s.subspec 'Crashes' do |ss| @@ -61,6 +66,7 @@ Pod::Spec.new do |s| ss.libraries = 'z', 'c++' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenterCrashes.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenterCrashes.framework" + ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenterCrashes.framework" end s.subspec 'Distribute' do |ss| diff --git a/README.md b/README.md index 112bc8663d..e3ab78b91f 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ The App Center SDK uses a modular architecture so you can use any or all of the 2. **App Center Crashes**: App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. -3. **App Center Distribute**: App Center Distribute will let your users install a new version of the app when you distribute it via the App Center. With a new version of the app available, the SDK will present an update dialog to the users to either download or postpone the new version. Once they choose to update, the SDK will start to update your application. This feature will NOT work if your app is deployed to the app store. **Not available for macOS*. +3. **App Center Distribute**: App Center Distribute will let your users install a new version of the app when you distribute it via the App Center. With a new version of the app available, the SDK will present an update dialog to the users to either download or postpone the new version. Once they choose to update, the SDK will start to update your application. This feature will NOT work if your app is deployed to the app store. **Not available for macOS and tvOS*. -4. **App Center Push**: App Center Push enables you to send push notifications to users of your app from the App Center portal. You can also segment your user base based on a set of properties and send them targeted notifications. +4. **App Center Push**: App Center Push enables you to send push notifications to users of your app from the App Center portal. You can also segment your user base based on a set of properties and send them targeted notifications. **Not available for tvOS*. ## 1. Get started It is super easy to use App Center. Have a look at our [get started documentation](https://docs.microsoft.com/en-us/appcenter/sdk/getting-started/ios) and onboard your app within minutes. Our [detailed documentation](https://docs.microsoft.com/en-us/appcenter/sdk/) is available as well. From da2747e0b4bf8c84c146116df85543d6bdde284d Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Tue, 14 Nov 2017 22:33:42 -0800 Subject: [PATCH 13/13] Revert "Support tvOS in podspec" This reverts commit 9578cc11b05284bac334ee3a41af1ca6cdeebcb7. --- AppCenter.podspec | 10 ++-------- README.md | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/AppCenter.podspec b/AppCenter.podspec index 293afc5dde..61529ba62d 100644 --- a/AppCenter.podspec +++ b/AppCenter.podspec @@ -9,10 +9,10 @@ Pod::Spec.new do |s| The App Center SDK uses a modular architecture so you can use any or all of the following services: - 1. App Center Analytics (iOS, macOS and tvOS): + 1. App Center Analytics (iOS and macOS): App Center Analytics helps you understand user behavior and customer engagement to improve your app. The SDK automatically captures session count, device properties like model, OS version, etc. You can define your own custom events to measure things that matter to you. All the information captured is available in the App Center portal for you to analyze the data. - 2. App Center Crashes (iOS, macOS and tvOS): + 2. App Center Crashes (iOS and macOS): App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. 3. App Center Distribute (iOS only): @@ -31,7 +31,6 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' - s.tvos.deployment_target = '10.0' s.source = { :http => "https://github.com/microsoft/AppCenter-SDK-Apple/releases/download/#{s.version}/AppCenter-SDK-Apple-#{s.version}.zip" } s.preserve_path = "AppCenter-SDK-Apple/LICENSE" @@ -42,10 +41,8 @@ Pod::Spec.new do |s| ss.frameworks = 'Foundation', 'SystemConfiguration' ss.ios.frameworks = 'CoreTelephony', 'UIKit' ss.osx.frameworks = 'AppKit' - ss.tvos.frameworks = 'UIKit' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenter.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenter.framework" - ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenter.framework" ss.libraries = 'sqlite3' end @@ -54,10 +51,8 @@ Pod::Spec.new do |s| ss.frameworks = 'Foundation' ss.ios.frameworks = 'UIKit' ss.osx.frameworks = 'AppKit' - ss.tvos.frameworks = 'UIKit' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenterAnalytics.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenterAnalytics.framework" - ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenterAnalytics.framework" end s.subspec 'Crashes' do |ss| @@ -66,7 +61,6 @@ Pod::Spec.new do |s| ss.libraries = 'z', 'c++' ss.ios.vendored_frameworks = "AppCenter-SDK-Apple/iOS/AppCenterCrashes.framework" ss.osx.vendored_frameworks = "AppCenter-SDK-Apple/macOS/AppCenterCrashes.framework" - ss.tvos.vendored_frameworks = "AppCenter-SDK-Apple/tvOS/AppCenterCrashes.framework" end s.subspec 'Distribute' do |ss| diff --git a/README.md b/README.md index e3ab78b91f..112bc8663d 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ The App Center SDK uses a modular architecture so you can use any or all of the 2. **App Center Crashes**: App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. -3. **App Center Distribute**: App Center Distribute will let your users install a new version of the app when you distribute it via the App Center. With a new version of the app available, the SDK will present an update dialog to the users to either download or postpone the new version. Once they choose to update, the SDK will start to update your application. This feature will NOT work if your app is deployed to the app store. **Not available for macOS and tvOS*. +3. **App Center Distribute**: App Center Distribute will let your users install a new version of the app when you distribute it via the App Center. With a new version of the app available, the SDK will present an update dialog to the users to either download or postpone the new version. Once they choose to update, the SDK will start to update your application. This feature will NOT work if your app is deployed to the app store. **Not available for macOS*. -4. **App Center Push**: App Center Push enables you to send push notifications to users of your app from the App Center portal. You can also segment your user base based on a set of properties and send them targeted notifications. **Not available for tvOS*. +4. **App Center Push**: App Center Push enables you to send push notifications to users of your app from the App Center portal. You can also segment your user base based on a set of properties and send them targeted notifications. ## 1. Get started It is super easy to use App Center. Have a look at our [get started documentation](https://docs.microsoft.com/en-us/appcenter/sdk/getting-started/ios) and onboard your app within minutes. Our [detailed documentation](https://docs.microsoft.com/en-us/appcenter/sdk/) is available as well.