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/Flows/FIRIAMBookKeeper.h"
24
 
25
NSString *const FIRIAM_UserDefaultsKeyForImpressions = @"firebase-iam-message-impressions";
26
NSString *const FIRIAM_UserDefaultsKeyForLastImpressionTimestamp =
27
    @"firebase-iam-last-impression-timestamp";
28
NSString *FIRIAM_UserDefaultsKeyForLastFetchTimestamp = @"firebase-iam-last-fetch-timestamp";
29
 
30
// The two keys used to map FIRIAMImpressionRecord object to a NSDictionary object for
31
// persistence.
32
NSString *const FIRIAM_ImpressionDictKeyForID = @"message_id";
33
NSString *const FIRIAM_ImpressionDictKeyForTimestamp = @"impression_time";
34
 
35
static NSString *const kUserDefaultsKeyForFetchWaitTime = @"firebase-iam-fetch-wait-time";
36
 
37
// 24 hours
38
static NSTimeInterval kDefaultFetchWaitTimeInSeconds = 24 * 60 * 60;
39
 
40
// 3 days
41
static NSTimeInterval kMaxFetchWaitTimeInSeconds = 3 * 24 * 60 * 60;
42
 
43
@interface FIRIAMBookKeeperViaUserDefaults ()
44
@property(nonatomic) double lastDisplayTime;
45
@property(nonatomic) double lastFetchTime;
46
@property(nonatomic) double nextFetchWaitTime;
47
@property(nonatomic, nonnull) NSUserDefaults *defaults;
48
@end
49
 
50
@interface FIRIAMImpressionRecord ()
51
- (instancetype)initWithStorageDictionary:(NSDictionary *)dict;
52
@end
53
 
54
@implementation FIRIAMImpressionRecord
55
 
56
- (instancetype)initWithMessageID:(NSString *)messageID
57
          impressionTimeInSeconds:(long)impressionTime {
58
  if (self = [super init]) {
59
    _messageID = messageID;
60
    _impressionTimeInSeconds = impressionTime;
61
  }
62
  return self;
63
}
64
 
65
- (instancetype)initWithStorageDictionary:(NSDictionary *)dict {
66
  id timestamp = dict[FIRIAM_ImpressionDictKeyForTimestamp];
67
  id messageID = dict[FIRIAM_ImpressionDictKeyForID];
68
 
69
  if (![timestamp isKindOfClass:[NSNumber class]] || ![messageID isKindOfClass:[NSString class]]) {
70
    FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270003",
71
                @"Incorrect data in the dictionary object for creating a FIRIAMImpressionRecord"
72
                 " object");
73
    return nil;
74
  } else {
75
    return [self initWithMessageID:messageID
76
           impressionTimeInSeconds:((NSNumber *)timestamp).longValue];
77
  }
78
}
79
 
80
- (NSString *)description {
81
  return [NSString stringWithFormat:@"%@ impressed at %ld in seconds", self.messageID,
82
                                    self.impressionTimeInSeconds];
83
}
84
@end
85
 
86
@implementation FIRIAMBookKeeperViaUserDefaults
87
 
88
- (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults {
89
  if (self = [super init]) {
90
    _defaults = userDefaults;
91
 
92
    // ok if it returns 0 due to the entry being absent
93
    _lastDisplayTime = [_defaults doubleForKey:FIRIAM_UserDefaultsKeyForLastImpressionTimestamp];
94
    _lastFetchTime = [_defaults doubleForKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];
95
 
96
    id fetchWaitTimeEntry = [_defaults objectForKey:kUserDefaultsKeyForFetchWaitTime];
97
 
98
    if (![fetchWaitTimeEntry isKindOfClass:NSNumber.class]) {
99
      // This corresponds to the case there is no wait time entry is set in user defaults yet
100
      _nextFetchWaitTime = kDefaultFetchWaitTimeInSeconds;
101
    } else {
102
      _nextFetchWaitTime = ((NSNumber *)fetchWaitTimeEntry).doubleValue;
103
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270009",
104
                  @"Next fetch wait time loaded from user defaults is %lf", _nextFetchWaitTime);
105
    }
106
  }
107
  return self;
108
}
109
 
110
// A helper function for reading and verifying the stored array data for impressions
111
// in UserDefaults. It returns nil if it does not exist or fail to pass the data type
112
// checking.
113
- (NSArray *)fetchImpressionArrayFromStorage {
114
  id impressionsData = [self.defaults objectForKey:FIRIAM_UserDefaultsKeyForImpressions];
115
 
116
  if (impressionsData && ![impressionsData isKindOfClass:[NSArray class]]) {
117
    FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM270007",
118
                  @"Found non-array data from impression userdefaults storage with key %@",
119
                  FIRIAM_UserDefaultsKeyForImpressions);
120
    return nil;
121
  }
122
  return (NSArray *)impressionsData;
123
}
124
 
125
- (void)recordNewImpressionForMessage:(NSString *)messageID
126
          withStartTimestampInSeconds:(double)timestamp {
127
  @synchronized(self) {
128
    NSArray *oldImpressions = [self fetchImpressionArrayFromStorage];
129
    // oldImpressions could be nil at the first time
130
    NSMutableArray *newImpressions =
131
        oldImpressions ? [oldImpressions mutableCopy] : [[NSMutableArray alloc] init];
132
 
133
    // Two cases
134
    //    If a prior impression exists for that messageID, update its impression timestamp
135
    //    If a prior impression for that messageID does not exist, add a new entry for the
136
    //    messageID.
137
 
138
    NSDictionary *newImpressionEntry = @{
139
      FIRIAM_ImpressionDictKeyForID : messageID,
140
      FIRIAM_ImpressionDictKeyForTimestamp : [NSNumber numberWithDouble:timestamp]
141
    };
142
 
143
    BOOL oldImpressionRecordFound = NO;
144
 
145
    for (int i = 0; i < newImpressions.count; i++) {
146
      if ([newImpressions[i] isKindOfClass:[NSDictionary class]]) {
147
        NSDictionary *currentItem = (NSDictionary *)newImpressions[i];
148
        if ([messageID isEqualToString:currentItem[FIRIAM_ImpressionDictKeyForID]]) {
149
          FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270001",
150
                      @"Updating timestamp of existing impression record to be %f for "
151
                       "message %@",
152
                      timestamp, messageID);
153
 
154
          [newImpressions replaceObjectAtIndex:i withObject:newImpressionEntry];
155
          oldImpressionRecordFound = YES;
156
          break;
157
        }
158
      }
159
    }
160
 
161
    if (!oldImpressionRecordFound) {
162
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270002",
163
                  @"Insert the first impression record for message %@ with timestamp in seconds "
164
                   "as %f",
165
                  messageID, timestamp);
166
      [newImpressions addObject:newImpressionEntry];
167
    }
168
 
169
    [self.defaults setObject:newImpressions forKey:FIRIAM_UserDefaultsKeyForImpressions];
170
    [self.defaults setDouble:timestamp forKey:FIRIAM_UserDefaultsKeyForLastImpressionTimestamp];
171
    self.lastDisplayTime = timestamp;
172
  }
173
}
174
 
175
- (void)clearImpressionsWithMessageList:(NSArray<NSString *> *)messageList {
176
  @synchronized(self) {
177
    NSArray *existingImpressions = [self fetchImpressionArrayFromStorage];
178
 
179
    NSSet<NSString *> *messageIDSet = [NSSet setWithArray:messageList];
180
    NSPredicate *notInMessageListPredicate =
181
        [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
182
          if (![evaluatedObject isKindOfClass:[NSDictionary class]]) {
183
            return NO;  // unexpected item. Throw it away
184
          }
185
          NSDictionary *impression = (NSDictionary *)evaluatedObject;
186
          return impression[FIRIAM_ImpressionDictKeyForID] &&
187
                 ![messageIDSet containsObject:impression[FIRIAM_ImpressionDictKeyForID]];
188
        }];
189
 
190
    NSArray<NSDictionary *> *updatedImpressions =
191
        [existingImpressions filteredArrayUsingPredicate:notInMessageListPredicate];
192
 
193
    if (existingImpressions.count != updatedImpressions.count) {
194
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270004",
195
                  @"Updating the impression records after purging %d items based on the "
196
                   "server fetch response",
197
                  (int)(existingImpressions.count - updatedImpressions.count));
198
      [self.defaults setObject:updatedImpressions forKey:FIRIAM_UserDefaultsKeyForImpressions];
199
    } else {
200
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270005",
201
                  @"No impression records update due to no change after applying the server "
202
                   "message list");
203
    }
204
  }
205
}
206
 
207
- (NSArray<FIRIAMImpressionRecord *> *)getImpressions {
208
  NSArray<NSDictionary *> *impressionsFromStorage = [self fetchImpressionArrayFromStorage];
209
 
210
  NSMutableArray<FIRIAMImpressionRecord *> *resultArray = [[NSMutableArray alloc] init];
211
 
212
  for (NSDictionary *next in impressionsFromStorage) {
213
    FIRIAMImpressionRecord *nextImpression =
214
        [[FIRIAMImpressionRecord alloc] initWithStorageDictionary:next];
215
    [resultArray addObject:nextImpression];
216
  }
217
 
218
  return resultArray;
219
}
220
 
221
- (NSArray<NSString *> *)getMessageIDsFromImpressions {
222
  NSArray<NSDictionary *> *impressionsFromStorage = [self fetchImpressionArrayFromStorage];
223
 
224
  NSMutableArray<NSString *> *resultArray = [[NSMutableArray alloc] init];
225
 
226
  for (NSDictionary *next in impressionsFromStorage) {
227
    [resultArray addObject:next[FIRIAM_ImpressionDictKeyForID]];
228
  }
229
 
230
  return resultArray;
231
}
232
 
233
- (void)recordNewFetchWithFetchCount:(NSInteger)fetchedMsgCount
234
              withTimestampInSeconds:(double)fetchTimestamp
235
                   nextFetchWaitTime:(nullable NSNumber *)nextFetchWaitTime;
236
{
237
  [self.defaults setDouble:fetchTimestamp forKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];
238
  self.lastFetchTime = fetchTimestamp;
239
 
240
  if (nextFetchWaitTime != nil) {
241
    if (nextFetchWaitTime.doubleValue > kMaxFetchWaitTimeInSeconds) {
242
      FIRLogInfo(kFIRLoggerInAppMessaging, @"I-IAM270006",
243
                 @"next fetch wait time %lf is too large. Ignore it.",
244
                 nextFetchWaitTime.doubleValue);
245
    } else {
246
      FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270008",
247
                  @"Setting next fetch wait time as %lf from fetch response.",
248
                  nextFetchWaitTime.doubleValue);
249
      self.nextFetchWaitTime = nextFetchWaitTime.doubleValue;
250
      [self.defaults setObject:nextFetchWaitTime forKey:kUserDefaultsKeyForFetchWaitTime];
251
    }
252
  }
253
}
254
 
255
- (void)cleanupImpressions {
256
  [self.defaults setObject:@[] forKey:FIRIAM_UserDefaultsKeyForImpressions];
257
}
258
 
259
- (void)cleanupFetchRecords {
260
  [self.defaults setDouble:0 forKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];
261
  self.lastFetchTime = 0;
262
}
263
@end
264
 
265
#endif  // TARGET_OS_IOS || TARGET_OS_TV