Skip to content

Commit 3905bd2

Browse files
christibbspaulb777
authored andcommitted
Open source FIAM headless SDK (#2312)
1 parent a43709f commit 3905bd2

File tree

137 files changed

+15462
-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

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