Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2017 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 <TargetConditionals.h>
18
#if TARGET_OS_IOS || TARGET_OS_TV
19
 
20
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
21
 
22
#import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"
23
#import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutLogger.h"
24
#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMFetchFlow.h"
25
#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMRuntimeManager.h"
26
 
27
@implementation FIRIAMFetchSetting
28
@end
29
 
30
// the notification message to say that the fetch flow is done
31
NSString *const kFIRIAMFetchIsDoneNotification = @"FIRIAMFetchIsDoneNotification";
32
 
33
@interface FIRIAMFetchFlow ()
34
@property(nonatomic) id<FIRIAMTimeFetcher> timeFetcher;
35
@property(nonatomic) NSTimeInterval lastFetchTime;
36
@property(nonatomic, nonnull, readonly) FIRIAMFetchSetting *setting;
37
@property(nonatomic, nonnull, readonly) FIRIAMMessageClientCache *messageCache;
38
@property(nonatomic) id<FIRIAMMessageFetcher> messageFetcher;
39
@property(nonatomic, nonnull, readonly) id<FIRIAMBookKeeper> fetchBookKeeper;
40
@property(nonatomic, nonnull, readonly) FIRIAMActivityLogger *activityLogger;
41
@property(nonatomic, nonnull, readonly) id<FIRIAMAnalyticsEventLogger> analyticsEventLogger;
42
@property(nonatomic, nonnull, readonly) FIRIAMSDKModeManager *sdkModeManager;
43
@property(nonatomic, nonnull, readonly) FIRIAMDisplayExecutor *displayExecutor;
44
 
45
@end
46
 
47
@implementation FIRIAMFetchFlow
48
- (instancetype)initWithSetting:(FIRIAMFetchSetting *)setting
49
                   messageCache:(FIRIAMMessageClientCache *)cache
50
                 messageFetcher:(id<FIRIAMMessageFetcher>)messageFetcher
51
                    timeFetcher:(id<FIRIAMTimeFetcher>)timeFetcher
52
                     bookKeeper:(id<FIRIAMBookKeeper>)fetchBookKeeper
53
                 activityLogger:(FIRIAMActivityLogger *)activityLogger
54
           analyticsEventLogger:(id<FIRIAMAnalyticsEventLogger>)analyticsEventLogger
55
           FIRIAMSDKModeManager:(FIRIAMSDKModeManager *)sdkModeManager
56
                displayExecutor:(FIRIAMDisplayExecutor *)displayExecutor {
57
  if (self = [super init]) {
58
    _timeFetcher = timeFetcher;
59
    _lastFetchTime = [fetchBookKeeper lastFetchTime];
60
    _setting = setting;
61
    _messageCache = cache;
62
    _messageFetcher = messageFetcher;
63
    _fetchBookKeeper = fetchBookKeeper;
64
    _activityLogger = activityLogger;
65
    _analyticsEventLogger = analyticsEventLogger;
66
    _sdkModeManager = sdkModeManager;
67
    _displayExecutor = displayExecutor;
68
  }
69
  return self;
70
}
71
 
72
- (FIRIAMAnalyticsLogEventType)fetchErrorToLogEventType:(NSError *)error {
73
  if ([error.domain isEqual:NSURLErrorDomain]) {
74
    if (error.code == NSURLErrorNotConnectedToInternet) {
75
      return FIRIAMAnalyticsEventFetchAPINetworkError;
76
    } else {
77
      // error.code could be a non 2xx status code
78
      if (error.code > 0) {
79
        if (error.code >= 400 && error.code < 500) {
80
          return FIRIAMAnalyticsEventFetchAPIClientError;
81
        } else {
82
          if (error.code >= 500 && error.code < 600) {
83
            return FIRIAMAnalyticsEventFetchAPIServerError;
84
          }
85
        }
86
      }
87
    }
88
  }
89
 
90
  return FIRIAMAnalyticsLogEventUnknown;
91
}
92
 
93
- (void)sendFetchIsDoneNotification {
94
  [[NSNotificationCenter defaultCenter] postNotificationName:kFIRIAMFetchIsDoneNotification
95
                                                      object:self];
96
}
97
 
98
- (void)handleSuccessullyFetchedMessages:(NSArray<FIRIAMMessageDefinition *> *)messagesInResponse
99
                       withFetchWaitTime:(NSNumber *_Nullable)fetchWaitTime
100
                      requestImpressions:(NSArray<FIRIAMImpressionRecord *> *)requestImpressions {
101
  FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700004", @"%lu messages were fetched successfully.",
102
              (unsigned long)messagesInResponse.count);
103
 
104
  for (FIRIAMMessageDefinition *next in messagesInResponse) {
105
    if (next.isTestMessage && self.sdkModeManager.currentMode != FIRIAMSDKModeTesting) {
106
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700006",
107
                  @"Seeing test message in fetch response. Turn "
108
                   "the current instance into a testing instance.");
109
      [self.sdkModeManager becomeTestingInstance];
110
    }
111
  }
112
 
113
  NSArray<NSString *> *responseMessageIDs =
114
      [messagesInResponse valueForKeyPath:@"renderData.messageID"];
115
  NSArray<NSString *> *impressionMessageIDs = [requestImpressions valueForKey:@"messageID"];
116
 
117
  // We are going to clear impression records for those IDs that are in both impressionMessageIDs
118
  // and responseMessageIDs. This is to avoid incorrectly clearing impressions records that come
119
  // in between the sending the request and receiving the response for the fetch operation.
120
  // So we are computing intersection between responseMessageIDs and impressionMessageIDs and use
121
  // that for impression log clearing.
122
  NSMutableSet *idIntersection = [NSMutableSet setWithArray:responseMessageIDs];
123
  [idIntersection intersectSet:[NSSet setWithArray:impressionMessageIDs]];
124
 
125
  [self.fetchBookKeeper clearImpressionsWithMessageList:[idIntersection allObjects]];
126
  [self.messageCache setMessageData:messagesInResponse];
127
 
128
  [self.sdkModeManager registerOneMoreFetch];
129
  [self.fetchBookKeeper recordNewFetchWithFetchCount:messagesInResponse.count
130
                              withTimestampInSeconds:[self.timeFetcher currentTimestampInSeconds]
131
                                   nextFetchWaitTime:fetchWaitTime];
132
}
133
 
134
- (void)checkAndFetchForInitialAppLaunch:(BOOL)forInitialAppLaunch {
135
  NSTimeInterval intervalFromLastFetchInSeconds =
136
      [self.timeFetcher currentTimestampInSeconds] - self.fetchBookKeeper.lastFetchTime;
137
 
138
  FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700005",
139
              @"Interval from last time fetch is %lf seconds", intervalFromLastFetchInSeconds);
140
 
141
  BOOL fetchIsAllowedNow = NO;
142
 
143
  if (intervalFromLastFetchInSeconds >= self.fetchBookKeeper.nextFetchWaitTime) {
144
    // it's enough wait time interval from last fetch.
145
    fetchIsAllowedNow = YES;
146
  } else {
147
    FIRIAMSDKMode sdkMode = [self.sdkModeManager currentMode];
148
    if (sdkMode == FIRIAMSDKModeNewlyInstalled || sdkMode == FIRIAMSDKModeTesting) {
149
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700007",
150
                  @"OK to fetch due to current SDK mode being %@",
151
                  FIRIAMDescriptonStringForSDKMode(sdkMode));
152
      fetchIsAllowedNow = YES;
153
    } else {
154
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700008",
155
                  @"Interval from last time fetch is %lf seconds, smaller than fetch wait time %lf",
156
                  intervalFromLastFetchInSeconds, self.fetchBookKeeper.nextFetchWaitTime);
157
    }
158
  }
159
 
160
  if (fetchIsAllowedNow) {
161
    // we are allowed to fetch in-app message from time interval wise
162
 
163
    FIRIAMActivityRecord *record =
164
        [[FIRIAMActivityRecord alloc] initWithActivityType:FIRIAMActivityTypeCheckForFetch
165
                                              isSuccessful:YES
166
                                                withDetail:@"OK to do a fetch"
167
                                                 timestamp:nil];
168
    [self.activityLogger addLogRecord:record];
169
 
170
    NSArray<FIRIAMImpressionRecord *> *impressions = [self.fetchBookKeeper getImpressions];
171
    FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700001", @"Go ahead to fetch messages");
172
 
173
    NSTimeInterval fetchStartTime = [[NSDate date] timeIntervalSince1970];
174
 
175
    [self.messageFetcher
176
        fetchMessagesWithImpressionList:impressions
177
                         withCompletion:^(NSArray<FIRIAMMessageDefinition *> *_Nullable messages,
178
                                          NSNumber *_Nullable nextFetchWaitTime,
179
                                          NSInteger discardedMessageCount,
180
                                          NSError *_Nullable error) {
181
                           if (error) {
182
                             FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM700002",
183
                                           @"Error happened during message fetching %@", error);
184
 
185
                             FIRIAMAnalyticsLogEventType eventType =
186
                                 [self fetchErrorToLogEventType:error];
187
 
188
                             [self.analyticsEventLogger logAnalyticsEventForType:eventType
189
                                                                   forCampaignID:@"all"
190
                                                                withCampaignName:@"all"
191
                                                                   eventTimeInMs:nil
192
                                                                      completion:^(BOOL success){
193
                                                                          // nothing to do
194
                                                                      }];
195
 
196
                             FIRIAMActivityRecord *record = [[FIRIAMActivityRecord alloc]
197
                                 initWithActivityType:FIRIAMActivityTypeFetchMessage
198
                                         isSuccessful:NO
199
                                           withDetail:error.description
200
                                            timestamp:nil];
201
                             [self.activityLogger addLogRecord:record];
202
                           } else {
203
                             double fetchOperationLatencyInMills =
204
                                 ([[NSDate date] timeIntervalSince1970] - fetchStartTime) * 1000;
205
                             NSString *impressionListString =
206
                                 [impressions componentsJoinedByString:@","];
207
                             NSString *activityLogDetail = @"";
208
 
209
                             if (discardedMessageCount > 0) {
210
                               activityLogDetail = [NSString
211
                                   stringWithFormat:
212
                                       @"%lu messages fetched with impression list as [%@]"
213
                                        " and %lu messages are discarded due to data being "
214
                                        "invalid. It took"
215
                                        " %lf milliseconds",
216
                                       (unsigned long)messages.count, impressionListString,
217
                                       (unsigned long)discardedMessageCount,
218
                                       fetchOperationLatencyInMills];
219
                             } else {
220
                               activityLogDetail = [NSString
221
                                   stringWithFormat:
222
                                       @"%lu messages fetched with impression list as [%@]. It took"
223
                                        " %lf milliseconds",
224
                                       (unsigned long)messages.count, impressionListString,
225
                                       fetchOperationLatencyInMills];
226
                             }
227
 
228
                             FIRIAMActivityRecord *record = [[FIRIAMActivityRecord alloc]
229
                                 initWithActivityType:FIRIAMActivityTypeFetchMessage
230
                                         isSuccessful:YES
231
                                           withDetail:activityLogDetail
232
                                            timestamp:nil];
233
                             [self.activityLogger addLogRecord:record];
234
 
235
                             // Now handle the fetched messages.
236
                             [self handleSuccessullyFetchedMessages:messages
237
                                                  withFetchWaitTime:nextFetchWaitTime
238
                                                 requestImpressions:impressions];
239
 
240
                             if (forInitialAppLaunch) {
241
                               [self checkForAppLaunchMessage];
242
                             }
243
                           }
244
                           // Send this regardless whether fetch is successful or not.
245
                           [self sendFetchIsDoneNotification];
246
                         }];
247
 
248
  } else {
249
    FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM700003",
250
                @"Only %lf seconds from last fetch time. No action.",
251
                intervalFromLastFetchInSeconds);
252
    // for no fetch case, we still send out the notification so that and display flow can continue
253
    // from here.
254
    [self sendFetchIsDoneNotification];
255
    FIRIAMActivityRecord *record =
256
        [[FIRIAMActivityRecord alloc] initWithActivityType:FIRIAMActivityTypeCheckForFetch
257
                                              isSuccessful:NO
258
                                                withDetail:@"Abort due to check time interval "
259
                                                            "not reached yet"
260
                                                 timestamp:nil];
261
    [self.activityLogger addLogRecord:record];
262
  }
263
}
264
 
265
- (void)checkForAppLaunchMessage {
266
  [self.displayExecutor checkAndDisplayNextAppLaunchMessage];
267
}
268
@end
269
 
270
#endif  // TARGET_OS_IOS || TARGET_OS_TV