FIRIAMAnalyticsEventLoggerImpl.m 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 <TargetConditionals.h>
  17. #if TARGET_OS_IOS || TARGET_OS_TV || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
  18. #import <GoogleUtilities/GULUserDefaults.h>
  19. #import "FirebaseInAppMessaging/Sources/Analytics/FIRIAMAnalyticsEventLoggerImpl.h"
  20. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  21. #import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"
  22. #import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutLogger.h"
  23. #import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
  24. typedef void (^FIRAUserPropertiesCallback)(NSDictionary *userProperties);
  25. @interface FIRIAMAnalyticsEventLoggerImpl ()
  26. @property(readonly, nonatomic) FIRIAMClearcutLogger *clearCutLogger;
  27. @property(readonly, nonatomic) id<FIRIAMTimeFetcher> timeFetcher;
  28. @property(nonatomic, readonly) GULUserDefaults *userDefaults;
  29. @end
  30. // in these kFAXX constants, FA represents FirebaseAnalytics
  31. static NSString *const kFIREventOriginFIAM = @"fiam";
  32. ;
  33. static NSString *const kFAEventNameForImpression = @"firebase_in_app_message_impression";
  34. static NSString *const kFAEventNameForAction = @"firebase_in_app_message_action";
  35. static NSString *const kFAEventNameForDismiss = @"firebase_in_app_message_dismiss";
  36. // In order to support tracking conversions from clicking a fiam event, we need to set
  37. // an analytics user property with the fiam message's campaign id.
  38. // This is the user property as kFIRUserPropertyLastNotification defined for FCM.
  39. // Unlike FCM, FIAM would only allow the user property to exist up to certain expiration time
  40. // after which, we stop attributing any further conversions to that fiam message click.
  41. // So we include kFAUserPropertyPrefixForFIAM as the prefix for the entry written by fiam SDK
  42. // to avoid removing entries written by FCM SDK
  43. static NSString *const kFAUserPropertyForLastNotification = @"_ln";
  44. static NSString *const kFAUserPropertyPrefixForFIAM = @"fiam:";
  45. // This user defaults key is for the entry to tell when we should remove the private user
  46. // property from a prior action url click to stop conversion attribution for a campaign
  47. static NSString *const kFIAMUserDefaualtsKeyForRemoveUserPropertyTimeInSeconds =
  48. @"firebase-iam-conversion-tracking-expires-in-seconds";
  49. @implementation FIRIAMAnalyticsEventLoggerImpl {
  50. id<FIRAnalyticsInterop> _analytics;
  51. }
  52. - (instancetype)initWithClearcutLogger:(FIRIAMClearcutLogger *)ctLogger
  53. usingTimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
  54. usingUserDefaults:(nullable GULUserDefaults *)userDefaults
  55. analytics:(nullable id<FIRAnalyticsInterop>)analytics {
  56. if (self = [super init]) {
  57. _clearCutLogger = ctLogger;
  58. _timeFetcher = timeFetcher;
  59. _analytics = analytics;
  60. _userDefaults = userDefaults ? userDefaults : [GULUserDefaults standardUserDefaults];
  61. if (!_analytics) {
  62. FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM280002",
  63. @"Firebase In App Messaging was not configured with FirebaseAnalytics.");
  64. }
  65. }
  66. return self;
  67. }
  68. - (NSDictionary *)constructFAEventParamsWithCampaignID:(NSString *)campaignID
  69. campaignName:(NSString *)campaignName {
  70. // event parameter names are aligned with definitions in event_names_util.cc
  71. return @{
  72. @"_nmn" : campaignName ?: @"unknown",
  73. @"_nmid" : campaignID ?: @"unknown",
  74. @"_ndt" : @([self.timeFetcher currentTimestampInSeconds])
  75. };
  76. }
  77. - (void)logFAEventsForMessageImpressionWithcampaignID:(NSString *)campaignID
  78. campaignName:(NSString *)campaignName {
  79. if (_analytics) {
  80. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280001",
  81. @"Log campaign impression Firebase Analytics event for campaign ID %@", campaignID);
  82. NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
  83. campaignName:campaignName];
  84. [_analytics logEventWithOrigin:kFIREventOriginFIAM
  85. name:kFAEventNameForImpression
  86. parameters:params];
  87. }
  88. }
  89. - (BOOL)setAnalyticsUserPropertyForKey:(NSString *)key withValue:(NSString *)value {
  90. if (!_analytics || !key || !value) {
  91. return NO;
  92. }
  93. [_analytics setUserPropertyWithOrigin:kFIREventOriginFIAM name:key value:value];
  94. return YES;
  95. }
  96. - (void)logFAEventsForMessageActionWithCampaignID:(NSString *)campaignID
  97. campaignName:(NSString *)campaignName {
  98. if (_analytics) {
  99. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280004",
  100. @"Log action click Firebase Analytics event for campaign ID %@", campaignID);
  101. NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
  102. campaignName:campaignName];
  103. [_analytics logEventWithOrigin:kFIREventOriginFIAM
  104. name:kFAEventNameForAction
  105. parameters:params];
  106. }
  107. }
  108. - (void)logConversionTrackingEventForCampaignID:(NSString *)campaignID {
  109. // Set a special user property so that conversion events can be queried based on that
  110. // for reporting purposes.
  111. NSString *conversionTrackingUserPropertyValue =
  112. [NSString stringWithFormat:@"%@%@", kFAUserPropertyPrefixForFIAM, campaignID];
  113. if ([self setAnalyticsUserPropertyForKey:kFAUserPropertyForLastNotification
  114. withValue:conversionTrackingUserPropertyValue]) {
  115. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280009",
  116. @"User property for conversion tracking was set for campaign %@", campaignID);
  117. }
  118. }
  119. - (void)logFAEventsForMessageDismissWithcampaignID:(NSString *)campaignID
  120. campaignName:(NSString *)campaignName {
  121. if (_analytics) {
  122. FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280007",
  123. @"Log message dismiss Firebase Analytics event for campaign ID %@", campaignID);
  124. NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
  125. campaignName:campaignName];
  126. [_analytics logEventWithOrigin:kFIREventOriginFIAM
  127. name:kFAEventNameForDismiss
  128. parameters:params];
  129. }
  130. }
  131. - (void)logAnalyticsEventForType:(FIRIAMAnalyticsLogEventType)eventType
  132. forCampaignID:(NSString *)campaignID
  133. withCampaignName:(NSString *)campaignName
  134. eventTimeInMs:(nullable NSNumber *)eventTimeInMs
  135. completion:(void (^)(BOOL success))completion {
  136. // log Firebase Analytics event first
  137. if (eventType == FIRIAMAnalyticsEventMessageImpression) {
  138. [self logFAEventsForMessageImpressionWithcampaignID:campaignID campaignName:campaignName];
  139. } else if (eventType == FIRIAMAnalyticsEventActionURLFollow) {
  140. [self logFAEventsForMessageActionWithCampaignID:campaignID campaignName:campaignName];
  141. } else if (eventType == FIRIAMAnalyticsEventMessageDismissAuto ||
  142. eventType == FIRIAMAnalyticsEventMessageDismissClick) {
  143. [self logFAEventsForMessageDismissWithcampaignID:campaignID campaignName:campaignName];
  144. }
  145. // and do clearcut logging as well
  146. [self.clearCutLogger logAnalyticsEventForType:eventType
  147. forCampaignID:campaignID
  148. withCampaignName:campaignName
  149. eventTimeInMs:eventTimeInMs
  150. completion:completion];
  151. }
  152. @end
  153. #endif // TARGET_OS_IOS || TARGET_OS_TV || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)