diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f173fe6..9e662c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## XX.XX.XX +* Added a new config option disableViewRestartForManualRecording to disable auto close/restart behavior of manual views on app background/foreground actions. + ## 25.4.8 * Mitigated an issue where "giveAllConsent" did not include metrics consent. diff --git a/Countly.m b/Countly.m index 7d220020..a6f25e1d 100644 --- a/Countly.m +++ b/Countly.m @@ -248,6 +248,10 @@ - (void)startWithConfig:(CountlyConfig *)config } #endif + if(config.disableViewRestartForManualRecording){ + CountlyViewTrackingInternal.sharedInstance.isManualViewRestartActive = NO; + } + if(config.experimental.enablePreviousNameRecording) { CountlyViewTrackingInternal.sharedInstance.enablePreviousNameRecording = YES; } diff --git a/CountlyConfig.h b/CountlyConfig.h index 6c268a18..215586a5 100644 --- a/CountlyConfig.h +++ b/CountlyConfig.h @@ -693,6 +693,11 @@ typedef enum : NSUInteger */ @property (nonatomic) BOOL disableBackoffMechanism; +/** + * Disable view restarting for manual view recording + */ +@property(nonatomic) BOOL disableViewRestartForManualRecording; + #if (TARGET_OS_IOS) /** * Variable to access content configurations. diff --git a/CountlyTests/CountlyBaseTestCase.swift b/CountlyTests/CountlyBaseTestCase.swift index e98a6147..d85115d0 100644 --- a/CountlyTests/CountlyBaseTestCase.swift +++ b/CountlyTests/CountlyBaseTestCase.swift @@ -34,7 +34,9 @@ class CountlyBaseTestCase: XCTestCase { } func cleanupState() { - Countly.sharedInstance().halt(true) + // TODO: This also nils the instances which makes testing bad + // Shared instances are static they must not be nilled for multi instance cases. + //Countly.sharedInstance().halt(true) } } diff --git a/CountlyTests/CountlyViewTests.swift b/CountlyTests/CountlyViewTests.swift index 6569fd76..541deb59 100644 --- a/CountlyTests/CountlyViewTests.swift +++ b/CountlyTests/CountlyViewTests.swift @@ -701,9 +701,43 @@ class CountlyViewForegroundBackgroundTests: CountlyViewBaseTest { func testBackgroundAndForegroundTriggers() throws { let config = createBaseConfig() Countly.sharedInstance().start(with: config) + + Countly.sharedInstance().views().startView("View1") + + goBackgroundForeground() + let startedQueuedEventsCount = ["View1": 1] + + let endedQueuedEventsDurations = ["View1": [3]] + + // Call validateRecordedEvents to check if the events match expectations + validateQueuedViews(startedEventsCount: startedQueuedEventsCount, endedEventsDurations: endedQueuedEventsDurations) + + let startedEventsCount = ["View1": 1] + + let endedEventsDurations: [String: [Int]] = [:] + + // Call validateRecordedEvents to check if the events match expectations + validateRecordedViews(startedEventsCount: startedEventsCount, endedEventsDurations: endedEventsDurations) + } + + func testBackgroundAndForegroundTriggers_manualViewRestartDisabled() throws { + let config = createBaseConfig() + config.disableViewRestartForManualRecording = true + Countly.sharedInstance().start(with: config) + Countly.sharedInstance().views().startView("View1") + goBackgroundForeground() + + // Call validateRecordedEvents to check if the events match expectations + validateQueuedViews(startedEventsCount: ["View1": 1], endedEventsDurations: [:]) // no end view now + + // Call validateRecordedEvents to check if the events match expectations + validateRecordedViews(startedEventsCount: [:], endedEventsDurations: [:]) + } + + private func goBackgroundForeground() { // Create expectations for various events let waitForStart = XCTestExpectation(description: "Wait for 3 seconds before backgrounding app.") let waitForBackground = XCTestExpectation(description: "Wait for 4 seconds in background.") @@ -730,20 +764,6 @@ class CountlyViewForegroundBackgroundTests: CountlyViewBaseTest { // Wait for all expectations to be fulfilled wait(for: [waitForStart, waitForBackground, waitForForeground], timeout: 15.0) - - let startedQueuedEventsCount = ["View1": 1] - - let endedQueuedEventsDurations = ["View1": [3]] - - // Call validateRecordedEvents to check if the events match expectations - validateQueuedViews(startedEventsCount: startedQueuedEventsCount, endedEventsDurations: endedQueuedEventsDurations) - - let startedEventsCount = ["View1": 1] - - let endedEventsDurations: [String: [Int]] = [:] - - // Call validateRecordedEvents to check if the events match expectations - validateRecordedViews(startedEventsCount: startedEventsCount, endedEventsDurations: endedEventsDurations) } } diff --git a/CountlyViewTrackingInternal.h b/CountlyViewTrackingInternal.h index b21e2e1e..4f342350 100644 --- a/CountlyViewTrackingInternal.h +++ b/CountlyViewTrackingInternal.h @@ -22,6 +22,8 @@ extern NSString* const kCountlyVTKeyVisit; @property (nonatomic) NSString* currentViewName; @property (nonatomic) NSString* previousViewName; +@property (nonatomic) BOOL isManualViewRestartActive; + + (instancetype)sharedInstance; #if (TARGET_OS_IOS || TARGET_OS_VISION || TARGET_OS_TV) diff --git a/CountlyViewTrackingInternal.m b/CountlyViewTrackingInternal.m index 8331e2af..8407db6d 100644 --- a/CountlyViewTrackingInternal.m +++ b/CountlyViewTrackingInternal.m @@ -104,6 +104,7 @@ - (instancetype)init self.viewDataDictionary = NSMutableDictionary.new; self.viewSegmentation = nil; self.isFirstView = YES; + self.isManualViewRestartActive = YES; } return self; @@ -753,11 +754,13 @@ - (NSString*)titleForViewController:(UIViewController *)viewController - (void)applicationWillEnterForeground { #if (TARGET_OS_IOS || TARGET_OS_VISION || TARGET_OS_TV) - if (!self.isAutoViewTrackingActive) { + if (!self.isAutoViewTrackingActive && self.isManualViewRestartActive) { [self startStoppedViewsInternal]; } #else - [self startStoppedViewsInternal]; + if (self.isManualViewRestartActive) { + [self startStoppedViewsInternal]; + } #endif } - (void)applicationDidEnterBackground { @@ -765,11 +768,13 @@ - (void)applicationDidEnterBackground { if (self.isAutoViewTrackingActive) { [self stopCurrentView]; } - else { + else if (self.isManualViewRestartActive) { [self stopRunningViewsInternal]; } #else - [self stopRunningViewsInternal]; + if (self.isManualViewRestartActive) { + [self stopRunningViewsInternal]; + } #endif }