GDTCORPlatform.m 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Copyright 2019 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <GoogleDataTransport/GDTCORPlatform.h>
  17. #import <GoogleDataTransport/GDTCORAssert.h>
  18. #import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
  19. #ifdef GDTCOR_VERSION
  20. #define STR(x) STR_EXPAND(x)
  21. #define STR_EXPAND(x) #x
  22. NSString *const kGDTCORVersion = @STR(GDTCOR_VERSION);
  23. #else
  24. NSString *const kGDTCORVersion = @"Unknown";
  25. #endif // GDTCOR_VERSION
  26. const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0;
  27. NSString *const kGDTCORApplicationDidEnterBackgroundNotification =
  28. @"GDTCORApplicationDidEnterBackgroundNotification";
  29. NSString *const kGDTCORApplicationWillEnterForegroundNotification =
  30. @"GDTCORApplicationWillEnterForegroundNotification";
  31. NSString *const kGDTCORApplicationWillTerminateNotification =
  32. @"GDTCORApplicationWillTerminateNotification";
  33. #if !TARGET_OS_WATCH
  34. BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
  35. #if TARGET_OS_IOS
  36. return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN;
  37. #else
  38. return NO;
  39. #endif // TARGET_OS_IOS
  40. }
  41. #endif // !TARGET_OS_WATCH
  42. @interface GDTCORApplication ()
  43. /**
  44. Private flag to match the existing `readonly` public flag. This will be accurate for all platforms,
  45. since we handle each platform's lifecycle notifications separately.
  46. */
  47. @property(atomic, readwrite) BOOL isRunningInBackground;
  48. @end
  49. @implementation GDTCORApplication
  50. + (void)load {
  51. #if TARGET_OS_IOS || TARGET_OS_TV
  52. // If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues.
  53. GDTCORFatalAssert(
  54. GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid,
  55. @"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same.");
  56. #endif
  57. [self sharedApplication];
  58. }
  59. + (nullable GDTCORApplication *)sharedApplication {
  60. static GDTCORApplication *application;
  61. static dispatch_once_t onceToken;
  62. dispatch_once(&onceToken, ^{
  63. application = [[GDTCORApplication alloc] init];
  64. });
  65. return application;
  66. }
  67. - (instancetype)init {
  68. self = [super init];
  69. if (self) {
  70. // This class will be instantiated in the foreground.
  71. _isRunningInBackground = NO;
  72. #if TARGET_OS_IOS || TARGET_OS_TV
  73. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  74. [notificationCenter addObserver:self
  75. selector:@selector(iOSApplicationDidEnterBackground:)
  76. name:UIApplicationDidEnterBackgroundNotification
  77. object:nil];
  78. [notificationCenter addObserver:self
  79. selector:@selector(iOSApplicationWillEnterForeground:)
  80. name:UIApplicationWillEnterForegroundNotification
  81. object:nil];
  82. NSString *name = UIApplicationWillTerminateNotification;
  83. [notificationCenter addObserver:self
  84. selector:@selector(iOSApplicationWillTerminate:)
  85. name:name
  86. object:nil];
  87. #if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
  88. if (@available(iOS 13, tvOS 13.0, *)) {
  89. [notificationCenter addObserver:self
  90. selector:@selector(iOSApplicationWillEnterForeground:)
  91. name:UISceneWillEnterForegroundNotification
  92. object:nil];
  93. [notificationCenter addObserver:self
  94. selector:@selector(iOSApplicationDidEnterBackground:)
  95. name:UISceneWillDeactivateNotification
  96. object:nil];
  97. }
  98. #endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
  99. #elif TARGET_OS_OSX
  100. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  101. [notificationCenter addObserver:self
  102. selector:@selector(macOSApplicationWillTerminate:)
  103. name:NSApplicationWillTerminateNotification
  104. object:nil];
  105. #endif // TARGET_OS_IOS || TARGET_OS_TV
  106. }
  107. return self;
  108. }
  109. - (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name
  110. expirationHandler:(void (^)(void))handler {
  111. return [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name
  112. expirationHandler:handler];
  113. }
  114. - (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID {
  115. if (bgID != GDTCORBackgroundIdentifierInvalid) {
  116. [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID];
  117. }
  118. }
  119. #pragma mark - App environment helpers
  120. - (BOOL)isAppExtension {
  121. #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
  122. BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
  123. return appExtension;
  124. #elif TARGET_OS_OSX
  125. return NO;
  126. #endif
  127. }
  128. /** Returns a UIApplication instance if on the appropriate platform.
  129. *
  130. * @return The shared UIApplication if on the appropriate platform.
  131. */
  132. #if TARGET_OS_IOS || TARGET_OS_TV
  133. - (nullable UIApplication *)sharedApplicationForBackgroundTask {
  134. #else
  135. - (nullable id)sharedApplicationForBackgroundTask {
  136. #endif
  137. if ([self isAppExtension]) {
  138. return nil;
  139. }
  140. id sharedApplication = nil;
  141. Class uiApplicationClass = NSClassFromString(@"UIApplication");
  142. if (uiApplicationClass &&
  143. [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) {
  144. sharedApplication = [uiApplicationClass sharedApplication];
  145. }
  146. return sharedApplication;
  147. }
  148. #pragma mark - UIApplicationDelegate
  149. #if TARGET_OS_IOS || TARGET_OS_TV
  150. - (void)iOSApplicationDidEnterBackground:(NSNotification *)notif {
  151. _isRunningInBackground = YES;
  152. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  153. [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil];
  154. }
  155. - (void)iOSApplicationWillEnterForeground:(NSNotification *)notif {
  156. _isRunningInBackground = NO;
  157. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  158. [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil];
  159. }
  160. - (void)iOSApplicationWillTerminate:(NSNotification *)notif {
  161. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  162. [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
  163. }
  164. #endif // TARGET_OS_IOS || TARGET_OS_TV
  165. #pragma mark - NSApplicationDelegate
  166. #if TARGET_OS_OSX
  167. - (void)macOSApplicationWillTerminate:(NSNotification *)notif {
  168. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  169. [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
  170. }
  171. #endif // TARGET_OS_OSX
  172. @end