GDTCORPlatform.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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 <GoogleDataTransport/GDTCORConsoleLogger.h>
  19. #import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
  20. #ifdef GDTCOR_VERSION
  21. #define STR(x) STR_EXPAND(x)
  22. #define STR_EXPAND(x) #x
  23. NSString *const kGDTCORVersion = @STR(GDTCOR_VERSION);
  24. #else
  25. NSString *const kGDTCORVersion = @"Unknown";
  26. #endif // GDTCOR_VERSION
  27. const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0;
  28. NSString *const kGDTCORApplicationDidEnterBackgroundNotification =
  29. @"GDTCORApplicationDidEnterBackgroundNotification";
  30. NSString *const kGDTCORApplicationWillEnterForegroundNotification =
  31. @"GDTCORApplicationWillEnterForegroundNotification";
  32. NSString *const kGDTCORApplicationWillTerminateNotification =
  33. @"GDTCORApplicationWillTerminateNotification";
  34. #if !TARGET_OS_WATCH
  35. BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
  36. #if TARGET_OS_IOS
  37. return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN;
  38. #else
  39. return NO;
  40. #endif // TARGET_OS_IOS
  41. }
  42. #endif // !TARGET_OS_WATCH
  43. @interface GDTCORApplication ()
  44. /**
  45. Private flag to match the existing `readonly` public flag. This will be accurate for all platforms,
  46. since we handle each platform's lifecycle notifications separately.
  47. */
  48. @property(atomic, readwrite) BOOL isRunningInBackground;
  49. @end
  50. @implementation GDTCORApplication
  51. + (void)load {
  52. GDTCORLogDebug(
  53. "%@", @"GDT is initializing. Please note that if you quit the app via the "
  54. "debugger and not through a lifecycle event, event data will remain on disk but "
  55. "storage won't have a reference to them since the singleton wasn't saved to disk.");
  56. #if TARGET_OS_IOS || TARGET_OS_TV
  57. // If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues.
  58. GDTCORFatalAssert(
  59. GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid,
  60. @"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same.");
  61. #endif
  62. [self sharedApplication];
  63. }
  64. + (nullable GDTCORApplication *)sharedApplication {
  65. static GDTCORApplication *application;
  66. static dispatch_once_t onceToken;
  67. dispatch_once(&onceToken, ^{
  68. application = [[GDTCORApplication alloc] init];
  69. });
  70. return application;
  71. }
  72. - (instancetype)init {
  73. self = [super init];
  74. if (self) {
  75. // This class will be instantiated in the foreground.
  76. _isRunningInBackground = NO;
  77. #if TARGET_OS_IOS || TARGET_OS_TV
  78. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  79. [notificationCenter addObserver:self
  80. selector:@selector(iOSApplicationDidEnterBackground:)
  81. name:UIApplicationDidEnterBackgroundNotification
  82. object:nil];
  83. [notificationCenter addObserver:self
  84. selector:@selector(iOSApplicationWillEnterForeground:)
  85. name:UIApplicationWillEnterForegroundNotification
  86. object:nil];
  87. NSString *name = UIApplicationWillTerminateNotification;
  88. [notificationCenter addObserver:self
  89. selector:@selector(iOSApplicationWillTerminate:)
  90. name:name
  91. object:nil];
  92. #if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
  93. if (@available(iOS 13, tvOS 13.0, *)) {
  94. [notificationCenter addObserver:self
  95. selector:@selector(iOSApplicationWillEnterForeground:)
  96. name:UISceneWillEnterForegroundNotification
  97. object:nil];
  98. [notificationCenter addObserver:self
  99. selector:@selector(iOSApplicationDidEnterBackground:)
  100. name:UISceneWillDeactivateNotification
  101. object:nil];
  102. }
  103. #endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
  104. #elif TARGET_OS_OSX
  105. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  106. [notificationCenter addObserver:self
  107. selector:@selector(macOSApplicationWillTerminate:)
  108. name:NSApplicationWillTerminateNotification
  109. object:nil];
  110. #endif // TARGET_OS_IOS || TARGET_OS_TV
  111. }
  112. return self;
  113. }
  114. - (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name
  115. expirationHandler:(void (^)(void))handler {
  116. GDTCORBackgroundIdentifier bgID =
  117. [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name
  118. expirationHandler:handler];
  119. #if !NDEBUG
  120. if (bgID != GDTCORBackgroundIdentifierInvalid) {
  121. GDTCORLogDebug("Creating background task with name:%@ bgID:%ld", name, (long)bgID);
  122. }
  123. #endif // !NDEBUG
  124. return bgID;
  125. }
  126. - (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID {
  127. if (bgID != GDTCORBackgroundIdentifierInvalid) {
  128. GDTCORLogDebug("Ending background task with ID:%ld was successful", (long)bgID);
  129. [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID];
  130. return;
  131. }
  132. }
  133. #pragma mark - App environment helpers
  134. - (BOOL)isAppExtension {
  135. #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
  136. BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
  137. return appExtension;
  138. #elif TARGET_OS_OSX
  139. return NO;
  140. #endif
  141. }
  142. /** Returns a UIApplication instance if on the appropriate platform.
  143. *
  144. * @return The shared UIApplication if on the appropriate platform.
  145. */
  146. #if TARGET_OS_IOS || TARGET_OS_TV
  147. - (nullable UIApplication *)sharedApplicationForBackgroundTask {
  148. #else
  149. - (nullable id)sharedApplicationForBackgroundTask {
  150. #endif
  151. if ([self isAppExtension]) {
  152. return nil;
  153. }
  154. id sharedApplication = nil;
  155. Class uiApplicationClass = NSClassFromString(@"UIApplication");
  156. if (uiApplicationClass &&
  157. [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) {
  158. sharedApplication = [uiApplicationClass sharedApplication];
  159. }
  160. return sharedApplication;
  161. }
  162. #pragma mark - UIApplicationDelegate
  163. #if TARGET_OS_IOS || TARGET_OS_TV
  164. - (void)iOSApplicationDidEnterBackground:(NSNotification *)notif {
  165. _isRunningInBackground = YES;
  166. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  167. GDTCORLogDebug("%@", @"GDTCORPlatform is sending a notif that the app is backgrounding.");
  168. [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil];
  169. }
  170. - (void)iOSApplicationWillEnterForeground:(NSNotification *)notif {
  171. _isRunningInBackground = NO;
  172. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  173. GDTCORLogDebug("%@", @"GDTCORPlatform is sending a notif that the app is foregrounding.");
  174. [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil];
  175. }
  176. - (void)iOSApplicationWillTerminate:(NSNotification *)notif {
  177. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  178. GDTCORLogDebug("%@", @"GDTCORPlatform is sending a notif that the app is terminating.");
  179. [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
  180. }
  181. #endif // TARGET_OS_IOS || TARGET_OS_TV
  182. #pragma mark - NSApplicationDelegate
  183. #if TARGET_OS_OSX
  184. - (void)macOSApplicationWillTerminate:(NSNotification *)notif {
  185. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  186. GDTCORLogDebug("%@", @"GDTCORPlatform is sending a notif that the app is terminating.");
  187. [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
  188. }
  189. #endif // TARGET_OS_OSX
  190. @end