/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.m

http://github.com/facebook/facebook-ios-sdk · Objective C · 443 lines · 344 code · 68 blank · 31 comment · 43 complexity · 178694181cc51460fe79656345034616 MD5 · raw file

  1. // Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  2. //
  3. // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
  4. // copy, modify, and distribute this software in source code or binary form for use
  5. // in connection with the web services and APIs provided by Facebook.
  6. //
  7. // As with any software that integrates with the Facebook platform, your use of
  8. // this software is subject to the Facebook Developer Principles and Policies
  9. // [http://developers.facebook.com/policy/]. This copyright notice shall be
  10. // included in all copies or substantial portions of the software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #import "FBSDKApplicationDelegate.h"
  19. #import "FBSDKApplicationDelegate+Internal.h"
  20. #import <objc/runtime.h>
  21. #import "FBSDKAppEvents+Internal.h"
  22. #import "FBSDKConstants.h"
  23. #import "FBSDKDynamicFrameworkLoader.h"
  24. #import "FBSDKError.h"
  25. #import "FBSDKEventDeactivationManager.h"
  26. #import "FBSDKFeatureManager.h"
  27. #import "FBSDKGateKeeperManager.h"
  28. #import "FBSDKInstrumentManager.h"
  29. #import "FBSDKInternalUtility.h"
  30. #import "FBSDKLogger.h"
  31. #import "FBSDKServerConfiguration.h"
  32. #import "FBSDKServerConfigurationManager.h"
  33. #import "FBSDKSettings+Internal.h"
  34. #import "FBSDKTimeSpentData.h"
  35. #if !TARGET_OS_TV
  36. #import "FBSDKMeasurementEventListener.h"
  37. #import "FBSDKContainerViewController.h"
  38. #import "FBSDKProfile+Internal.h"
  39. #endif
  40. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  41. NSNotificationName const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
  42. #else
  43. NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
  44. #endif
  45. static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
  46. static NSString *const FBSDKKitsBitmaskKey = @"com.facebook.sdk.kits.bitmask";
  47. static BOOL g_isSDKInitialized = NO;
  48. static UIApplicationState _applicationState;
  49. @implementation FBSDKApplicationDelegate
  50. {
  51. NSHashTable<id<FBSDKApplicationObserving>> *_applicationObservers;
  52. BOOL _isAppLaunched;
  53. }
  54. #pragma mark - Class Methods
  55. + (void)load
  56. {
  57. if ([FBSDKSettings isAutoInitEnabled]) {
  58. // when the app becomes active by any means, kick off the initialization.
  59. [[NSNotificationCenter defaultCenter] addObserver:self
  60. selector:@selector(initializeWithLaunchData:)
  61. name:UIApplicationDidFinishLaunchingNotification
  62. object:nil];
  63. }
  64. }
  65. // Initialize SDK listeners
  66. // Don't call this function in any place else. It should only be called when the class is loaded.
  67. + (void)initializeWithLaunchData:(NSNotification *)note
  68. {
  69. [self initializeSDK:note.userInfo];
  70. // Remove the observer
  71. [[NSNotificationCenter defaultCenter] removeObserver:self
  72. name:UIApplicationDidFinishLaunchingNotification
  73. object:nil];
  74. }
  75. + (void)initializeSDK:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions
  76. {
  77. if (g_isSDKInitialized) {
  78. // Do nothing if initialized already
  79. return;
  80. }
  81. g_isSDKInitialized = YES;
  82. FBSDKApplicationDelegate *delegate = [self sharedInstance];
  83. NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
  84. [defaultCenter addObserver:delegate selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
  85. [defaultCenter addObserver:delegate selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
  86. [[FBSDKAppEvents singleton] registerNotifications];
  87. [delegate application:[UIApplication sharedApplication] didFinishLaunchingWithOptions:launchOptions];
  88. [FBSDKFeatureManager checkFeature:FBSDKFeatureInstrument completionBlock:^(BOOL enabled) {
  89. if (enabled) {
  90. [FBSDKInstrumentManager enable];
  91. }
  92. }];
  93. [FBSDKFeatureManager checkFeature:FBSDKFeatureRestrictiveDataFiltering completionBlock:^(BOOL enabled) {
  94. if (enabled) {
  95. [FBSDKRestrictiveDataFilterManager enable];
  96. }
  97. }];
  98. [FBSDKFeatureManager checkFeature:FBSDKFeatureEventDeactivation completionBlock:^(BOOL enabled) {
  99. if (enabled) {
  100. [FBSDKEventDeactivationManager enable];
  101. }
  102. }];
  103. [FBSDKFeatureManager checkFeature:FBSDKFeatureMonitoring completionBlock:^(BOOL enabled) {
  104. if (enabled && FBSDKSettings.isAutoLogAppEventsEnabled) {
  105. #ifndef DEBUG
  106. [FBSDKMonitor enable];
  107. #endif
  108. }
  109. }];
  110. #if !TARGET_OS_TV
  111. // Register Listener for App Link measurement events
  112. [FBSDKMeasurementEventListener defaultListener];
  113. [delegate _logIfAutoAppLinkEnabled];
  114. #endif
  115. // Set the SourceApplication for time spent data. This is not going to update the value if the app has already launched.
  116. [FBSDKTimeSpentData setSourceApplication:launchOptions[UIApplicationLaunchOptionsSourceApplicationKey]
  117. openURL:launchOptions[UIApplicationLaunchOptionsURLKey]];
  118. // Register on UIApplicationDidEnterBackgroundNotification events to reset source application data when app backgrounds.
  119. [FBSDKTimeSpentData registerAutoResetSourceApplication];
  120. [FBSDKInternalUtility validateFacebookReservedURLSchemes];
  121. }
  122. + (FBSDKApplicationDelegate *)sharedInstance
  123. {
  124. static FBSDKApplicationDelegate *_sharedInstance;
  125. static dispatch_once_t onceToken;
  126. dispatch_once(&onceToken, ^{
  127. _sharedInstance = [[self alloc] init];
  128. });
  129. return _sharedInstance;
  130. }
  131. #pragma mark - Object Lifecycle
  132. - (instancetype)init
  133. {
  134. if ((self = [super init]) != nil) {
  135. _applicationObservers = [[NSHashTable alloc] init];
  136. }
  137. return self;
  138. }
  139. - (void)dealloc
  140. {
  141. [[NSNotificationCenter defaultCenter] removeObserver:self];
  142. }
  143. #pragma mark - UIApplicationDelegate
  144. #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_9_0
  145. - (BOOL)application:(UIApplication *)application
  146. openURL:(NSURL *)url
  147. options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
  148. {
  149. if (@available(iOS 9.0, *)) {
  150. return [self application:application
  151. openURL:url
  152. sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
  153. annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
  154. }
  155. return NO;
  156. }
  157. #endif
  158. - (BOOL)application:(UIApplication *)application
  159. openURL:(NSURL *)url
  160. sourceApplication:(NSString *)sourceApplication
  161. annotation:(id)annotation
  162. {
  163. if (sourceApplication != nil && ![sourceApplication isKindOfClass:[NSString class]]) {
  164. @throw [NSException exceptionWithName:NSInvalidArgumentException
  165. reason:@"Expected 'sourceApplication' to be NSString. Please verify you are passing in 'sourceApplication' from your app delegate (not the UIApplication* parameter). If your app delegate implements iOS 9's application:openURL:options:, you should pass in options[UIApplicationOpenURLOptionsSourceApplicationKey]. "
  166. userInfo:nil];
  167. }
  168. [FBSDKTimeSpentData setSourceApplication:sourceApplication openURL:url];
  169. BOOL handled = NO;
  170. NSArray<id<FBSDKApplicationObserving>> *observers = [_applicationObservers allObjects];
  171. for (id<FBSDKApplicationObserving> observer in observers) {
  172. if ([observer respondsToSelector:@selector(application:openURL:sourceApplication:annotation:)]) {
  173. if ([observer application:application
  174. openURL:url
  175. sourceApplication:sourceApplication
  176. annotation:annotation]) {
  177. handled = YES;
  178. }
  179. }
  180. }
  181. if (handled) {
  182. return YES;
  183. }
  184. [self _logIfAppLinkEvent:url];
  185. return NO;
  186. }
  187. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  188. {
  189. if ([self isAppLaunched]) {
  190. return NO;
  191. }
  192. _isAppLaunched = YES;
  193. FBSDKAccessToken *cachedToken = [FBSDKSettings accessTokenCache].accessToken;
  194. [FBSDKAccessToken setCurrentAccessToken:cachedToken];
  195. // fetch app settings
  196. [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL];
  197. if (FBSDKSettings.isAutoLogAppEventsEnabled) {
  198. [self _logSDKInitialize];
  199. }
  200. #if !TARGET_OS_TV
  201. FBSDKProfile *cachedProfile = [FBSDKProfile fetchCachedProfile];
  202. [FBSDKProfile setCurrentProfile:cachedProfile];
  203. #endif
  204. NSArray<id<FBSDKApplicationObserving>> *observers = [_applicationObservers allObjects];
  205. BOOL handled = NO;
  206. for (id<FBSDKApplicationObserving> observer in observers) {
  207. if ([observer respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]) {
  208. if ([observer application:application didFinishLaunchingWithOptions:launchOptions]) {
  209. handled = YES;
  210. }
  211. }
  212. }
  213. return handled;
  214. }
  215. - (void)applicationDidEnterBackground:(NSNotification *)notification
  216. {
  217. _applicationState = UIApplicationStateBackground;
  218. NSArray<id<FBSDKApplicationObserving>> *observers = [_applicationObservers allObjects];
  219. for (id<FBSDKApplicationObserving> observer in observers) {
  220. if ([observer respondsToSelector:@selector(applicationDidEnterBackground:)]) {
  221. [observer applicationDidEnterBackground:notification.object];
  222. }
  223. }
  224. }
  225. - (void)applicationDidBecomeActive:(NSNotification *)notification
  226. {
  227. _applicationState = UIApplicationStateActive;
  228. // Auto log basic events in case autoLogAppEventsEnabled is set
  229. if (FBSDKSettings.isAutoLogAppEventsEnabled) {
  230. [FBSDKAppEvents activateApp];
  231. }
  232. NSArray<id<FBSDKApplicationObserving>> *observers = [_applicationObservers copy];
  233. for (id<FBSDKApplicationObserving> observer in observers) {
  234. if ([observer respondsToSelector:@selector(applicationDidBecomeActive:)]) {
  235. [observer applicationDidBecomeActive:notification.object];
  236. }
  237. }
  238. }
  239. #pragma mark - Internal Methods
  240. #pragma mark - FBSDKApplicationObserving
  241. - (void)addObserver:(id<FBSDKApplicationObserving>)observer
  242. {
  243. if (![_applicationObservers containsObject:observer]) {
  244. [_applicationObservers addObject:observer];
  245. }
  246. }
  247. - (void)removeObserver:(id<FBSDKApplicationObserving>)observer
  248. {
  249. if ([_applicationObservers containsObject:observer]) {
  250. [_applicationObservers removeObject:observer];
  251. }
  252. }
  253. + (UIApplicationState)applicationState
  254. {
  255. return _applicationState;
  256. }
  257. #pragma mark - Helper Methods
  258. - (void)_logIfAppLinkEvent:(NSURL *)url
  259. {
  260. if (!url) {
  261. return;
  262. }
  263. NSDictionary<NSString *, NSString *> *params = [FBSDKBasicUtility dictionaryWithQueryString:url.query];
  264. NSString *applinkDataString = params[@"al_applink_data"];
  265. if (!applinkDataString) {
  266. return;
  267. }
  268. NSDictionary<id, id> *applinkData = [FBSDKBasicUtility objectForJSONString:applinkDataString error:NULL];
  269. if (!applinkData) {
  270. return;
  271. }
  272. NSString *targetURLString = applinkData[@"target_url"];
  273. NSURL *targetURL = [targetURLString isKindOfClass:[NSString class]] ? [NSURL URLWithString:targetURLString] : nil;
  274. NSMutableDictionary *logData = [[NSMutableDictionary alloc] init];
  275. [FBSDKBasicUtility dictionary:logData setObject:targetURL.absoluteString forKey:@"targetURL"];
  276. [FBSDKBasicUtility dictionary:logData setObject:targetURL.host forKey:@"targetURLHost"];
  277. NSDictionary *refererData = applinkData[@"referer_data"];
  278. if (refererData) {
  279. [FBSDKBasicUtility dictionary:logData setObject:refererData[@"target_url"] forKey:@"referralTargetURL"];
  280. [FBSDKBasicUtility dictionary:logData setObject:refererData[@"url"] forKey:@"referralURL"];
  281. [FBSDKBasicUtility dictionary:logData setObject:refererData[@"app_name"] forKey:@"referralAppName"];
  282. }
  283. [FBSDKBasicUtility dictionary:logData setObject:url.absoluteString forKey:@"inputURL"];
  284. [FBSDKBasicUtility dictionary:logData setObject:url.scheme forKey:@"inputURLScheme"];
  285. [FBSDKAppEvents logInternalEvent:FBSDKAppLinkInboundEvent
  286. parameters:logData
  287. isImplicitlyLogged:YES];
  288. }
  289. - (void)_logSDKInitialize
  290. {
  291. NSDictionary *metaInfo = [NSDictionary dictionaryWithObjects:@[@"login_lib_included",
  292. @"marketing_lib_included",
  293. @"messenger_lib_included",
  294. @"places_lib_included",
  295. @"share_lib_included",
  296. @"tv_lib_included"]
  297. forKeys:@[@"FBSDKLoginManager",
  298. @"FBSDKAutoLog",
  299. @"FBSDKMessengerButton",
  300. @"FBSDKPlacesManager",
  301. @"FBSDKShareDialog",
  302. @"FBSDKTVInterfaceFactory"]];
  303. NSInteger bitmask = 0;
  304. NSInteger bit = 0;
  305. NSMutableDictionary<NSString *, NSNumber *> *params = NSMutableDictionary.new;
  306. params[@"core_lib_included"] = @1;
  307. for (NSString *className in metaInfo.allKeys) {
  308. NSString *keyName = [metaInfo objectForKey:className];
  309. if (objc_lookUpClass([className UTF8String])) {
  310. params[keyName] = @1;
  311. bitmask |= 1 << bit;
  312. }
  313. bit++;
  314. }
  315. [self _logSwiftRuntimeAvailability];
  316. NSInteger existingBitmask = [[NSUserDefaults standardUserDefaults] integerForKey:FBSDKKitsBitmaskKey];
  317. if (existingBitmask != bitmask) {
  318. [[NSUserDefaults standardUserDefaults] setInteger:bitmask forKey:FBSDKKitsBitmaskKey];
  319. [FBSDKAppEvents logInternalEvent:@"fb_sdk_initialize"
  320. parameters:params
  321. isImplicitlyLogged:NO];
  322. }
  323. }
  324. - (void)_logIfAutoAppLinkEnabled
  325. {
  326. #if !TARGET_OS_TV
  327. NSNumber *enabled = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FBSDKAutoAppLinkEnabled"];
  328. if (enabled.boolValue) {
  329. NSMutableDictionary<NSString *, NSString *> *params = [[NSMutableDictionary alloc] init];
  330. if (![FBSDKAppLinkUtility isMatchURLScheme:[NSString stringWithFormat:@"fb%@", [FBSDKSettings appID]]]) {
  331. NSString *warning = @"You haven't set the Auto App Link URL scheme: fb<YOUR APP ID>";
  332. params[@"SchemeWarning"] = warning;
  333. NSLog(@"%@", warning);
  334. }
  335. [FBSDKAppEvents logInternalEvent:@"fb_auto_applink" parameters:params isImplicitlyLogged:YES];
  336. }
  337. #endif
  338. }
  339. - (void)_logSwiftRuntimeAvailability
  340. {
  341. NSString *swiftUsageKey = @"is_using_swift";
  342. NSString *eventName = @"fb_sdk_swift_runtime_check";
  343. NSMutableDictionary<NSString *, NSNumber *> *params = NSMutableDictionary.new;
  344. // Tracking if the consuming Application is using Swift
  345. id delegate = [UIApplication sharedApplication].delegate;
  346. NSString const *className = NSStringFromClass([delegate class]);
  347. if ([className componentsSeparatedByString:@"."].count > 1) {
  348. params[swiftUsageKey] = @YES;
  349. }
  350. // Additional check to see if the consuming application perhaps was
  351. // originally an objc project but is now using Swift
  352. if (!params[swiftUsageKey].boolValue) {
  353. double delayInSeconds = 1.0;
  354. dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  355. dispatch_after(delay, dispatch_get_main_queue(), ^{
  356. UIViewController *topMostViewController = [FBSDKInternalUtility topMostViewController];
  357. NSString const *vcClassName = NSStringFromClass([topMostViewController class]);
  358. if ([vcClassName componentsSeparatedByString:@"."].count > 1) {
  359. params[swiftUsageKey] = @YES;
  360. [FBSDKAppEvents logInternalEvent:eventName
  361. parameters:params
  362. isImplicitlyLogged:NO];
  363. }
  364. });
  365. };
  366. }
  367. + (BOOL)isSDKInitialized
  368. {
  369. return [FBSDKSettings isAutoInitEnabled] || g_isSDKInitialized;
  370. }
  371. // Wrapping this makes it mockable and enables testability
  372. - (BOOL)isAppLaunched {
  373. return _isAppLaunched;
  374. }
  375. @end