Skip to content

Commit 523c270

Browse files
authored
Merge iam-master into iam-staging (#353)
* compile and run * unit tests pass and swift target compiles * dump build version in activity log * standardize cross sdk imports in firebase iam code (#211) standardize cross sdk imports & polish with style script * using new sample app for testing non-development fiam sdk (#213) * in-app messaging public interface cleanup (#216) * slim down public header files * move testing source files to their correct folders * compiles * style script fine-tune * adding root object creation methods to follow the firebse iOS convension * IAM url following refactor (#218) * @available not supported by blaze build yet (#220) * Clearcut integration for in-app messaging (#222) * Update iam-master to catch up with latest master (#223) * Support multiple triggers defined for the same iam message (#224) * FIAM Clearcut Client Implmentation Improvement (#226) * fixing action url bug and set auto dismiss to be 12 seconds (#227) * use official public api dns name (#233) * Logging firebase analytics events for fiam (#232) * Fine tuning of fiam's code for loading data from caches (#234) * fiam ui fine tuning before EAP (#235) * allow fiam SDK functions to be disabled/enabled dynamically (#247) * analytics event parameter name tuning (#253) * migrate off @import for fiam code (#261) * different modes for fiam sdk at runtime (#262) * realtime clearcut when in running in simulator (#265) * Update interface based on the Firebase API review feedback (#267) * check existence of fiam SDK resource bundle (#268) * handling api keys with application restrictions (#269) * fixing typo and refoctor for unit testing (#270) * fix color method name clash and layout adjust (#271) * Yongmao/layout issue and class rename (#273) * fix long text height calc error * rename class * fiam modal view layout tuning (#274) * test on device for ios client (#275) * dynamic testing mode handling (#277) * main header file comment update and run style.sh (#281) * honor global firebase auto data collection flag in fiam (#283) * honor global firebase auto data collection flag in fiam * address comments * tuning * address review comments * tuning for comments * Rename Core global data collection switch (#287) * Support displaying a messages defined as recurring (#286) * continue * Adjust some inapp messaging dependeces due to the firebase core changes from the upcoming release * bump up version for in-app messaging * Fix impression log clearing race condition bug. (#289) * fix impression handling race condition bug * podspec and interacting interfaces for new firebaseinappmessagingdisplay pod (#290) * create inapp messaging display podspec * Default fiam display UI implementation (#292) * Default fiam display UI implementation. Created the new pod for FirebaseInAppMessagingDisplay * Make FirebaseInAppMessaging headless (#293) * import path tuning * log test message events (#296) * respect fetch wait time from server (#297) * add changelog.md for fiam headless sdk (#300) * port the fetch wait time change back into github (#304) * remove resource bundle check for headless sdk * fix a bug in which the test-on-device message does not follow action url * Add category on NSString to interlace two strings, use it to obfuscate clearcut host name * Use FIR prefix to avoid collisions * Change method name for getting server hostname * Delete Swift example project, its coverage is already duplicated in the FIRInAppMessagingDisplay UITests * Miscellaneous open sourcing cleanup tasks * Convert FIAM to use the Analytics connector (#336) * Convert FIAM to use Analytics connector along with converting to the FIRLibrary component registration model. * Update interop headers for missing methods * Convert existing unit tests * Fix style for fiam sources (#342) * Clean up non-idiomatic ObjC method names * Clean up Swift test target from Podfile * Use dummy GoogleService-Info.plist and don't expose api keys (#343) * Update plist to include fake API keys * Remove changes in non fiam code from iam-master branch (#350) * Fix a few method and parameter naming nits * Fix comment typos in several files * Delete remaining Swift project files
1 parent faad116 commit 523c270

File tree

137 files changed

+15560
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+15560
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
17+
#import <Foundation/Foundation.h>
18+
#import "FIRIAMClientInfoFetcher.h"
19+
#import "FIRIAMTimeFetcher.h"
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
/// Values for different fiam activity types.
24+
typedef NS_ENUM(NSInteger, FIRIAMAnalyticsLogEventType) {
25+
26+
FIRIAMAnalyticsLogEventUnknown = -1,
27+
28+
FIRIAMAnalyticsEventMessageImpression = 0,
29+
FIRIAMAnalyticsEventActionURLFollow = 1,
30+
FIRIAMAnalyticsEventMessageDismissAuto = 2,
31+
FIRIAMAnalyticsEventMessageDismissClick = 3,
32+
FIRIAMAnalyticsEventMessageDismissSwipe = 4,
33+
34+
// category: errors happened
35+
FIRIAMAnalyticsEventImageFetchError = 11,
36+
FIRIAMAnalyticsEventImageFormatUnsupported = 12,
37+
38+
FIRIAMAnalyticsEventFetchAPINetworkError = 13,
39+
FIRIAMAnalyticsEventFetchAPIClientError = 14, // server returns 4xx status code
40+
FIRIAMAnalyticsEventFetchAPIServerError = 15, // server returns 5xx status code
41+
42+
// Events for test messages
43+
FIRIAMAnalyticsEventTestMessageImpression = 16,
44+
FIRIAMAnalyticsEventTestMessageClick = 17,
45+
};
46+
47+
// a protocol for collecting Analytics log records. It's implementation will decide
48+
// what to do with that analytics log record
49+
@protocol FIRIAMAnalyticsEventLogger
50+
/**
51+
* Adds an analytics log record.
52+
* @param eventTimeInMs the timestamp in ms for when the event happened.
53+
* if it's nil, the implementation will use the current system for this info.
54+
*/
55+
- (void)logAnalyticsEventForType:(FIRIAMAnalyticsLogEventType)eventType
56+
forCampaignID:(NSString *)campaignID
57+
withCampaignName:(NSString *)campaignName
58+
eventTimeInMs:(nullable NSNumber *)eventTimeInMs
59+
completion:(void (^)(BOOL success))completion;
60+
@end
61+
NS_ASSUME_NONNULL_END
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
17+
#import <Foundation/Foundation.h>
18+
19+
#import "FIRIAMAnalyticsEventLogger.h"
20+
21+
@class FIRIAMClearcutLogger;
22+
@protocol FIRIAMTimeFetcher;
23+
@protocol FIRAnalyticsInterop;
24+
25+
NS_ASSUME_NONNULL_BEGIN
26+
/**
27+
* Implementation of protocol FIRIAMAnalyticsEventLogger by doing two things
28+
* 1 Firing Firebase Analytics Events for impressions and clicks and dismisses
29+
* 2 Making clearcut logging for all other types of analytics events
30+
*/
31+
@interface FIRIAMAnalyticsEventLoggerImpl : NSObject <FIRIAMAnalyticsEventLogger>
32+
- (instancetype)init NS_UNAVAILABLE;
33+
34+
/**
35+
*
36+
* @param userDefaults needed for tracking upload timing info persistently.If nil, using
37+
* NSUserDefaults standardUserDefaults. It's defined as a parameter to help with
38+
* unit testing mocking
39+
* @param conversionExpiresInSeconds specifies the time-length in seconds when we stop
40+
* attribution conversions for a prior fiam message click from analytics perspective
41+
*/
42+
- (instancetype)initWithClearcutLogger:(FIRIAMClearcutLogger *)ctLogger
43+
usingTimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
44+
usingUserDefaults:(nullable NSUserDefaults *)userDefaults
45+
conversionExpires:(long)conversionExpiresInSeconds
46+
analytics:(nullable id<FIRAnalyticsInterop>)analytics;
47+
@end
48+
NS_ASSUME_NONNULL_END
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
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+
17+
#import "FIRIAMAnalyticsEventLoggerImpl.h"
18+
19+
#import <FirebaseAnalyticsInterop/FIRAnalyticsInterop.h>
20+
#import <FirebaseCore/FIRLogger.h>
21+
#import "FIRCore+InAppMessaging.h"
22+
#import "FIRIAMClearcutLogger.h"
23+
24+
typedef void (^FIRAUserPropertiesCallback)(NSDictionary *userProperties);
25+
26+
@interface FIRIAMAnalyticsEventLoggerImpl ()
27+
@property(readonly, nonatomic) FIRIAMClearcutLogger *clearCutLogger;
28+
@property(readonly, nonatomic) id<FIRIAMTimeFetcher> timeFetcher;
29+
@property(readonly, nonatomic) long conversionTrackingExpiresInSeconds;
30+
@property(nonatomic, readonly) NSUserDefaults *userDefaults;
31+
@end
32+
33+
// in these kFAXX constants, FA represents FirebaseAnalytics
34+
static NSString *const kFIREventOriginFIAM = @"fiam";
35+
;
36+
static NSString *const kFAEventNameForImpression = @"firebase_in_app_message_impression";
37+
static NSString *const kFAEventNameForAction = @"firebase_in_app_message_action";
38+
static NSString *const kFAEventNameForDismiss = @"firebase_in_app_message_dismiss";
39+
40+
// In order to support tracking conversions from clicking a fiam event, we need to set
41+
// an analytics user property with the fiam message's campaign id.
42+
// This is the user property as kFIRUserPropertyLastNotification defined for FCM.
43+
// Unlike FCM, FIAM would only allow the user property to exist up to certain expiration time
44+
// after which, we stop attributing any further conversions to that fiam message click.
45+
// So we include kFAUserPropertyPrefixForFIAM as the prefix for the entry written by fiam SDK
46+
// to avoid removing entries written by FCM SDK
47+
static NSString *const kFAUserPropertyForLastNotification = @"_ln";
48+
static NSString *const kFAUserPropertyPrefixForFIAM = @"fiam:";
49+
50+
// This user defaults key is for the entry to tell when we should remove the private user
51+
// property from a prior action url click to stop conversion attribution for a campaign
52+
static NSString *const kFIAMUserDefaualtsKeyForRemoveUserPropertyTimeInSeconds =
53+
@"firebase-iam-conversion-tracking-expires-in-seconds";
54+
55+
@implementation FIRIAMAnalyticsEventLoggerImpl {
56+
id<FIRAnalyticsInterop> _analytics;
57+
}
58+
59+
- (instancetype)initWithClearcutLogger:(FIRIAMClearcutLogger *)ctLogger
60+
usingTimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
61+
usingUserDefaults:(nullable NSUserDefaults *)userDefaults
62+
conversionExpires:(long)conversionExpiresInSeconds
63+
analytics:(nullable id<FIRAnalyticsInterop>)analytics {
64+
if (self = [super init]) {
65+
_clearCutLogger = ctLogger;
66+
_timeFetcher = timeFetcher;
67+
_analytics = analytics;
68+
_userDefaults = userDefaults ? userDefaults : [NSUserDefaults standardUserDefaults];
69+
70+
if (!_analytics) {
71+
FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM280002",
72+
@"Firebase In App Messaging was not configured with FirebaseAnalytics.");
73+
}
74+
_conversionTrackingExpiresInSeconds = conversionExpiresInSeconds;
75+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280003",
76+
@"Conversion tracking from a click expires in %ld seconds",
77+
conversionExpiresInSeconds);
78+
79+
// On startup, we make a check for conversion tracking expiration
80+
[self checkOnConversionTrackingExpiration];
81+
}
82+
return self;
83+
}
84+
85+
- (void)checkOnConversionTrackingExpiration {
86+
double expireTimeInSeconds =
87+
[_userDefaults doubleForKey:kFIAMUserDefaualtsKeyForRemoveUserPropertyTimeInSeconds];
88+
89+
double nowInSeconds = (double)[self.timeFetcher currentTimestampInSeconds];
90+
91+
if (expireTimeInSeconds < nowInSeconds) {
92+
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
93+
[_analytics
94+
checkLastNotificationForOrigin:kFIREventOriginFIAM
95+
queue:queue
96+
callback:^(NSString *_Nullable currentLastNotificationProperty) {
97+
if (currentLastNotificationProperty) {
98+
if ([self setAnalyticsUserPropertyForKey:
99+
kFAUserPropertyForLastNotification
100+
withValue:@"empty"]) {
101+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280005",
102+
@"User property for conversion tracking has "
103+
@"expired, set to be empty");
104+
}
105+
}
106+
}];
107+
}
108+
}
109+
110+
- (NSDictionary *)constructFAEventParamsWithCampaignID:(NSString *)campaignID
111+
campaignName:(NSString *)campaignName {
112+
// event parameter names are aligned with definitions in event_names_util.cc
113+
return @{
114+
@"_nmn" : campaignName ?: @"unknown",
115+
@"_nmid" : campaignID ?: @"unknown",
116+
@"_ndt" : @([self.timeFetcher currentTimestampInSeconds])
117+
};
118+
}
119+
120+
- (void)logFAEventsForMessageImpressionWithcampaignID:(NSString *)campaignID
121+
campaignName:(NSString *)campaignName {
122+
if (_analytics) {
123+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280001",
124+
@"Log campaign impression Firebase Analytics event for campaign ID %@", campaignID);
125+
126+
NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
127+
campaignName:campaignName];
128+
[_analytics logEventWithOrigin:kFIREventOriginFIAM
129+
name:kFAEventNameForImpression
130+
parameters:params];
131+
}
132+
}
133+
134+
- (BOOL)setAnalyticsUserPropertyForKey:(NSString *)key withValue:(NSString *)value {
135+
if (!_analytics || !key || !value) {
136+
return NO;
137+
}
138+
[_analytics setUserPropertyWithOrigin:kFIREventOriginFIAM name:key value:value];
139+
return YES;
140+
}
141+
142+
- (void)logFAEventsForMessageActionWithCampaignID:(NSString *)campaignID
143+
campaignName:(NSString *)campaignName {
144+
if (_analytics) {
145+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280004",
146+
@"Log action click Firebase Analytics event for campaign ID %@", campaignID);
147+
148+
NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
149+
campaignName:campaignName];
150+
151+
[_analytics logEventWithOrigin:kFIREventOriginFIAM
152+
name:kFAEventNameForAction
153+
parameters:params];
154+
}
155+
156+
// set a special user property so that conversion events can be queried based on that
157+
// for reporting purpose
158+
NSString *conversionTrackingUserPropertyValue =
159+
[NSString stringWithFormat:@"%@%@", kFAUserPropertyPrefixForFIAM, campaignID];
160+
161+
if ([self setAnalyticsUserPropertyForKey:kFAUserPropertyForLastNotification
162+
withValue:conversionTrackingUserPropertyValue]) {
163+
// reset the user property expiration time
164+
long expirationTime = (long)[self.timeFetcher currentTimestampInSeconds] +
165+
self.conversionTrackingExpiresInSeconds;
166+
167+
[_userDefaults setDouble:expirationTime
168+
forKey:kFIAMUserDefaualtsKeyForRemoveUserPropertyTimeInSeconds];
169+
170+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280009",
171+
@"User property for conversion tracking was set for campaign %@ "
172+
"and expires at epoch time in seconds %ld",
173+
campaignID, expirationTime);
174+
}
175+
}
176+
177+
- (void)logFAEventsForMessageDismissWithcampaignID:(NSString *)campaignID
178+
campaignName:(NSString *)campaignName {
179+
if (_analytics) {
180+
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM280007",
181+
@"Log message dismiss Firebase Analytics event for campaign ID %@", campaignID);
182+
183+
NSDictionary *params = [self constructFAEventParamsWithCampaignID:campaignID
184+
campaignName:campaignName];
185+
[_analytics logEventWithOrigin:kFIREventOriginFIAM
186+
name:kFAEventNameForDismiss
187+
parameters:params];
188+
}
189+
}
190+
191+
- (void)logAnalyticsEventForType:(FIRIAMAnalyticsLogEventType)eventType
192+
forCampaignID:(NSString *)campaignID
193+
withCampaignName:(NSString *)campaignName
194+
eventTimeInMs:(nullable NSNumber *)eventTimeInMs
195+
completion:(void (^)(BOOL success))completion {
196+
// log Firebase Analytics event first
197+
if (eventType == FIRIAMAnalyticsEventMessageImpression) {
198+
[self logFAEventsForMessageImpressionWithcampaignID:campaignID campaignName:campaignName];
199+
} else if (eventType == FIRIAMAnalyticsEventActionURLFollow) {
200+
[self logFAEventsForMessageActionWithCampaignID:campaignID campaignName:campaignName];
201+
} else if (eventType == FIRIAMAnalyticsEventMessageDismissAuto ||
202+
eventType == FIRIAMAnalyticsEventMessageDismissClick) {
203+
[self logFAEventsForMessageDismissWithcampaignID:campaignID campaignName:campaignName];
204+
}
205+
206+
// and do clearcut logging as well
207+
[self.clearCutLogger logAnalyticsEventForType:eventType
208+
forCampaignID:campaignID
209+
withCampaignName:campaignName
210+
eventTimeInMs:eventTimeInMs
211+
completion:completion];
212+
}
213+
@end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
17+
#import <Foundation/Foundation.h>
18+
19+
@class FIRIAMClearcutLogRecord;
20+
@protocol FIRIAMTimeFetcher;
21+
22+
NS_ASSUME_NONNULL_BEGIN
23+
// class for sending requests to clearcut over its http API
24+
@interface FIRIAMClearcutHttpRequestSender : NSObject
25+
26+
/**
27+
* Create an FIRIAMClearcutHttpRequestSender instance with specified clearcut server.
28+
*
29+
* @param serverHost API server host.
30+
* @param osMajorVersion detected iOS major version of the current device
31+
*/
32+
- (instancetype)initWithClearcutHost:(NSString *)serverHost
33+
usingTimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
34+
withOSMajorVersion:(NSString *)osMajorVersion;
35+
36+
/**
37+
* Sends a batch of FIRIAMClearcutLogRecord records to clearcut server.
38+
* @param logs an array of log records to be sent.
39+
* @param completion is the handler to triggered upon completion. 'success' is a bool
40+
* to indicate if the sending is successful. 'shouldRetryLogs' indicates if these
41+
* logs need to be retried later on. On success case, waitTimeInMills is the value
42+
* returned from clearcut server to indicate the minimal wait time before another
43+
* send request can be attempted.
44+
*/
45+
46+
- (void)sendClearcutHttpRequestForLogs:(NSArray<FIRIAMClearcutLogRecord *> *)logs
47+
withCompletion:(void (^)(BOOL success,
48+
BOOL shouldRetryLogs,
49+
int64_t waitTimeInMills))completion;
50+
@end
51+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)