diff --git a/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m b/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m index d8c57fef3af..6d0937197d1 100644 --- a/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m +++ b/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m @@ -37,6 +37,15 @@ BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) { #endif // TARGET_OS_IOS } +@interface GDTCORApplication () +/** + Private flag to match the existing `readonly` public flag. This will be accurate for all platforms, + since we handle each platform's lifecycle notifications separately. + */ +@property(atomic, readwrite) BOOL isRunningInBackground; + +@end + @implementation GDTCORApplication + (void)load { @@ -61,6 +70,9 @@ + (nullable GDTCORApplication *)sharedApplication { - (instancetype)init { self = [super init]; if (self) { + // This class will be instantiated in the foreground. + _isRunningInBackground = NO; + #if TARGET_OS_IOS || TARGET_OS_TV NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self @@ -125,16 +137,6 @@ - (BOOL)isAppExtension { #endif } -- (BOOL)isRunningInBackground { -#if TARGET_OS_IOS || TARGET_OS_TV - BOOL runningInBackground = - [[self sharedApplicationForBackgroundTask] applicationState] == UIApplicationStateBackground; - return runningInBackground; -#else // For macoS and Catalyst apps. - return NO; -#endif -} - /** Returns a UIApplication instance if on the appropriate platform. * * @return The shared UIApplication if on the appropriate platform. @@ -160,11 +162,15 @@ - (nullable id)sharedApplicationForBackgroundTask { #if TARGET_OS_IOS || TARGET_OS_TV - (void)iOSApplicationDidEnterBackground:(NSNotification *)notif { + _isRunningInBackground = YES; + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; } - (void)iOSApplicationWillEnterForeground:(NSNotification *)notif { + _isRunningInBackground = NO; + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil]; } diff --git a/GoogleDataTransport/GDTCORLibrary/Public/GDTCORPlatform.h b/GoogleDataTransport/GDTCORLibrary/Public/GDTCORPlatform.h index 2e29e06cb79..00cafc84571 100644 --- a/GoogleDataTransport/GDTCORLibrary/Public/GDTCORPlatform.h +++ b/GoogleDataTransport/GDTCORLibrary/Public/GDTCORPlatform.h @@ -61,18 +61,15 @@ FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInv /** A cross-platform application class. */ @interface GDTCORApplication : NSObject +/** Flag to determine if the application is running in the background. */ +@property(atomic, readonly) BOOL isRunningInBackground; + /** Creates and/or returns the shared application instance. * * @return The shared application instance. */ + (nullable GDTCORApplication *)sharedApplication; -/** Flag to determine if the application is running in the background. - * - * @return YES if the app is running in the background, otherwise NO. - */ -- (BOOL)isRunningInBackground; - /** Creates a background task with the returned identifier if on a suitable platform. * * @name name The name of the task, useful for debugging which background tasks are running. diff --git a/GoogleDataTransport/GDTCORTests/Lifecycle/GDTCORLifecycleTest.m b/GoogleDataTransport/GDTCORTests/Lifecycle/GDTCORLifecycleTest.m index 59a96de4454..03e49c3a39b 100644 --- a/GoogleDataTransport/GDTCORTests/Lifecycle/GDTCORLifecycleTest.m +++ b/GoogleDataTransport/GDTCORTests/Lifecycle/GDTCORLifecycleTest.m @@ -90,8 +90,11 @@ - (void)setUp { [[GDTCORUploadCoordinator sharedInstance] reset]; } +// Backgrounding and foregrounding are only applicable for iOS and tvOS. +#if TARGET_OS_IOS || TARGET_OS_TV + /** Tests that the library serializes itself to disk when the app backgrounds. */ -- (void)DISABLED_testBackgrounding { +- (void)testBackgrounding { GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"test" transformers:nil target:kGDTCORTargetTest]; @@ -105,10 +108,8 @@ - (void)DISABLED_testBackgrounding { }, 5.0); - // TODO(#3973): This notification no longer triggers the `isRunningInBackground` flag. Find - // another way to test it. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; - [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; + [notifCenter postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil]; XCTAssertTrue([GDTCORApplication sharedApplication].isRunningInBackground); GDTCORWaitForBlock( @@ -120,7 +121,7 @@ - (void)DISABLED_testBackgrounding { } /** Tests that the library deserializes itself from disk when the app foregrounds. */ -- (void)DISABLED_testForegrounding { +- (void)testForegrounding { GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"test" transformers:nil target:kGDTCORTargetTest]; @@ -134,10 +135,8 @@ - (void)DISABLED_testForegrounding { }, 5.0); - // TODO(#3973): This notification no longer triggers the `isRunningInBackground` flag. Find - // another way to test it. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; - [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; + [notifCenter postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil]; GDTCORWaitForBlock( ^BOOL { @@ -146,10 +145,8 @@ - (void)DISABLED_testForegrounding { }, 5.0); - // TODO(#3973): This notification no longer triggers the `isRunningInBackground` flag. Find - // another way to test it. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; - [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil]; + [notifCenter postNotificationName:UIApplicationWillEnterForegroundNotification object:nil]; XCTAssertFalse([GDTCORApplication sharedApplication].isRunningInBackground); GDTCORWaitForBlock( ^BOOL { @@ -157,6 +154,7 @@ - (void)DISABLED_testForegrounding { }, 5.0); } +#endif // #if TARGET_OS_IOS || TARGET_OS_TV /** Tests that the library gracefully stops doing stuff when terminating. */ - (void)testTermination { diff --git a/GoogleDataTransportCCTSupport/GDTCCTTests/Integration/GDTCCTIntegrationTest.m b/GoogleDataTransportCCTSupport/GDTCCTTests/Integration/GDTCCTIntegrationTest.m index a6d20a2530d..08d0777859c 100644 --- a/GoogleDataTransportCCTSupport/GDTCCTTests/Integration/GDTCCTIntegrationTest.m +++ b/GoogleDataTransportCCTSupport/GDTCCTTests/Integration/GDTCCTIntegrationTest.m @@ -157,7 +157,11 @@ - (void)testRunsWithoutCrashing { } eventsSent += eventsUploaded.integerValue; - if (eventsSent == self.totalEventsGenerated) { + NSLog(@"Single upload event of %ld, combined for %ld/%ld total expected.", + (long)eventsUploaded.integerValue, (long)eventsSent, + (long)self.totalEventsGenerated); + // Only fulfill the expectation once event generation is done and the numbers match. + if (self.generateEvents == NO && eventsSent == self.totalEventsGenerated) { [eventCountsMatchExpectation fulfill]; } }];