/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents.m

http://github.com/facebook/facebook-ios-sdk · Objective C · 1488 lines · 1193 code · 189 blank · 106 comment · 161 complexity · eb0ba228e2f4138314c4b940f35330a1 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 "FBSDKAppEvents.h"
  19. #import "FBSDKAppEvents+Internal.h"
  20. #import "FBSDKApplicationDelegate+Internal.h"
  21. #import <objc/runtime.h>
  22. #import <UIKit/UIApplication.h>
  23. #import "FBSDKAccessToken.h"
  24. #import "FBSDKAppEventsState.h"
  25. #import "FBSDKAppEventsStateManager.h"
  26. #import "FBSDKAppEventsUtility.h"
  27. #import "FBSDKConstants.h"
  28. #import "FBSDKDynamicFrameworkLoader.h"
  29. #import "FBSDKError.h"
  30. #import "FBSDKEventDeactivationManager.h"
  31. #import "FBSDKFeatureManager.h"
  32. #import "FBSDKGraphRequest+Internal.h"
  33. #import "FBSDKInternalUtility.h"
  34. #import "FBSDKLogger.h"
  35. #import "FBSDKRestrictiveDataFilterManager.h"
  36. #import "FBSDKPaymentObserver.h"
  37. #import "FBSDKServerConfiguration.h"
  38. #import "FBSDKServerConfigurationManager.h"
  39. #import "FBSDKSettings.h"
  40. #import "FBSDKTimeSpentData.h"
  41. #import "FBSDKUtility.h"
  42. #import "FBSDKUserDataStore.h"
  43. #if !TARGET_OS_TV
  44. #import "FBSDKIntegrityManager.h"
  45. #import "FBSDKEventBindingManager.h"
  46. #import "FBSDKHybridAppEventsScriptMessageHandler.h"
  47. #import "FBSDKModelManager.h"
  48. #endif
  49. //
  50. // Public event names
  51. //
  52. // General purpose
  53. FBSDKAppEventName FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration";
  54. FBSDKAppEventName FBSDKAppEventNameViewedContent = @"fb_mobile_content_view";
  55. FBSDKAppEventName FBSDKAppEventNameSearched = @"fb_mobile_search";
  56. FBSDKAppEventName FBSDKAppEventNameRated = @"fb_mobile_rate";
  57. FBSDKAppEventName FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion";
  58. FBSDKAppEventName FBSDKAppEventNameContact = @"Contact";
  59. FBSDKAppEventName FBSDKAppEventNameCustomizeProduct = @"CustomizeProduct";
  60. FBSDKAppEventName FBSDKAppEventNameDonate = @"Donate";
  61. FBSDKAppEventName FBSDKAppEventNameFindLocation = @"FindLocation";
  62. FBSDKAppEventName FBSDKAppEventNameSchedule = @"Schedule";
  63. FBSDKAppEventName FBSDKAppEventNameStartTrial = @"StartTrial";
  64. FBSDKAppEventName FBSDKAppEventNameSubmitApplication = @"SubmitApplication";
  65. FBSDKAppEventName FBSDKAppEventNameSubscribe = @"Subscribe";
  66. FBSDKAppEventName FBSDKAppEventNameSubscriptionHeartbeat = @"SubscriptionHeartbeat";
  67. FBSDKAppEventName FBSDKAppEventNameAdImpression = @"AdImpression";
  68. FBSDKAppEventName FBSDKAppEventNameAdClick = @"AdClick";
  69. // Ecommerce related
  70. FBSDKAppEventName FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart";
  71. FBSDKAppEventName FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist";
  72. FBSDKAppEventName FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout";
  73. FBSDKAppEventName FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info";
  74. FBSDKAppEventName FBSDKAppEventNameProductCatalogUpdate = @"fb_mobile_catalog_update";
  75. FBSDKAppEventName FBSDKAppEventNamePurchased = @"fb_mobile_purchase";
  76. // Gaming related
  77. FBSDKAppEventName FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved";
  78. FBSDKAppEventName FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked";
  79. FBSDKAppEventName FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits";
  80. //
  81. // Public event parameter names
  82. //
  83. FBSDKAppEventParameterName FBSDKAppEventParameterNameCurrency = @"fb_currency";
  84. FBSDKAppEventParameterName FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method";
  85. FBSDKAppEventParameterName FBSDKAppEventParameterNameContentType = @"fb_content_type";
  86. FBSDKAppEventParameterName FBSDKAppEventParameterNameContent = @"fb_content";
  87. FBSDKAppEventParameterName FBSDKAppEventParameterNameContentID = @"fb_content_id";
  88. FBSDKAppEventParameterName FBSDKAppEventParameterNameSearchString = @"fb_search_string";
  89. FBSDKAppEventParameterName FBSDKAppEventParameterNameSuccess = @"fb_success";
  90. FBSDKAppEventParameterName FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value";
  91. FBSDKAppEventParameterName FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available";
  92. FBSDKAppEventParameterName FBSDKAppEventParameterNameNumItems = @"fb_num_items";
  93. FBSDKAppEventParameterName FBSDKAppEventParameterNameLevel = @"fb_level";
  94. FBSDKAppEventParameterName FBSDKAppEventParameterNameDescription = @"fb_description";
  95. FBSDKAppEventParameterName FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
  96. FBSDKAppEventParameterName FBSDKAppEventParameterNameAdType = @"ad_type";
  97. FBSDKAppEventParameterName FBSDKAppEventParameterNameOrderID = @"fb_order_id";
  98. //
  99. // Public event parameter names for DPA Catalog
  100. //
  101. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel0 = @"fb_product_custom_label_0";
  102. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel1 = @"fb_product_custom_label_1";
  103. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel2 = @"fb_product_custom_label_2";
  104. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel3 = @"fb_product_custom_label_3";
  105. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel4 = @"fb_product_custom_label_4";
  106. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCategory = @"fb_product_category";
  107. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSUrl = @"fb_product_applink_ios_url";
  108. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppStoreID = @"fb_product_applink_ios_app_store_id";
  109. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppName = @"fb_product_applink_ios_app_name";
  110. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneUrl = @"fb_product_applink_iphone_url";
  111. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID = @"fb_product_applink_iphone_app_store_id";
  112. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppName = @"fb_product_applink_iphone_app_name";
  113. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadUrl = @"fb_product_applink_ipad_url";
  114. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppStoreID = @"fb_product_applink_ipad_app_store_id";
  115. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppName = @"fb_product_applink_ipad_app_name";
  116. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidUrl = @"fb_product_applink_android_url";
  117. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidPackage = @"fb_product_applink_android_package";
  118. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidAppName = @"fb_product_applink_android_app_name";
  119. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl = @"fb_product_applink_windows_phone_url";
  120. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID = @"fb_product_applink_windows_phone_app_id";
  121. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName = @"fb_product_applink_windows_phone_app_name";
  122. //
  123. // Public event parameter values
  124. //
  125. FBSDKAppEventParameterValue FBSDKAppEventParameterValueNo = @"0";
  126. FBSDKAppEventParameterValue FBSDKAppEventParameterValueYes = @"1";
  127. //
  128. // Public event user data types
  129. //
  130. FBSDKAppEventUserDataType FBSDKAppEventEmail = @"em";
  131. FBSDKAppEventUserDataType FBSDKAppEventFirstName = @"fn";
  132. FBSDKAppEventUserDataType FBSDKAppEventLastName = @"ln";
  133. FBSDKAppEventUserDataType FBSDKAppEventPhone = @"ph";
  134. FBSDKAppEventUserDataType FBSDKAppEventDateOfBirth = @"dob";
  135. FBSDKAppEventUserDataType FBSDKAppEventGender = @"ge";
  136. FBSDKAppEventUserDataType FBSDKAppEventCity = @"ct";
  137. FBSDKAppEventUserDataType FBSDKAppEventState = @"st";
  138. FBSDKAppEventUserDataType FBSDKAppEventZip = @"zp";
  139. FBSDKAppEventUserDataType FBSDKAppEventCountry = @"country";
  140. //
  141. // Event names internal to this file
  142. //
  143. FBSDKAppEventName FBSDKAppEventNameLoginViewUsage = @"fb_login_view_usage";
  144. FBSDKAppEventName FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch";
  145. FBSDKAppEventName FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss";
  146. FBSDKAppEventName FBSDKAppEventNameShareTrayDidLaunch = @"fb_share_tray_did_launch";
  147. FBSDKAppEventName FBSDKAppEventNameShareTrayDidSelectActivity = @"fb_share_tray_did_select_activity";
  148. FBSDKAppEventName FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch";
  149. FBSDKAppEventName FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss";
  150. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share";
  151. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo";
  152. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og";
  153. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og";
  154. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message";
  155. FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo";
  156. FBSDKAppEventName FBSDKAppEventNameFBDialogsNativeLoginDialogStart = @"fb_dialogs_native_login_dialog_start";
  157. NSString *const FBSDKAppEventsNativeLoginDialogStartTime = @"fb_native_login_dialog_start_time";
  158. FBSDKAppEventName FBSDKAppEventNameFBDialogsNativeLoginDialogEnd = @"fb_dialogs_native_login_dialog_end";
  159. NSString *const FBSDKAppEventsNativeLoginDialogEndTime = @"fb_native_login_dialog_end_time";
  160. FBSDKAppEventName FBSDKAppEventNameFBDialogsWebLoginCompleted = @"fb_dialogs_web_login_dialog_complete";
  161. NSString *const FBSDKAppEventsWebLoginE2E = @"fb_web_login_e2e";
  162. FBSDKAppEventName FBSDKAppEventNameFBSessionAuthStart = @"fb_mobile_login_start";
  163. FBSDKAppEventName FBSDKAppEventNameFBSessionAuthEnd = @"fb_mobile_login_complete";
  164. FBSDKAppEventName FBSDKAppEventNameFBSessionAuthMethodStart = @"fb_mobile_login_method_start";
  165. FBSDKAppEventName FBSDKAppEventNameFBSessionAuthMethodEnd = @"fb_mobile_login_method_complete";
  166. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression";
  167. FBSDKAppEventName FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression";
  168. FBSDKAppEventName FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression";
  169. FBSDKAppEventName FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression";
  170. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonImpression = @"fb_live_streaming_button_impression";
  171. FBSDKAppEventName FBSDKAppEventNameFBSDKSmartLoginService = @"fb_smart_login_service";
  172. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap";
  173. FBSDKAppEventName FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap";
  174. FBSDKAppEventName FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap";
  175. FBSDKAppEventName FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap";
  176. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap = @"fb_live_streaming_button_did_tap";
  177. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable";
  178. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like";
  179. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidPresentDialog = @"fb_like_control_did_present_dialog";
  180. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidTap = @"fb_like_control_did_tap";
  181. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidUnlike = @"fb_like_control_did_unlike";
  182. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlError = @"fb_like_control_error";
  183. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlImpression = @"fb_like_control_impression";
  184. FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable = @"fb_like_control_network_unavailable";
  185. FBSDKAppEventName FBSDKAppEventNameFBSDKEventShareDialogResult = @"fb_dialog_share_result";
  186. FBSDKAppEventName FBSDKAppEventNameFBSDKEventMessengerShareDialogResult = @"fb_messenger_dialog_share_result";
  187. FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result";
  188. FBSDKAppEventName FBSDKAppEventNameFBSDKEventShareDialogShow = @"fb_dialog_share_show";
  189. FBSDKAppEventName FBSDKAppEventNameFBSDKEventMessengerShareDialogShow = @"fb_messenger_dialog_share_show";
  190. FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show";
  191. FBSDKAppEventName FBSDKAppEventNameFBSessionFASLoginDialogResult = @"fb_mobile_login_fas_dialog_result";
  192. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStart = @"fb_sdk_live_streaming_start";
  193. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStop = @"fb_sdk_live_streaming_stop";
  194. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingPause = @"fb_sdk_live_streaming_pause";
  195. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingResume = @"fb_sdk_live_streaming_resume";
  196. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingError = @"fb_sdk_live_streaming_error";
  197. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus = @"fb_sdk_live_streaming_update_status";
  198. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingVideoID = @"fb_sdk_live_streaming_video_id";
  199. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingMic = @"fb_sdk_live_streaming_mic";
  200. FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingCamera = @"fb_sdk_live_streaming_camera";
  201. // Event Parameters internal to this file
  202. NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome";
  203. NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message";
  204. NSString *const FBSDKAppEventParameterDialogMode = @"fb_dialog_mode";
  205. NSString *const FBSDKAppEventParameterDialogShareContentType = @"fb_dialog_share_content_type";
  206. NSString *const FBSDKAppEventParameterDialogShareContentUUID = @"fb_dialog_share_content_uuid";
  207. NSString *const FBSDKAppEventParameterDialogShareContentPageID = @"fb_dialog_share_content_page_id";
  208. NSString *const FBSDKAppEventParameterShareTrayActivityName = @"fb_share_tray_activity";
  209. NSString *const FBSDKAppEventParameterShareTrayResult = @"fb_share_tray_result";
  210. NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
  211. NSString *const FBSDKAppEventParameterEventName = @"_eventName";
  212. NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
  213. NSString *const FBSDKAppEventParameterInBackground = @"_inBackground";
  214. NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus = @"live_streaming_prev_status";
  215. NSString *const FBSDKAppEventParameterLiveStreamingStatus = @"live_streaming_status";
  216. NSString *const FBSDKAppEventParameterLiveStreamingError = @"live_streaming_error";
  217. NSString *const FBSDKAppEventParameterLiveStreamingVideoID = @"live_streaming_video_id";
  218. NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled = @"live_streaming_mic_enabled";
  219. NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled = @"live_streaming_camera_enabled";
  220. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductItemID = @"fb_product_item_id";
  221. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAvailability = @"fb_product_availability";
  222. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCondition = @"fb_product_condition";
  223. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductDescription = @"fb_product_description";
  224. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductImageLink = @"fb_product_image_link";
  225. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductLink = @"fb_product_link";
  226. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductTitle = @"fb_product_title";
  227. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductGTIN = @"fb_product_gtin";
  228. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductMPN = @"fb_product_mpn";
  229. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductBrand = @"fb_product_brand";
  230. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceAmount = @"fb_product_price_amount";
  231. FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceCurrency = @"fb_product_price_currency";
  232. // Event parameter values internal to this file
  233. NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
  234. NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled = @"Cancelled";
  235. NSString *const FBSDKAppEventsDialogOutcomeValue_Failed = @"Failed";
  236. NSString *const FBSDKAppEventsDialogShareModeAutomatic = @"Automatic";
  237. NSString *const FBSDKAppEventsDialogShareModeBrowser = @"Browser";
  238. NSString *const FBSDKAppEventsDialogShareModeNative = @"Native";
  239. NSString *const FBSDKAppEventsDialogShareModeShareSheet = @"ShareSheet";
  240. NSString *const FBSDKAppEventsDialogShareModeWeb = @"Web";
  241. NSString *const FBSDKAppEventsDialogShareModeFeedBrowser = @"FeedBrowser";
  242. NSString *const FBSDKAppEventsDialogShareModeFeedWeb = @"FeedWeb";
  243. NSString *const FBSDKAppEventsDialogShareModeUnknown = @"Unknown";
  244. NSString *const FBSDKAppEventsDialogShareContentTypeStatus = @"Status";
  245. NSString *const FBSDKAppEventsDialogShareContentTypePhoto = @"Photo";
  246. NSString *const FBSDKAppEventsDialogShareContentTypeVideo = @"Video";
  247. NSString *const FBSDKAppEventsDialogShareContentTypeCamera = @"Camera";
  248. NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown";
  249. NSString *const FBSDKGateKeeperAppEventsKillSwitch = @"app_events_killswitch";
  250. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  251. NSNotificationName const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
  252. #else
  253. NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
  254. #endif
  255. NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID";
  256. //
  257. // Push Notifications
  258. //
  259. // Activities Endpoint Parameter
  260. static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token";
  261. // Event Names
  262. static FBSDKAppEventName FBSDKAppEventNamePushTokenObtained = @"fb_mobile_obtain_push_token";
  263. static FBSDKAppEventName FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened";
  264. // Event Parameter
  265. static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign";
  266. static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
  267. // Payload Keys
  268. static NSString *const FBSDKAppEventsPushPayloadKey = @"fb_push_payload";
  269. static NSString *const FBSDKAppEventsPushPayloadCampaignKey = @"campaign";
  270. //
  271. // Augmentation of web browser constants
  272. //
  273. NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey = @"pixelID";
  274. NSString *const FBSDKAppEventsWKWebViewMessagesHandlerKey = @"fbmqHandler";
  275. NSString *const FBSDKAppEventsWKWebViewMessagesEventKey = @"event";
  276. NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey = @"params";
  277. NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1";
  278. #define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100
  279. #define FLUSH_PERIOD_IN_SECONDS 15
  280. #define USER_ID_USER_DEFAULTS_KEY @"com.facebook.sdk.appevents.userid"
  281. #define FBUnityUtilityClassName "FBUnityUtility"
  282. #define FBUnityUtilityUpdateBindingsSelector @"triggerUpdateBindings:"
  283. static NSString *g_overrideAppID = nil;
  284. @interface FBSDKAppEvents ()
  285. @property (nonatomic, assign) FBSDKAppEventsFlushBehavior flushBehavior;
  286. //for testing only.
  287. @property (nonatomic, assign) BOOL disableTimer;
  288. @property (nonatomic, copy) NSString *pushNotificationsDeviceTokenString;
  289. @property (nonatomic, strong) dispatch_source_t flushTimer;
  290. @property (nonatomic, copy) NSString *userID;
  291. @end
  292. @implementation FBSDKAppEvents
  293. {
  294. BOOL _explicitEventsLoggedYet;
  295. FBSDKServerConfiguration *_serverConfiguration;
  296. FBSDKAppEventsState *_appEventsState;
  297. #if !TARGET_OS_TV
  298. FBSDKEventBindingManager *_eventBindingManager;
  299. #endif
  300. BOOL _isUnityInit;
  301. }
  302. #pragma mark - Object Lifecycle
  303. + (void)initialize
  304. {
  305. if (self == [FBSDKAppEvents class]) {
  306. g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy];
  307. [FBSDKBasicUtility anonymousID];
  308. }
  309. }
  310. - (instancetype)init
  311. {
  312. self = [super init];
  313. if (self) {
  314. _flushBehavior = FBSDKAppEventsFlushBehaviorAuto;
  315. __weak FBSDKAppEvents *weakSelf = self;
  316. self.flushTimer = [FBSDKUtility startGCDTimerWithInterval:FLUSH_PERIOD_IN_SECONDS
  317. block:^{
  318. [weakSelf flushTimerFired:nil];
  319. }];
  320. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  321. _userID = [defaults stringForKey:USER_ID_USER_DEFAULTS_KEY];
  322. [self fetchServerConfiguration:nil];
  323. }
  324. return self;
  325. }
  326. - (void)registerNotifications {
  327. [[NSNotificationCenter defaultCenter]
  328. addObserver:self
  329. selector:@selector(applicationMovingFromActiveStateOrTerminating)
  330. name:UIApplicationWillResignActiveNotification
  331. object:NULL];
  332. [[NSNotificationCenter defaultCenter]
  333. addObserver:self
  334. selector:@selector(applicationMovingFromActiveStateOrTerminating)
  335. name:UIApplicationWillTerminateNotification
  336. object:NULL];
  337. [[NSNotificationCenter defaultCenter]
  338. addObserver:self
  339. selector:@selector(applicationDidBecomeActive)
  340. name:UIApplicationDidBecomeActiveNotification
  341. object:NULL];
  342. }
  343. - (void)dealloc
  344. {
  345. [[NSNotificationCenter defaultCenter] removeObserver:self];
  346. [FBSDKUtility stopGCDTimer:self.flushTimer];
  347. }
  348. #pragma mark - Public Methods
  349. + (void)logEvent:(FBSDKAppEventName)eventName
  350. {
  351. [FBSDKAppEvents logEvent:eventName
  352. parameters:@{}];
  353. }
  354. + (void)logEvent:(FBSDKAppEventName)eventName
  355. valueToSum:(double)valueToSum
  356. {
  357. [FBSDKAppEvents logEvent:eventName
  358. valueToSum:valueToSum
  359. parameters:@{}];
  360. }
  361. + (void)logEvent:(FBSDKAppEventName)eventName
  362. parameters:(NSDictionary *)parameters
  363. {
  364. [FBSDKAppEvents logEvent:eventName
  365. valueToSum:nil
  366. parameters:parameters
  367. accessToken:nil];
  368. }
  369. + (void)logEvent:(FBSDKAppEventName)eventName
  370. valueToSum:(double)valueToSum
  371. parameters:(NSDictionary *)parameters
  372. {
  373. [FBSDKAppEvents logEvent:eventName
  374. valueToSum:@(valueToSum)
  375. parameters:parameters
  376. accessToken:nil];
  377. }
  378. + (void)logEvent:(FBSDKAppEventName)eventName
  379. valueToSum:(NSNumber *)valueToSum
  380. parameters:(NSDictionary *)parameters
  381. accessToken:(FBSDKAccessToken *)accessToken
  382. {
  383. [[FBSDKAppEvents singleton] instanceLogEvent:eventName
  384. valueToSum:valueToSum
  385. parameters:parameters
  386. isImplicitlyLogged:[parameters[FBSDKAppEventParameterImplicitlyLogged] boolValue]
  387. accessToken:accessToken];
  388. }
  389. + (void)logPurchase:(double)purchaseAmount
  390. currency:(NSString *)currency
  391. {
  392. [FBSDKAppEvents logPurchase:purchaseAmount
  393. currency:currency
  394. parameters:@{}];
  395. }
  396. + (void)logPurchase:(double)purchaseAmount
  397. currency:(NSString *)currency
  398. parameters:(NSDictionary *)parameters
  399. {
  400. [FBSDKAppEvents logPurchase:purchaseAmount
  401. currency:currency
  402. parameters:parameters
  403. accessToken:nil];
  404. }
  405. + (void)logPurchase:(double)purchaseAmount
  406. currency:(NSString *)currency
  407. parameters:(NSDictionary *)parameters
  408. accessToken:(FBSDKAccessToken *)accessToken
  409. {
  410. // A purchase event is just a regular logged event with a given event name
  411. // and treating the currency value as going into the parameters dictionary.
  412. NSDictionary *newParameters;
  413. if (!parameters) {
  414. newParameters = @{ FBSDKAppEventParameterNameCurrency : currency };
  415. } else {
  416. newParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
  417. [newParameters setValue:currency forKey:FBSDKAppEventParameterNameCurrency];
  418. }
  419. [FBSDKAppEvents logEvent:FBSDKAppEventNamePurchased
  420. valueToSum:@(purchaseAmount)
  421. parameters:newParameters
  422. accessToken:accessToken];
  423. // Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events
  424. // are relatively rare and relatively high value and worth getting across on wire right away.
  425. if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) {
  426. [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent];
  427. }
  428. }
  429. /*
  430. * Push Notifications Logging
  431. */
  432. + (void)logPushNotificationOpen:(NSDictionary *)payload
  433. {
  434. [self logPushNotificationOpen:payload action:@""];
  435. }
  436. + (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action
  437. {
  438. NSDictionary *facebookPayload = payload[FBSDKAppEventsPushPayloadKey];
  439. if (!facebookPayload) {
  440. return;
  441. }
  442. NSString *campaign = facebookPayload[FBSDKAppEventsPushPayloadCampaignKey];
  443. if (campaign.length == 0) {
  444. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  445. logEntry:@"Malformed payload specified for logging a push notification open."];
  446. return;
  447. }
  448. NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign];
  449. if (action && action.length > 0) {
  450. parameters[FBSDKAppEventParameterPushAction] = action;
  451. }
  452. [self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
  453. }
  454. /*
  455. * Uploads product catalog product item as an app event
  456. */
  457. + (void)logProductItem:(NSString *)itemID
  458. availability:(FBSDKProductAvailability)availability
  459. condition:(FBSDKProductCondition)condition
  460. description:(NSString *)description
  461. imageLink:(NSString *)imageLink
  462. link:(NSString *)link
  463. title:(NSString *)title
  464. priceAmount:(double)priceAmount
  465. currency:(NSString *)currency
  466. gtin:(NSString *)gtin
  467. mpn:(NSString *)mpn
  468. brand:(NSString *)brand
  469. parameters:(NSDictionary *)parameters
  470. {
  471. if (itemID == nil) {
  472. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  473. logEntry:@"itemID cannot be null"];
  474. return;
  475. } else if (description == nil) {
  476. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  477. logEntry:@"description cannot be null"];
  478. return;
  479. } else if (imageLink == nil) {
  480. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  481. logEntry:@"imageLink cannot be null"];
  482. return;
  483. } else if (link == nil) {
  484. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  485. logEntry:@"link cannot be null"];
  486. return;
  487. } else if (title == nil) {
  488. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  489. logEntry:@"title cannot be null"];
  490. return;
  491. } else if (currency == nil) {
  492. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  493. logEntry:@"currency cannot be null"];
  494. return;
  495. } else if (gtin == nil && mpn == nil && brand == nil) {
  496. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
  497. logEntry:@"Either gtin, mpn or brand is required"];
  498. return;
  499. }
  500. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  501. if (nil != parameters) {
  502. [dict setValuesForKeysWithDictionary:parameters];
  503. }
  504. dict[FBSDKAppEventParameterProductItemID] = itemID;
  505. NSString *avail = nil;
  506. switch (availability) {
  507. case FBSDKProductAvailabilityInStock:
  508. avail = @"IN_STOCK"; break;
  509. case FBSDKProductAvailabilityOutOfStock:
  510. avail = @"OUT_OF_STOCK"; break;
  511. case FBSDKProductAvailabilityPreOrder:
  512. avail = @"PREORDER"; break;
  513. case FBSDKProductAvailabilityAvailableForOrder:
  514. avail = @"AVALIABLE_FOR_ORDER"; break;
  515. case FBSDKProductAvailabilityDiscontinued:
  516. avail = @"DISCONTINUED"; break;
  517. }
  518. if (avail) {
  519. dict[FBSDKAppEventParameterProductAvailability] = avail;
  520. }
  521. NSString *cond = nil;
  522. switch (condition) {
  523. case FBSDKProductConditionNew:
  524. cond = @"NEW"; break;
  525. case FBSDKProductConditionRefurbished:
  526. cond = @"REFURBISHED"; break;
  527. case FBSDKProductConditionUsed:
  528. cond = @"USED"; break;
  529. }
  530. if (cond) {
  531. dict[FBSDKAppEventParameterProductCondition] = cond;
  532. }
  533. dict[FBSDKAppEventParameterProductDescription] = description;
  534. dict[FBSDKAppEventParameterProductImageLink] = imageLink;
  535. dict[FBSDKAppEventParameterProductLink] = link;
  536. dict[FBSDKAppEventParameterProductTitle] = title;
  537. dict[FBSDKAppEventParameterProductPriceAmount] = [NSString stringWithFormat:@"%.3lf", priceAmount];
  538. dict[FBSDKAppEventParameterProductPriceCurrency] = currency;
  539. if (gtin) {
  540. dict[FBSDKAppEventParameterProductGTIN] = gtin;
  541. }
  542. if (mpn) {
  543. dict[FBSDKAppEventParameterProductMPN] = mpn;
  544. }
  545. if (brand) {
  546. dict[FBSDKAppEventParameterProductBrand] = brand;
  547. }
  548. [FBSDKAppEvents logEvent:FBSDKAppEventNameProductCatalogUpdate
  549. parameters:dict];
  550. }
  551. + (void)activateApp
  552. {
  553. [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
  554. // Fetch app settings and register for transaction notifications only if app supports implicit purchase
  555. // events
  556. FBSDKAppEvents *instance = [FBSDKAppEvents singleton];
  557. [instance publishInstall];
  558. [instance fetchServerConfiguration:NULL];
  559. // Restore time spent data, indicating that we're being called from "activateApp", which will,
  560. // when appropriate, result in logging an "activated app" and "deactivated app" (for the
  561. // previous session) App Event.
  562. [FBSDKTimeSpentData restore:YES];
  563. }
  564. + (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
  565. {
  566. NSString *deviceTokenString = [FBSDKInternalUtility hexadecimalStringFromData:deviceToken];
  567. [FBSDKAppEvents setPushNotificationsDeviceTokenString:deviceTokenString];
  568. }
  569. + (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString
  570. {
  571. if (deviceTokenString == nil) {
  572. [FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = nil;
  573. return;
  574. }
  575. if (![deviceTokenString isEqualToString:([FBSDKAppEvents singleton].pushNotificationsDeviceTokenString)]) {
  576. [FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = deviceTokenString;
  577. [FBSDKAppEvents logEvent:FBSDKAppEventNamePushTokenObtained];
  578. // Unless the behavior is set to only allow explicit flushing, we go ahead and flush the event
  579. if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) {
  580. [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent];
  581. }
  582. }
  583. }
  584. + (FBSDKAppEventsFlushBehavior)flushBehavior
  585. {
  586. return [FBSDKAppEvents singleton].flushBehavior;
  587. }
  588. + (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior
  589. {
  590. [FBSDKAppEvents singleton].flushBehavior = flushBehavior;
  591. }
  592. + (NSString *)loggingOverrideAppID
  593. {
  594. return g_overrideAppID;
  595. }
  596. + (void)setLoggingOverrideAppID:(NSString *)appID
  597. {
  598. if (![g_overrideAppID isEqualToString:appID]) {
  599. FBSDKConditionalLog(![FBSDKAppEvents singleton]->_explicitEventsLoggedYet,
  600. FBSDKLoggingBehaviorDeveloperErrors,
  601. @"[FBSDKAppEvents setLoggingOverrideAppID:] should only be called prior to any events being logged.");
  602. g_overrideAppID = appID;
  603. }
  604. }
  605. + (void)flush
  606. {
  607. [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonExplicit];
  608. }
  609. + (void)setUserID:(NSString *)userID
  610. {
  611. if ([[[self class] singleton].userID isEqualToString:userID]) {
  612. return;
  613. }
  614. [[self class] singleton].userID = userID;
  615. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  616. [defaults setObject:userID forKey:USER_ID_USER_DEFAULTS_KEY];
  617. [defaults synchronize];
  618. }
  619. + (void)clearUserID
  620. {
  621. [self setUserID:nil];
  622. }
  623. + (NSString *)userID
  624. {
  625. return [[self class] singleton].userID;
  626. }
  627. + (void)setUserEmail:(nullable NSString *)email
  628. firstName:(nullable NSString *)firstName
  629. lastName:(nullable NSString *)lastName
  630. phone:(nullable NSString *)phone
  631. dateOfBirth:(nullable NSString *)dateOfBirth
  632. gender:(nullable NSString *)gender
  633. city:(nullable NSString *)city
  634. state:(nullable NSString *)state
  635. zip:(nullable NSString *)zip
  636. country:(nullable NSString *)country
  637. {
  638. [FBSDKUserDataStore setAndHashUserEmail:email
  639. firstName:firstName
  640. lastName:lastName
  641. phone:phone
  642. dateOfBirth:dateOfBirth
  643. gender:gender
  644. city:city
  645. state:state
  646. zip:zip
  647. country:country];
  648. }
  649. + (NSString*)getUserData
  650. {
  651. return [FBSDKUserDataStore getHashedData];
  652. }
  653. + (void)clearUserData
  654. {
  655. [FBSDKUserDataStore setAndHashUserEmail:nil
  656. firstName:nil
  657. lastName:nil
  658. phone:nil
  659. dateOfBirth:nil
  660. gender:nil
  661. city:nil
  662. state:nil
  663. zip:nil
  664. country:nil];
  665. }
  666. + (void)setUserData:(nullable NSString *)data
  667. forType:(FBSDKAppEventUserDataType)type
  668. {
  669. [FBSDKUserDataStore setAndHashData:data forType:type];
  670. }
  671. + (void)clearUserDataForType:(FBSDKAppEventUserDataType)type
  672. {
  673. [FBSDKUserDataStore clearDataForType:type];
  674. }
  675. + (void)updateUserProperties:(NSDictionary<NSString *, id> *)properties handler:(FBSDKGraphRequestBlock)handler
  676. {
  677. NSString *userID = [[self class] userID];
  678. if (userID.length == 0) {
  679. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
  680. NSError *error = [FBSDKError requiredArgumentErrorWithName:@"userID" message:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
  681. if (handler) {
  682. handler(nil, nil, error);
  683. }
  684. return;
  685. }
  686. NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionaryWithCapacity:3];
  687. [FBSDKBasicUtility dictionary:dataDictionary setObject:[FBSDKAppEvents userID] forKey:@"user_unique_id"];
  688. [FBSDKBasicUtility dictionary:dataDictionary setObject:[FBSDKAppEventsUtility advertiserID] forKey:@"advertiser_id"];
  689. [FBSDKBasicUtility dictionary:dataDictionary setObject:properties forKey:@"custom_data"];
  690. NSError *error;
  691. __block NSError *invalidObjectError;
  692. NSString *dataJSONString = [FBSDKBasicUtility JSONStringForObject:@[dataDictionary] error:&error invalidObjectHandler:^id(id object, BOOL *stop) {
  693. *stop = YES;
  694. invalidObjectError = [FBSDKError unknownErrorWithMessage:@"The values in the properties dictionary must be NSStrings or NSNumbers"];
  695. return nil;
  696. }];
  697. if (!error) {
  698. error = invalidObjectError;
  699. }
  700. if (error) {
  701. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Failed to serialize properties for [FBSDKAppEvents updateUserProperties:]"];
  702. if (handler) {
  703. handler(nil, nil, error);
  704. }
  705. return;
  706. }
  707. NSDictionary *params = @{ @"data" : dataJSONString };
  708. FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/user_properties", [[self singleton] appID]]
  709. parameters:params
  710. tokenString:[FBSDKAccessToken currentAccessToken].tokenString
  711. HTTPMethod:FBSDKHTTPMethodPOST
  712. flags:FBSDKGraphRequestFlagDisableErrorRecovery |
  713. FBSDKGraphRequestFlagDoNotInvalidateTokenOnError |
  714. FBSDKGraphRequestFlagSkipClientToken
  715. ];
  716. [request startWithCompletionHandler:handler];
  717. }
  718. + (NSString *)anonymousID
  719. {
  720. return [FBSDKBasicUtility anonymousID];
  721. }
  722. #if !TARGET_OS_TV
  723. + (void)augmentHybridWKWebView:(WKWebView *)webView {
  724. // Ensure we can instantiate WebKit before trying this
  725. Class WKWebViewClass = fbsdkdfl_WKWebViewClass();
  726. if (WKWebViewClass != nil && [webView isKindOfClass:WKWebViewClass]) {
  727. Class WKUserScriptClass = fbsdkdfl_WKUserScriptClass();
  728. if (WKUserScriptClass != nil) {
  729. WKUserContentController *controller = webView.configuration.userContentController;
  730. FBSDKHybridAppEventsScriptMessageHandler *scriptHandler = [[FBSDKHybridAppEventsScriptMessageHandler alloc] init];
  731. [controller addScriptMessageHandler:scriptHandler name:FBSDKAppEventsWKWebViewMessagesHandlerKey];
  732. NSString *js = [NSString stringWithFormat:@"window.fbmq_%@={'sendEvent': function(pixel_id,event_name,custom_data){var msg={\"%@\":pixel_id, \"%@\":event_name,\"%@\":custom_data};window.webkit.messageHandlers[\"%@\"].postMessage(msg);}, 'getProtocol':function(){return \"%@\";}}",
  733. [[self singleton] appID],
  734. FBSDKAppEventsWKWebViewMessagesPixelIDKey,
  735. FBSDKAppEventsWKWebViewMessagesEventKey,
  736. FBSDKAppEventsWKWebViewMessagesParamsKey,
  737. FBSDKAppEventsWKWebViewMessagesHandlerKey,
  738. FBSDKAPPEventsWKWebViewMessagesProtocolKey
  739. ];
  740. [controller addUserScript:[[WKUserScriptClass alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]];
  741. }
  742. }
  743. else {
  744. [FBSDKAppEventsUtility logAndNotify:@"You must call augmentHybridWKWebView with WebKit linked to your project and a WKWebView instance"];
  745. }
  746. }
  747. #endif
  748. + (void)setIsUnityInit:(BOOL)isUnityInit
  749. {
  750. [FBSDKAppEvents singleton]->_isUnityInit = isUnityInit;
  751. }
  752. #pragma clang diagnostic push
  753. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  754. + (void)sendEventBindingsToUnity
  755. {
  756. // Send event bindings to Unity only Unity is initialized
  757. if ([FBSDKAppEvents singleton]->_isUnityInit
  758. && [FBSDKAppEvents singleton]->_serverConfiguration
  759. && [NSJSONSerialization isValidJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings]
  760. ) {
  761. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings ?: @""
  762. options:0
  763. error:nil];
  764. NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  765. Class classFBUnityUtility = objc_lookUpClass(FBUnityUtilityClassName);
  766. SEL updateBindingSelector = NSSelectorFromString(FBUnityUtilityUpdateBindingsSelector);
  767. if ([classFBUnityUtility respondsToSelector:updateBindingSelector]) {
  768. [classFBUnityUtility performSelector:updateBindingSelector withObject:jsonString];
  769. }
  770. }
  771. }
  772. #pragma clang diagnostic pop
  773. #pragma mark - Internal Methods
  774. + (void)logInternalEvent:(FBSDKAppEventName)eventName
  775. isImplicitlyLogged:(BOOL)isImplicitlyLogged;
  776. {
  777. [FBSDKAppEvents logInternalEvent:eventName
  778. parameters:@{}
  779. isImplicitlyLogged:isImplicitlyLogged];
  780. }
  781. + (void)logInternalEvent:(FBSDKAppEventName)eventName
  782. valueToSum:(double)valueToSum
  783. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  784. {
  785. [FBSDKAppEvents logInternalEvent:eventName
  786. valueToSum:valueToSum
  787. parameters:@{}
  788. isImplicitlyLogged:isImplicitlyLogged];
  789. }
  790. + (void)logInternalEvent:(FBSDKAppEventName)eventName
  791. parameters:(NSDictionary *)parameters
  792. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  793. {
  794. [FBSDKAppEvents logInternalEvent:eventName
  795. valueToSum:nil
  796. parameters:parameters
  797. isImplicitlyLogged:isImplicitlyLogged
  798. accessToken:nil];
  799. }
  800. + (void)logInternalEvent:(FBSDKAppEventName)eventName
  801. parameters:(NSDictionary *)parameters
  802. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  803. accessToken:(FBSDKAccessToken *)accessToken
  804. {
  805. [FBSDKAppEvents logInternalEvent:eventName
  806. valueToSum:nil
  807. parameters:parameters
  808. isImplicitlyLogged:isImplicitlyLogged
  809. accessToken:accessToken];
  810. }
  811. + (void)logInternalEvent:(FBSDKAppEventName)eventName
  812. valueToSum:(double)valueToSum
  813. parameters:(NSDictionary *)parameters
  814. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  815. {
  816. [FBSDKAppEvents logInternalEvent:eventName
  817. valueToSum:@(valueToSum)
  818. parameters:parameters
  819. isImplicitlyLogged:isImplicitlyLogged
  820. accessToken:nil];
  821. }
  822. + (void)logInternalEvent:(NSString *)eventName
  823. valueToSum:(NSNumber *)valueToSum
  824. parameters:(NSDictionary *)parameters
  825. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  826. accessToken:(FBSDKAccessToken *)accessToken
  827. {
  828. if ([FBSDKSettings isAutoLogAppEventsEnabled]) {
  829. [[FBSDKAppEvents singleton] instanceLogEvent:eventName
  830. valueToSum:valueToSum
  831. parameters:parameters
  832. isImplicitlyLogged:isImplicitlyLogged
  833. accessToken:accessToken];
  834. }
  835. }
  836. + (void)logImplicitEvent:(NSString *)eventName
  837. valueToSum:(NSNumber *)valueToSum
  838. parameters:(NSDictionary *)parameters
  839. accessToken:(FBSDKAccessToken *)accessToken
  840. {
  841. [[FBSDKAppEvents singleton] instanceLogEvent:eventName
  842. valueToSum:valueToSum
  843. parameters:parameters
  844. isImplicitlyLogged:YES
  845. accessToken:accessToken];
  846. }
  847. #ifdef DEBUG
  848. static dispatch_once_t *onceTokenPointer;
  849. + (void)resetSingleton
  850. {
  851. if (onceTokenPointer) {
  852. *onceTokenPointer = 0;
  853. }
  854. }
  855. #endif
  856. + (FBSDKAppEvents *)singleton
  857. {
  858. static dispatch_once_t onceToken;
  859. #ifdef DEBUG
  860. onceTokenPointer = &onceToken;
  861. #endif
  862. static FBSDKAppEvents *shared = nil;
  863. dispatch_once(&onceToken, ^{
  864. shared = [[self alloc] init];
  865. });
  866. return shared;
  867. }
  868. - (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason
  869. {
  870. // Always flush asynchronously, even on main thread, for two reasons:
  871. // - most consistent code path for all threads.
  872. // - allow locks being held by caller to be released prior to actual flushing work being done.
  873. @synchronized (self) {
  874. if (!_appEventsState) {
  875. return;
  876. }
  877. FBSDKAppEventsState *copy = [_appEventsState copy];
  878. _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:copy.tokenString
  879. appID:copy.appID];
  880. dispatch_async(dispatch_get_main_queue(), ^{
  881. [self flushOnMainQueue:copy forReason:flushReason];
  882. });
  883. }
  884. }
  885. #pragma mark - Private Methods
  886. - (NSString *)appID
  887. {
  888. return [FBSDKAppEvents loggingOverrideAppID] ?: [FBSDKSettings appID];
  889. }
  890. - (void)publishInstall
  891. {
  892. NSString *appID = [self appID];
  893. if (appID.length == 0) {
  894. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appID] for [FBSDKAppEvents publishInstall:]"];
  895. return;
  896. }
  897. NSString *lastAttributionPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastAttributionPing%@", appID];
  898. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  899. if ([defaults objectForKey:lastAttributionPingString]) {
  900. return;
  901. }
  902. [self fetchServerConfiguration:^{
  903. NSDictionary *params = [FBSDKAppEventsUtility activityParametersDictionaryForEvent:@"MOBILE_APP_INSTALL"
  904. shouldAccessAdvertisingID:self->_serverConfiguration.isAdvertisingIDEnabled];
  905. NSString *path = [NSString stringWithFormat:@"%@/activities", appID];
  906. FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
  907. parameters:params
  908. tokenString:nil
  909. HTTPMethod:FBSDKHTTPMethodPOST
  910. flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
  911. [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
  912. if (!error) {
  913. [defaults setObject:[NSDate date] forKey:lastAttributionPingString];
  914. NSString *lastInstallResponseKey = [NSString stringWithFormat:@"com.facebook.sdk:lastInstallResponse%@", appID];
  915. [defaults setObject:result forKey:lastInstallResponseKey];
  916. [defaults synchronize];
  917. }
  918. }];
  919. }];
  920. }
  921. #if !TARGET_OS_TV
  922. - (void)enableCodelessEvents {
  923. if (_serverConfiguration.isCodelessEventsEnabled) {
  924. [FBSDKCodelessIndexer enable];
  925. if (!_eventBindingManager) {
  926. _eventBindingManager = [[FBSDKEventBindingManager alloc] init];
  927. }
  928. if ([FBSDKInternalUtility isUnity]) {
  929. [FBSDKAppEvents sendEventBindingsToUnity];
  930. } else {
  931. [_eventBindingManager updateBindings:[FBSDKEventBindingManager
  932. parseArray:_serverConfiguration.eventBindings]];
  933. }
  934. }
  935. }
  936. #endif
  937. // app events can use a server configuration up to 24 hours old to minimize network traffic.
  938. - (void)fetchServerConfiguration:(FBSDKCodeBlock)callback
  939. {
  940. [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
  941. self->_serverConfiguration = serverConfiguration;
  942. if (self->_serverConfiguration.implicitPurchaseLoggingEnabled && [FBSDKSettings isAutoLogAppEventsEnabled]) {
  943. [FBSDKPaymentObserver startObservingTransactions];
  944. } else {
  945. [FBSDKPaymentObserver stopObservingTransactions];
  946. }
  947. #if !TARGET_OS_TV
  948. [FBSDKFeatureManager checkFeature:FBSDKFeatureCodelessEvents completionBlock:^(BOOL enabled) {
  949. if (enabled) {
  950. [self enableCodelessEvents];
  951. }
  952. }];
  953. [FBSDKFeatureManager checkFeature:FBSDKFeatureAAM completionBlock:^(BOOL enabled) {
  954. if (enabled) {
  955. // Enable AAM
  956. [FBSDKMetadataIndexer enable];
  957. }
  958. }];
  959. #endif
  960. #if !defined BUCK && !TARGET_OS_TV
  961. [FBSDKFeatureManager checkFeature:FBSDKFeaturePrivacyProtection completionBlock:^(BOOL enabled) {
  962. if (enabled) {
  963. [FBSDKModelManager enable];
  964. }
  965. }];
  966. #endif
  967. if (callback) {
  968. callback();
  969. }
  970. }];
  971. }
  972. #pragma clang diagnostic push
  973. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  974. - (void)instanceLogEvent:(FBSDKAppEventName)eventName
  975. valueToSum:(NSNumber *)valueToSum
  976. parameters:(NSDictionary *)parameters
  977. isImplicitlyLogged:(BOOL)isImplicitlyLogged
  978. accessToken:(FBSDKAccessToken *)accessToken
  979. {
  980. // Kill events if kill-switch is enabled
  981. if ([FBSDKGateKeeperManager boolForKey:FBSDKGateKeeperAppEventsKillSwitch
  982. defaultValue:NO]) {
  983. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
  984. formatString:@"FBSDKAppEvents: KillSwitch is enabled and fail to log app event: %@",
  985. eventName];
  986. return;
  987. }
  988. if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) {
  989. return;
  990. }
  991. if (!isImplicitlyLogged && !_explicitEventsLoggedYet) {
  992. _explicitEventsLoggedYet = YES;
  993. }
  994. __block BOOL failed = ![FBSDKAppEventsUtility validateIdentifier:eventName];
  995. // Make sure parameter dictionary is well formed. Log and exit if not.
  996. [parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  997. if (![key isKindOfClass:[NSString class]]) {
  998. [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The keys in the parameters must be NSStrings, '%@' is not.", key]];
  999. failed = YES;
  1000. }
  1001. if (![FBSDKAppEventsUtility validateIdentifier:key]) {
  1002. failed = YES;
  1003. }
  1004. if (![obj isKindOfClass:[NSString class]] && ![obj isKindOfClass:[NSNumber class]]) {
  1005. [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The values in the parameters dictionary must be NSStrings or NSNumbers, '%@' is not.", obj]];
  1006. failed = YES;
  1007. }
  1008. }
  1009. ];
  1010. if (failed) {
  1011. return;
  1012. }
  1013. // Filter out deactivated params
  1014. parameters = [FBSDKEventDeactivationManager processParameters:parameters eventName:eventName];
  1015. #if !defined BUCK && !TARGET_OS_TV
  1016. // Filter out restrictive data with on-device ML
  1017. parameters = [FBSDKIntegrityManager processParameters:parameters];
  1018. #endif
  1019. // Filter out restrictive keys
  1020. parameters = [FBSDKRestrictiveDataFilterManager processParameters:parameters
  1021. eventName:eventName];
  1022. NSMutableDictionary<NSString *, id> *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
  1023. eventDictionary[FBSDKAppEventParameterEventName] = eventName;
  1024. if (!eventDictionary[FBSDKAppEventParameterLogTime]) {
  1025. eventDictionary[FBSDKAppEventParameterLogTime] = @([FBSDKAppEventsUtility unixTimeNow]);
  1026. }
  1027. [FBSDKBasicUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
  1028. if (isImplicitlyLogged) {
  1029. eventDictionary[FBSDKAppEventParameterImplicitlyLogged] = @"1";
  1030. }
  1031. NSString *currentViewControllerName;
  1032. UIApplicationState applicationState;
  1033. if ([NSThread isMainThread]) {
  1034. // We only collect the view controller when on the main thread, as the behavior off
  1035. // the main thread is unpredictable. Besides, UI state for off-main-thread computations
  1036. // isn't really relevant anyhow.
  1037. UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
  1038. vc = vc.presentedViewController ?: vc;
  1039. if (vc) {
  1040. currentViewControllerName = [[vc class] description];
  1041. } else {
  1042. currentViewControllerName = @"no_ui";
  1043. }
  1044. applicationState = [UIApplication sharedApplication].applicationState;
  1045. } else {
  1046. currentViewControllerName = @"off_thread";
  1047. applicationState = [FBSDKApplicationDelegate applicationState];
  1048. }
  1049. eventDictionary[@"_ui"] = currentViewControllerName;
  1050. if (applicationState == UIApplicationStateBackground) {
  1051. eventDictionary[FBSDKAppEventParameterInBackground] = @"1";
  1052. }
  1053. NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
  1054. NSString *appID = [self appID];
  1055. @synchronized (self) {
  1056. if (!_appEventsState) {
  1057. _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID];
  1058. } else if (![_appEventsState isCompatibleWithTokenString:tokenString appID:appID]) {
  1059. if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) {
  1060. [FBSDKAppEventsStateManager persistAppEventsData:_appEventsState];
  1061. } else {
  1062. [self flushForReason:FBSDKAppEventsFlushReasonSessionChange];
  1063. }
  1064. _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID];
  1065. }
  1066. [_appEventsState addEvent:eventDictionary isImplicit:isImplicitlyLogged];
  1067. if (!isImplicitlyLogged) {
  1068. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
  1069. formatString:@"FBSDKAppEvents: Recording event @ %ld: %@",
  1070. [FBSDKAppEventsUtility unixTimeNow],
  1071. eventDictionary];
  1072. }
  1073. [self checkPersistedEvents];
  1074. if (_appEventsState.events.count > NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER &&
  1075. self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly) {
  1076. [self flushForReason:FBSDKAppEventsFlushReasonEventThreshold];
  1077. }
  1078. }
  1079. }
  1080. #pragma clang diagnostic pop
  1081. // this fetches persisted event states.
  1082. // for those matching the currently tracked events, add it.
  1083. // otherwise, either flush (if not explicitonly behavior) or persist them back.
  1084. - (void)checkPersistedEvents
  1085. {
  1086. NSArray *existingEventsStates = [FBSDKAppEventsStateManager retrievePersistedAppEventsStates];
  1087. if (existingEventsStates.count == 0) {
  1088. return;
  1089. }
  1090. FBSDKAppEventsState *matchingEventsPreviouslySaved = nil;
  1091. // reduce lock time by creating a new FBSDKAppEventsState to collect matching persisted events.
  1092. @synchronized(self) {
  1093. if (_appEventsState) {
  1094. matchingEventsPreviouslySaved = [[FBSDKAppEventsState alloc] initWithToken:_appEventsState.tokenString
  1095. appID:_appEventsState.appID];
  1096. }
  1097. }
  1098. for (FBSDKAppEventsState *saved in existingEventsStates) {
  1099. if ([saved isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) {
  1100. [matchingEventsPreviouslySaved addEventsFromAppEventState:saved];
  1101. } else {
  1102. if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) {
  1103. [FBSDKAppEventsStateManager persistAppEventsData:saved];
  1104. } else {
  1105. dispatch_async(dispatch_get_main_queue(), ^{
  1106. [self flushOnMainQueue:saved forReason:FBSDKAppEventsFlushReasonPersistedEvents];
  1107. });
  1108. }
  1109. }
  1110. }
  1111. if (matchingEventsPreviouslySaved.events.count > 0) {
  1112. @synchronized(self) {
  1113. if ([_appEventsState isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) {
  1114. [_appEventsState addEventsFromAppEventState:matchingEventsPreviouslySaved];
  1115. }
  1116. }
  1117. }
  1118. }
  1119. - (void)flushOnMainQueue:(FBSDKAppEventsState *)appEventsState
  1120. forReason:(FBSDKAppEventsFlushReason)reason
  1121. {
  1122. if (appEventsState.events.count == 0) {
  1123. return;
  1124. }
  1125. if (appEventsState.appID.length == 0) {
  1126. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appEventsState.appID] for [FBSDKAppEvents flushOnMainQueue:]"];
  1127. return;
  1128. }
  1129. [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
  1130. [self fetchServerConfiguration:^(void) {
  1131. NSString *receipt_data = appEventsState.extractReceiptData;
  1132. NSString *encodedEvents = [appEventsState JSONStringForEvents:self->_serverConfiguration.implicitLoggingEnabled];
  1133. if (!encodedEvents) {
  1134. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
  1135. logEntry:@"FBSDKAppEvents: Flushing skipped - no events after removing implicitly logged ones.\n"];
  1136. return;
  1137. }
  1138. NSMutableDictionary *postParameters = [FBSDKAppEventsUtility
  1139. activityParametersDictionaryForEvent:@"CUSTOM_APP_EVENTS"
  1140. shouldAccessAdvertisingID:self->_serverConfiguration.advertisingIDEnabled];
  1141. NSInteger length = receipt_data.length;
  1142. if (length > 0) {
  1143. postParameters[@"receipt_data"] = receipt_data;
  1144. }
  1145. postParameters[@"custom_events"] = encodedEvents;
  1146. if (appEventsState.numSkipped > 0) {
  1147. postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped];
  1148. }
  1149. if (self.pushNotificationsDeviceTokenString) {
  1150. postParameters[FBSDKActivitesParameterPushDeviceToken] = self.pushNotificationsDeviceTokenString;
  1151. }
  1152. NSString *loggingEntry = nil;
  1153. if ([FBSDKSettings.loggingBehaviors containsObject:FBSDKLoggingBehaviorAppEvents]) {
  1154. NSData *prettyJSONData = [NSJSONSerialization dataWithJSONObject:appEventsState.events
  1155. options:NSJSONWritingPrettyPrinted
  1156. error:NULL];
  1157. NSString *prettyPrintedJsonEvents = [[NSString alloc] initWithData:prettyJSONData
  1158. encoding:NSUTF8StringEncoding];
  1159. // Remove this param -- just an encoding of the events which we pretty print later.
  1160. NSMutableDictionary *paramsForPrinting = [postParameters mutableCopy];
  1161. [paramsForPrinting removeObjectForKey:@"custom_events_file"];
  1162. loggingEntry = [NSString stringWithFormat:@"FBSDKAppEvents: Flushed @ %ld, %lu events due to '%@' - %@\nEvents: %@",
  1163. [FBSDKAppEventsUtility unixTimeNow],
  1164. (unsigned long)appEventsState.events.count,
  1165. [FBSDKAppEventsUtility flushReasonToString:reason],
  1166. paramsForPrinting,
  1167. prettyPrintedJsonEvents];
  1168. }
  1169. FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID]
  1170. parameters:postParameters
  1171. tokenString:appEventsState.tokenString
  1172. HTTPMethod:FBSDKHTTPMethodPOST
  1173. flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
  1174. [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
  1175. [self handleActivitiesPostCompletion:error
  1176. loggingEntry:loggingEntry
  1177. appEventsState:(FBSDKAppEventsState *)appEventsState];
  1178. }];
  1179. }];
  1180. }
  1181. - (void)handleActivitiesPostCompletion:(NSError *)error
  1182. loggingEntry:(NSString *)loggingEntry
  1183. appEventsState:(FBSDKAppEventsState *)appEventsState
  1184. {
  1185. typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushResult) {
  1186. FlushResultSuccess,
  1187. FlushResultServerError,
  1188. FlushResultNoConnectivity
  1189. };
  1190. [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
  1191. FBSDKAppEventsFlushResult flushResult = FlushResultSuccess;
  1192. if (error) {
  1193. NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue];
  1194. // We interpret a 400 coming back from FBRequestConnection as a server error due to improper data being
  1195. // sent down. Otherwise we assume no connectivity, or another condition where we could treat it as no connectivity.
  1196. // Adding 404 as having wrong/missing appID results in 404 and that is not a connectivity issue
  1197. flushResult = (errorCode == 400 || errorCode == 404) ? FlushResultServerError : FlushResultNoConnectivity;
  1198. }
  1199. if (flushResult == FlushResultServerError) {
  1200. // Only log events that developer can do something with (i.e., if parameters are incorrect).
  1201. // as opposed to cases where the token is bad.
  1202. if ([error.userInfo[FBSDKGraphRequestErrorKey] unsignedIntegerValue] == FBSDKGraphRequestErrorOther) {
  1203. NSString *message = [NSString stringWithFormat:@"Failed to send AppEvents: %@", error];
  1204. [FBSDKAppEventsUtility logAndNotify:message allowLogAsDeveloperError:!appEventsState.areAllEventsImplicit];
  1205. }
  1206. } else if (flushResult == FlushResultNoConnectivity) {
  1207. @synchronized(self) {
  1208. if ([appEventsState isCompatibleWithAppEventsState:_appEventsState]) {
  1209. [_appEventsState addEventsFromAppEventState:appEventsState];
  1210. } else {
  1211. // flush failed due to connectivity. Persist to be tried again later.
  1212. [FBSDKAppEventsStateManager persistAppEventsData:appEventsState];
  1213. }
  1214. }
  1215. }
  1216. NSString *resultString = @"<unknown>";
  1217. switch (flushResult) {
  1218. case FlushResultSuccess:
  1219. resultString = @"Success";
  1220. break;
  1221. case FlushResultNoConnectivity:
  1222. resultString = @"No Connectivity";
  1223. break;
  1224. case FlushResultServerError:
  1225. resultString = [NSString stringWithFormat:@"Server Error - %@", error.description];
  1226. break;
  1227. }
  1228. [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
  1229. formatString:@"%@\nFlush Result : %@", loggingEntry, resultString];
  1230. }
  1231. - (void)flushTimerFired:(id)arg
  1232. {
  1233. [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
  1234. if (self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly && !self.disableTimer) {
  1235. [self flushForReason:FBSDKAppEventsFlushReasonTimer];
  1236. }
  1237. }
  1238. - (void)applicationDidBecomeActive
  1239. {
  1240. [FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
  1241. [self checkPersistedEvents];
  1242. // Restore time spent data, indicating that we're not being called from "activateApp".
  1243. [FBSDKTimeSpentData restore:NO];
  1244. }
  1245. - (void)applicationMovingFromActiveStateOrTerminating
  1246. {
  1247. // When moving from active state, we don't have time to wait for the result of a flush, so
  1248. // just persist events to storage, and we'll process them at the next activation.
  1249. FBSDKAppEventsState *copy = nil;
  1250. @synchronized (self) {
  1251. copy = [_appEventsState copy];
  1252. _appEventsState = nil;
  1253. }
  1254. if (copy) {
  1255. [FBSDKAppEventsStateManager persistAppEventsData:copy];
  1256. }
  1257. [FBSDKTimeSpentData suspend];
  1258. }
  1259. #pragma mark - Custom Audience
  1260. + (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken
  1261. {
  1262. accessToken = accessToken ?: [FBSDKAccessToken currentAccessToken];
  1263. // Rules for how we use the attribution ID / advertiser ID for an 'custom_audience_third_party_id' Graph API request
  1264. // 1) if the OS tells us that the user has Limited Ad Tracking, then just don't send, and return a nil in the token.
  1265. // 2) if the app has set 'limitEventAndDataUsage', this effectively implies that app-initiated ad targeting shouldn't happen,
  1266. // so use that data here to return nil as well.
  1267. // 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter
  1268. // 4) otherwise, send back the udid parameter.
  1269. if ([FBSDKAppEventsUtility advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed || FBSDKSettings.shouldLimitEventAndDataUsage) {
  1270. return nil;
  1271. }
  1272. NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
  1273. NSString *udid = nil;
  1274. if (!accessToken) {
  1275. // We don't have a logged in user, so we need some form of udid representation. Prefer advertiser ID if
  1276. // available, and back off to attribution ID if not. Note that this function only makes sense to be
  1277. // called in the context of advertising.
  1278. udid = [FBSDKAppEventsUtility advertiserID];
  1279. if (!udid) {
  1280. udid = [FBSDKAppEventsUtility attributionID];
  1281. }
  1282. if (!udid) {
  1283. // No udid, and no user token. No point in making the request.
  1284. return nil;
  1285. }
  1286. }
  1287. NSDictionary *parameters = nil;
  1288. if (udid) {
  1289. parameters = @{ @"udid" : udid };
  1290. }
  1291. NSString *graphPath = [NSString stringWithFormat:@"%@/custom_audience_third_party_id", [[self singleton] appID]];
  1292. FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath
  1293. parameters:parameters
  1294. tokenString:tokenString
  1295. HTTPMethod:nil
  1296. flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
  1297. return request;
  1298. }
  1299. @end