PageRenderTime 24ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.m

https://gitlab.com/daniel.colceag/MonkeyNews
Objective C | 313 lines | 240 code | 45 blank | 28 comment | 32 complexity | 418af460e10b8f2d7bbc85a4386c8fcd 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 "FBSDKAppEventsUtility.h"
  19. #import <AdSupport/AdSupport.h>
  20. #import "FBSDKAccessToken.h"
  21. #import "FBSDKAppEvents.h"
  22. #import "FBSDKAppEventsDeviceInfo.h"
  23. #import "FBSDKConstants.h"
  24. #import "FBSDKDynamicFrameworkLoader.h"
  25. #import "FBSDKError.h"
  26. #import "FBSDKInternalUtility.h"
  27. #import "FBSDKLogger.h"
  28. #import "FBSDKMacros.h"
  29. #import "FBSDKSettings.h"
  30. #import "FBSDKTimeSpentData.h"
  31. #define FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME @"com-facebook-sdk-PersistedAnonymousID.json"
  32. #define FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY @"anon_id"
  33. #define FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH 40
  34. @implementation FBSDKAppEventsUtility
  35. + (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
  36. implicitEventsOnly:(BOOL)implicitEventsOnly
  37. shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID {
  38. NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
  39. parameters[@"event"] = eventCategory;
  40. NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below.
  41. [FBSDKInternalUtility dictionary:parameters setObject:attributionID forKey:@"attribution"];
  42. if (!implicitEventsOnly && shouldAccessAdvertisingID) {
  43. NSString *advertiserID = [[self class] advertiserID];
  44. [FBSDKInternalUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"];
  45. }
  46. parameters[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY] = [self anonymousID];
  47. FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus];
  48. if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) {
  49. BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed);
  50. parameters[@"advertiser_tracking_enabled"] = [@(allowed) stringValue];
  51. }
  52. parameters[@"application_tracking_enabled"] = [@(!FBSDKSettings.limitEventAndDataUsage) stringValue];
  53. [FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters];
  54. static dispatch_once_t fetchBundleOnce;
  55. static NSMutableArray *urlSchemes;
  56. dispatch_once(&fetchBundleOnce, ^{
  57. NSBundle *mainBundle = [NSBundle mainBundle];
  58. urlSchemes = [[NSMutableArray alloc] init];
  59. for (NSDictionary *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) {
  60. NSArray *schemesForType = [fields objectForKey:@"CFBundleURLSchemes"];
  61. if (schemesForType) {
  62. [urlSchemes addObjectsFromArray:schemesForType];
  63. }
  64. }
  65. });
  66. if (urlSchemes.count > 0) {
  67. [parameters setObject:[FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL]
  68. forKey:@"url_schemes"];
  69. }
  70. return parameters;
  71. }
  72. + (NSString *)advertiserID
  73. {
  74. NSString *result = nil;
  75. Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass();
  76. if ([ASIdentifierManagerClass class]) {
  77. ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
  78. result = [[manager advertisingIdentifier] UUIDString];
  79. }
  80. return result;
  81. }
  82. + (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus
  83. {
  84. static dispatch_once_t fetchAdvertisingTrackingStatusOnce;
  85. static FBSDKAdvertisingTrackingStatus status;
  86. dispatch_once(&fetchAdvertisingTrackingStatusOnce, ^{
  87. status = FBSDKAdvertisingTrackingUnspecified;
  88. Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass();
  89. if ([ASIdentifierManagerClass class]) {
  90. ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
  91. if (manager) {
  92. status = [manager isAdvertisingTrackingEnabled] ? FBSDKAdvertisingTrackingAllowed : FBSDKAdvertisingTrackingDisallowed;
  93. }
  94. }
  95. });
  96. return status;
  97. }
  98. + (NSString *)anonymousID
  99. {
  100. // Grab previously written anonymous ID and, if none have been generated, create and
  101. // persist a new one which will remain associated with this app.
  102. NSString *result = [[self class] retrievePersistedAnonymousID];
  103. if (!result) {
  104. // Generate a new anonymous ID. Create as a UUID, but then prepend the fairly
  105. // arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which
  106. // will only contain hex.
  107. result = [NSString stringWithFormat:@"XZ%@", [[NSUUID UUID] UUIDString]];
  108. [self persistAnonymousID:result];
  109. }
  110. return result;
  111. }
  112. + (NSString *)attributionID
  113. {
  114. #if TARGET_OS_TV
  115. return nil;
  116. #else
  117. return [[UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO] string];
  118. #endif
  119. }
  120. // for tests only.
  121. + (void)clearLibraryFiles
  122. {
  123. [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
  124. error:NULL];
  125. [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDKTimeSpentFilename]
  126. error:NULL];
  127. }
  128. + (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className
  129. {
  130. FBSDKConditionalLog([NSThread isMainThread],
  131. FBSDKLoggingBehaviorDeveloperErrors,
  132. @"*** <%@, %@> is not called on the main thread. This can lead to errors.",
  133. methodName,
  134. className);
  135. }
  136. + (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason
  137. {
  138. NSString *result = @"Unknown";
  139. switch (flushReason) {
  140. case FBSDKAppEventsFlushReasonExplicit:
  141. result = @"Explicit";
  142. break;
  143. case FBSDKAppEventsFlushReasonTimer:
  144. result = @"Timer";
  145. break;
  146. case FBSDKAppEventsFlushReasonSessionChange:
  147. result = @"SessionChange";
  148. break;
  149. case FBSDKAppEventsFlushReasonPersistedEvents:
  150. result = @"PersistedEvents";
  151. break;
  152. case FBSDKAppEventsFlushReasonEventThreshold:
  153. result = @"EventCountThreshold";
  154. break;
  155. case FBSDKAppEventsFlushReasonEagerlyFlushingEvent:
  156. result = @"EagerlyFlushingEvent";
  157. break;
  158. }
  159. return result;
  160. }
  161. + (void)logAndNotify:(NSString *)msg
  162. {
  163. [[self class] logAndNotify:msg allowLogAsDeveloperError:YES];
  164. }
  165. + (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError
  166. {
  167. NSString *behaviorToLog = FBSDKLoggingBehaviorAppEvents;
  168. if (allowLogAsDeveloperError) {
  169. if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorDeveloperErrors]) {
  170. // Rather than log twice, prefer 'DeveloperErrors' if it's set over AppEvents.
  171. behaviorToLog = FBSDKLoggingBehaviorDeveloperErrors;
  172. }
  173. }
  174. [FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg];
  175. NSError *error = [FBSDKError errorWithCode:FBSDKAppEventsFlushErrorCode message:msg];
  176. [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
  177. }
  178. + (BOOL)regexValidateIdentifier:(NSString *)identifier
  179. {
  180. static NSRegularExpression *regex;
  181. static dispatch_once_t onceToken;
  182. static NSMutableSet *cachedIdentifiers;
  183. dispatch_once(&onceToken, ^{
  184. NSString *regexString = @"^[0-9a-zA-Z_]+[0-9a-zA-Z _-]*$";
  185. regex = [NSRegularExpression regularExpressionWithPattern:regexString
  186. options:0
  187. error:NULL];
  188. cachedIdentifiers = [[NSMutableSet alloc] init];
  189. });
  190. @synchronized(self) {
  191. if (![cachedIdentifiers containsObject:identifier]) {
  192. NSUInteger numMatches = [regex numberOfMatchesInString:identifier options:0 range:NSMakeRange(0, identifier.length)];
  193. if (numMatches > 0) {
  194. [cachedIdentifiers addObject:identifier];
  195. } else {
  196. return NO;
  197. }
  198. }
  199. }
  200. return YES;
  201. }
  202. + (BOOL)validateIdentifier:(NSString *)identifier
  203. {
  204. if (identifier == nil || identifier.length == 0 || identifier.length > FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH || ![[self class] regexValidateIdentifier:identifier]) {
  205. [[self class] logAndNotify:[NSString stringWithFormat:@"Invalid identifier: '%@'. Must be between 1 and %d characters, and must be contain only alphanumerics, _, - or spaces, starting with alphanumeric or _.",
  206. identifier, FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH]];
  207. return NO;
  208. }
  209. return YES;
  210. }
  211. + (void)persistAnonymousID:(NSString *)anonymousID
  212. {
  213. [[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
  214. NSDictionary *data = @{ FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY : anonymousID };
  215. NSString *content = [FBSDKInternalUtility JSONStringForObject:data error:NULL invalidObjectHandler:NULL];
  216. [content writeToFile:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
  217. atomically:YES
  218. encoding:NSASCIIStringEncoding
  219. error:nil];
  220. }
  221. + (NSString *)persistenceFilePath:(NSString *)filename
  222. {
  223. NSSearchPathDirectory directory = NSLibraryDirectory;
  224. NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
  225. NSString *docDirectory = [paths objectAtIndex:0];
  226. return [docDirectory stringByAppendingPathComponent:filename];
  227. }
  228. + (NSString *)retrievePersistedAnonymousID
  229. {
  230. [[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
  231. NSString *file = [[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME];
  232. NSString *content = [[NSString alloc] initWithContentsOfFile:file
  233. encoding:NSASCIIStringEncoding
  234. error:nil];
  235. NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
  236. return [results objectForKey:FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY];
  237. }
  238. // Given a candidate token (which may be nil), find the real token to string to use.
  239. // Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session.
  240. + (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token
  241. {
  242. if (!token) {
  243. token = [FBSDKAccessToken currentAccessToken];
  244. }
  245. NSString *appID = [FBSDKAppEvents loggingOverrideAppID] ?: token.appID ?: [FBSDKSettings appID];
  246. NSString *tokenString = token.tokenString;
  247. if (!tokenString || ![appID isEqualToString:token.appID]) {
  248. // If there's an logging override app id present, then we don't want to use the client token since the client token
  249. // is intended to match up with the primary app id (and AppEvents doesn't require a client token).
  250. NSString *clientTokenString = [FBSDKSettings clientToken];
  251. if (clientTokenString && appID && [appID isEqualToString:token.appID]){
  252. tokenString = [NSString stringWithFormat:@"%@|%@", appID, clientTokenString];
  253. } else if (appID) {
  254. tokenString = nil;
  255. }
  256. }
  257. return tokenString;
  258. }
  259. + (long)unixTimeNow
  260. {
  261. return (long)round([[NSDate date] timeIntervalSince1970]);
  262. }
  263. - (instancetype)init
  264. {
  265. FBSDK_NO_DESIGNATED_INITIALIZER();
  266. return nil;
  267. }
  268. @end