diff --git a/FirebasePerformance/CHANGELOG.md b/FirebasePerformance/CHANGELOG.md index fd98d461eee..a5679e943cc 100644 --- a/FirebasePerformance/CHANGELOG.md +++ b/FirebasePerformance/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fix a crash related to registering for notifications when the app is between foreground or background states. (#13174) + # 11.5.0 - [fixed] Replaced usage of the deprecated `UIApplication.keyWindow` property with `UIWindow.isKeyWindow`; this API is also available on visionOS. Note that diff --git a/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m b/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m index f7608fd9d96..5c7db89c9fe 100644 --- a/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m +++ b/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m @@ -35,16 +35,17 @@ - (instancetype)init { } else { _traceBackgroundState = FPRTraceStateForegroundOnly; } + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidBecomeActive:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidBecomeActive:) - name:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationDidEnterBackground:) - name:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + }); } return self; } diff --git a/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m b/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m index ab5268f3f00..272a7c418fa 100644 --- a/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m +++ b/FirebasePerformance/Tests/Unit/FPRTraceBackgroundActivityTrackerTest.m @@ -38,13 +38,27 @@ - (void)testForegroundTracking { /** Validates if the foreground & background state is captured correctly. */ - (void)testBackgroundTracking { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; + FPRTraceBackgroundActivityTracker *tracker = [[FPRTraceBackgroundActivityTracker alloc] init]; NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - XCTAssertEqual(tracker.traceBackgroundState, FPRTraceStateBackgroundAndForeground); + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + XCTAssertEqual(tracker.traceBackgroundState, + FPRTraceStateBackgroundAndForeground); + } + }]; } @end diff --git a/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m b/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m index bd187089d16..39a389fdb3b 100644 --- a/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m +++ b/FirebasePerformance/Tests/Unit/Timer/FIRTraceTest.m @@ -427,15 +427,28 @@ - (void)testValidTraceWithStageAndMetrics { /** Validates the value of background state when the app is backgrounded. */ - (void)testValidTraceWithBackgrounding { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; FIRTrace *trace = [[FIRTrace alloc] initWithName:@"Random"]; [trace start]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - XCTAssertEqual(trace.backgroundTraceState, FPRTraceStateBackgroundAndForeground); - [trace stop]; + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + XCTAssertEqual(trace.backgroundTraceState, + FPRTraceStateBackgroundAndForeground); + [trace stop]; + } + }]; } /** Validates the value of background state when trace is not started. */ @@ -452,15 +465,29 @@ - (void)testValidTraceWithoutStart { /** Validates the value of background state is available after trace is stopped. */ - (void)testBackgroundStateAfterTraceStop { + XCTestExpectation *expectation = [self expectationWithDescription:@"Application state change"]; + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; FIRTrace *trace = [[FIRTrace alloc] initWithName:@"Random"]; [trace start]; - [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification - object:[UIApplication sharedApplication]]; - [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification - object:[UIApplication sharedApplication]]; - [trace stop]; - XCTAssertEqual(trace.backgroundTraceState, FPRTraceStateBackgroundAndForeground); + dispatch_async(dispatch_get_main_queue(), ^{ + [defaultCenter postNotificationName:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + [defaultCenter postNotificationName:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:5.0 + handler:^(NSError *_Nullable error) { + if (error) { + XCTFail(@"Expectation failed with error: %@", error); + } else { + [trace stop]; + XCTAssertEqual(trace.backgroundTraceState, + FPRTraceStateBackgroundAndForeground); + } + }]; } /** Validates that stages do not have any valid background state. */ diff --git a/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh b/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh index 1c45d2521fd..10900343894 100755 --- a/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh +++ b/IntegrationTesting/CocoapodsIntegrationTest/scripts/build_with_environment.sh @@ -27,7 +27,7 @@ function runXcodebuild() { -workspace 'CocoapodsIntegrationTest.xcworkspace' -scheme 'CocoapodsIntegrationTest' -sdk 'iphonesimulator' - -destination 'platform=iOS Simulator,name=iPhone 14' + -destination 'platform=iOS Simulator,name=iPhone 15' CODE_SIGNING_REQUIRED=NO clean build @@ -36,7 +36,7 @@ function runXcodebuild() { parameters=("${buildcache_xcb_flags[@]}" "${parameters[@]}") echo xcodebuild "${parameters[@]}" - xcodebuild "${parameters[@]}" | xcpretty; result=$? + xcodebuild "${parameters[@]}" | xcbeautify --renderer github-actions; result=$? } # Configures bundler environment using Gemfile at the specified path.