FIRMessagingAnalytics.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FirebaseMessaging/Sources/FIRMessagingAnalytics.h"
  17. #import "GoogleUtilities/AppDelegateSwizzler/Private/GULAppDelegateSwizzler.h"
  18. #import "GoogleUtilities/Environment/Private/GULAppEnvironmentUtil.h"
  19. #import "Interop/Analytics/Public/FIRInteropEventNames.h"
  20. #import "Interop/Analytics/Public/FIRInteropParameterNames.h"
  21. #import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
  22. static NSString *const kLogTag = @"FIRMessagingAnalytics";
  23. // aps Key
  24. static NSString *const kApsKey = @"aps";
  25. static NSString *const kApsAlertKey = @"alert";
  26. static NSString *const kApsSoundKey = @"sound";
  27. static NSString *const kApsBadgeKey = @"badge";
  28. static NSString *const kApsContentAvailableKey = @"badge";
  29. // Data Key
  30. static NSString *const kDataKey = @"data";
  31. // Messaging From Key
  32. static NSString *const kFIRMessagingFromKey = @"from";
  33. static NSString *const kFIRParameterLabel = @"label";
  34. static NSString *const kReengagementSource = @"Firebase";
  35. static NSString *const kReengagementMedium = @"notification";
  36. // Analytics
  37. static NSString *const kAnalyticsEnabled = @"google.c.a."
  38. @"e";
  39. static NSString *const kAnalyticsComposerIdentifier = @"google.c.a."
  40. @"c_id";
  41. static NSString *const kAnalyticsComposerLabel = @"google.c.a."
  42. @"c_l";
  43. static NSString *const kAnalyticsMessageLabel = @"google.c.a."
  44. @"m_l";
  45. static NSString *const kAnalyticsMessageTimestamp = @"google.c.a."
  46. @"ts";
  47. static NSString *const kAnalyticsMessageUseDeviceTime = @"google.c.a."
  48. @"udt";
  49. static NSString *const kAnalyticsTrackConversions = @"google.c.a."
  50. @"tc";
  51. @implementation FIRMessagingAnalytics
  52. + (BOOL)canLogNotification:(NSDictionary *)notification {
  53. if (!notification.count) {
  54. // Payload is empty
  55. return NO;
  56. }
  57. NSString *isAnalyticsLoggingEnabled = notification[kAnalyticsEnabled];
  58. if (![isAnalyticsLoggingEnabled isKindOfClass:[NSString class]] ||
  59. ![isAnalyticsLoggingEnabled isEqualToString:@"1"]) {
  60. // Analytics logging is not enabled
  61. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics001,
  62. @"Analytics logging is disabled. Do not log event.");
  63. return NO;
  64. }
  65. return YES;
  66. }
  67. + (void)logOpenNotification:(NSDictionary *)notification
  68. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics {
  69. [self logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  70. [self logEvent:kFIRIEventNotificationOpen withNotification:notification toAnalytics:analytics];
  71. }
  72. + (void)logForegroundNotification:(NSDictionary *)notification
  73. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics {
  74. [self logEvent:kFIRIEventNotificationForeground
  75. withNotification:notification
  76. toAnalytics:analytics];
  77. }
  78. + (void)logEvent:(NSString *)event
  79. withNotification:(NSDictionary *)notification
  80. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics {
  81. if (!event.length) {
  82. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalyticsInvalidEvent,
  83. @"Can't log analytics with empty event.");
  84. return;
  85. }
  86. NSMutableDictionary *params = [self paramsForEvent:event withNotification:notification];
  87. [analytics logEventWithOrigin:@"fcm" name:event parameters:params];
  88. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics005, @"%@: Sending event: %@ params: %@",
  89. kLogTag, event, params);
  90. }
  91. + (NSMutableDictionary *)paramsForEvent:(NSString *)event
  92. withNotification:(NSDictionary *)notification {
  93. NSDictionary *analyticsDataMap = notification;
  94. if (!analyticsDataMap.count) {
  95. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics000,
  96. @"No data found in notification. Will not log any analytics events.");
  97. return nil;
  98. }
  99. if (![self canLogNotification:analyticsDataMap]) {
  100. return nil;
  101. }
  102. NSMutableDictionary *params = [NSMutableDictionary dictionary];
  103. NSString *composerIdentifier = analyticsDataMap[kAnalyticsComposerIdentifier];
  104. if ([composerIdentifier isKindOfClass:[NSString class]] && composerIdentifier.length) {
  105. params[kFIRIParameterMessageIdentifier] = [composerIdentifier copy];
  106. }
  107. NSString *composerLabel = analyticsDataMap[kAnalyticsComposerLabel];
  108. if ([composerLabel isKindOfClass:[NSString class]] && composerLabel.length) {
  109. params[kFIRIParameterMessageName] = [composerLabel copy];
  110. }
  111. NSString *messageLabel = analyticsDataMap[kAnalyticsMessageLabel];
  112. if ([messageLabel isKindOfClass:[NSString class]] && messageLabel.length) {
  113. params[kFIRParameterLabel] = [messageLabel copy];
  114. }
  115. NSString *from = analyticsDataMap[kFIRMessagingFromKey];
  116. if ([from isKindOfClass:[NSString class]] && [from containsString:@"/topics/"]) {
  117. params[kFIRIParameterTopic] = [from copy];
  118. }
  119. id timestamp = analyticsDataMap[kAnalyticsMessageTimestamp];
  120. if ([timestamp respondsToSelector:@selector(longLongValue)]) {
  121. int64_t timestampValue = [timestamp longLongValue];
  122. if (timestampValue != 0) {
  123. params[kFIRIParameterMessageTime] = @(timestampValue);
  124. }
  125. }
  126. if (analyticsDataMap[kAnalyticsMessageUseDeviceTime]) {
  127. params[kFIRIParameterMessageDeviceTime] = analyticsDataMap[kAnalyticsMessageUseDeviceTime];
  128. }
  129. return params;
  130. }
  131. + (void)logUserPropertyForConversionTracking:(NSDictionary *)notification
  132. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics {
  133. NSInteger shouldTrackConversions = [notification[kAnalyticsTrackConversions] integerValue];
  134. if (shouldTrackConversions != 1) {
  135. return;
  136. }
  137. NSString *composerIdentifier = notification[kAnalyticsComposerIdentifier];
  138. if ([composerIdentifier isKindOfClass:[NSString class]] && composerIdentifier.length) {
  139. // Set user property for event.
  140. [analytics setUserPropertyWithOrigin:@"fcm"
  141. name:kFIRIUserPropertyLastNotification
  142. value:composerIdentifier];
  143. // Set the re-engagement attribution properties.
  144. NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:3];
  145. params[kFIRIParameterSource] = kReengagementSource;
  146. params[kFIRIParameterMedium] = kReengagementMedium;
  147. params[kFIRIParameterCampaign] = composerIdentifier;
  148. [analytics logEventWithOrigin:@"fcm" name:kFIRIEventFirebaseCampaign parameters:params];
  149. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics003,
  150. @"%@: Sending event: %@ params: %@", kLogTag,
  151. kFIRIEventFirebaseCampaign, params);
  152. } else {
  153. FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics004,
  154. @"%@: Failed to set user property: %@ value: %@", kLogTag,
  155. kFIRIUserPropertyLastNotification, composerIdentifier);
  156. }
  157. }
  158. + (void)logMessage:(NSDictionary *)notification
  159. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics {
  160. // iOS onlly because Analytics doesn't support tvOS.
  161. #if TARGET_OS_IOS
  162. if (![self canLogNotification:notification]) {
  163. return;
  164. }
  165. UIApplication *application = [GULAppDelegateSwizzler sharedApplication];
  166. if (!application) {
  167. return;
  168. }
  169. UIApplicationState applicationState = application.applicationState;
  170. switch (applicationState) {
  171. case UIApplicationStateInactive:
  172. // App was either in background(suspended) or inactive and user tapped on a display
  173. // notification.
  174. [self logOpenNotification:notification toAnalytics:analytics];
  175. break;
  176. case UIApplicationStateActive:
  177. // App was in foreground when it received the notification.
  178. [self logForegroundNotification:notification toAnalytics:analytics];
  179. break;
  180. default:
  181. // Only a silent notification (i.e. 'content-available' is true) can be received while the app
  182. // is in the background. These messages aren't loggable anyway.
  183. break;
  184. }
  185. #endif
  186. }
  187. @end