AutorÃa | Ultima modificación | Ver Log |
/** Copyright 2017 Google** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#import <TargetConditionals.h>#if TARGET_OS_IOS || TARGET_OS_TV#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"#import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMBookKeeper.h"NSString *const FIRIAM_UserDefaultsKeyForImpressions = @"firebase-iam-message-impressions";NSString *const FIRIAM_UserDefaultsKeyForLastImpressionTimestamp =@"firebase-iam-last-impression-timestamp";NSString *FIRIAM_UserDefaultsKeyForLastFetchTimestamp = @"firebase-iam-last-fetch-timestamp";// The two keys used to map FIRIAMImpressionRecord object to a NSDictionary object for// persistence.NSString *const FIRIAM_ImpressionDictKeyForID = @"message_id";NSString *const FIRIAM_ImpressionDictKeyForTimestamp = @"impression_time";static NSString *const kUserDefaultsKeyForFetchWaitTime = @"firebase-iam-fetch-wait-time";// 24 hoursstatic NSTimeInterval kDefaultFetchWaitTimeInSeconds = 24 * 60 * 60;// 3 daysstatic NSTimeInterval kMaxFetchWaitTimeInSeconds = 3 * 24 * 60 * 60;@interface FIRIAMBookKeeperViaUserDefaults ()@property(nonatomic) double lastDisplayTime;@property(nonatomic) double lastFetchTime;@property(nonatomic) double nextFetchWaitTime;@property(nonatomic, nonnull) NSUserDefaults *defaults;@end@interface FIRIAMImpressionRecord ()- (instancetype)initWithStorageDictionary:(NSDictionary *)dict;@end@implementation FIRIAMImpressionRecord- (instancetype)initWithMessageID:(NSString *)messageIDimpressionTimeInSeconds:(long)impressionTime {if (self = [super init]) {_messageID = messageID;_impressionTimeInSeconds = impressionTime;}return self;}- (instancetype)initWithStorageDictionary:(NSDictionary *)dict {id timestamp = dict[FIRIAM_ImpressionDictKeyForTimestamp];id messageID = dict[FIRIAM_ImpressionDictKeyForID];if (![timestamp isKindOfClass:[NSNumber class]] || ![messageID isKindOfClass:[NSString class]]) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270003",@"Incorrect data in the dictionary object for creating a FIRIAMImpressionRecord"" object");return nil;} else {return [self initWithMessageID:messageIDimpressionTimeInSeconds:((NSNumber *)timestamp).longValue];}}- (NSString *)description {return [NSString stringWithFormat:@"%@ impressed at %ld in seconds", self.messageID,self.impressionTimeInSeconds];}@end@implementation FIRIAMBookKeeperViaUserDefaults- (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults {if (self = [super init]) {_defaults = userDefaults;// ok if it returns 0 due to the entry being absent_lastDisplayTime = [_defaults doubleForKey:FIRIAM_UserDefaultsKeyForLastImpressionTimestamp];_lastFetchTime = [_defaults doubleForKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];id fetchWaitTimeEntry = [_defaults objectForKey:kUserDefaultsKeyForFetchWaitTime];if (![fetchWaitTimeEntry isKindOfClass:NSNumber.class]) {// This corresponds to the case there is no wait time entry is set in user defaults yet_nextFetchWaitTime = kDefaultFetchWaitTimeInSeconds;} else {_nextFetchWaitTime = ((NSNumber *)fetchWaitTimeEntry).doubleValue;FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270009",@"Next fetch wait time loaded from user defaults is %lf", _nextFetchWaitTime);}}return self;}// A helper function for reading and verifying the stored array data for impressions// in UserDefaults. It returns nil if it does not exist or fail to pass the data type// checking.- (NSArray *)fetchImpressionArrayFromStorage {id impressionsData = [self.defaults objectForKey:FIRIAM_UserDefaultsKeyForImpressions];if (impressionsData && ![impressionsData isKindOfClass:[NSArray class]]) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM270007",@"Found non-array data from impression userdefaults storage with key %@",FIRIAM_UserDefaultsKeyForImpressions);return nil;}return (NSArray *)impressionsData;}- (void)recordNewImpressionForMessage:(NSString *)messageIDwithStartTimestampInSeconds:(double)timestamp {@synchronized(self) {NSArray *oldImpressions = [self fetchImpressionArrayFromStorage];// oldImpressions could be nil at the first timeNSMutableArray *newImpressions =oldImpressions ? [oldImpressions mutableCopy] : [[NSMutableArray alloc] init];// Two cases// If a prior impression exists for that messageID, update its impression timestamp// If a prior impression for that messageID does not exist, add a new entry for the// messageID.NSDictionary *newImpressionEntry = @{FIRIAM_ImpressionDictKeyForID : messageID,FIRIAM_ImpressionDictKeyForTimestamp : [NSNumber numberWithDouble:timestamp]};BOOL oldImpressionRecordFound = NO;for (int i = 0; i < newImpressions.count; i++) {if ([newImpressions[i] isKindOfClass:[NSDictionary class]]) {NSDictionary *currentItem = (NSDictionary *)newImpressions[i];if ([messageID isEqualToString:currentItem[FIRIAM_ImpressionDictKeyForID]]) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270001",@"Updating timestamp of existing impression record to be %f for ""message %@",timestamp, messageID);[newImpressions replaceObjectAtIndex:i withObject:newImpressionEntry];oldImpressionRecordFound = YES;break;}}}if (!oldImpressionRecordFound) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270002",@"Insert the first impression record for message %@ with timestamp in seconds ""as %f",messageID, timestamp);[newImpressions addObject:newImpressionEntry];}[self.defaults setObject:newImpressions forKey:FIRIAM_UserDefaultsKeyForImpressions];[self.defaults setDouble:timestamp forKey:FIRIAM_UserDefaultsKeyForLastImpressionTimestamp];self.lastDisplayTime = timestamp;}}- (void)clearImpressionsWithMessageList:(NSArray<NSString *> *)messageList {@synchronized(self) {NSArray *existingImpressions = [self fetchImpressionArrayFromStorage];NSSet<NSString *> *messageIDSet = [NSSet setWithArray:messageList];NSPredicate *notInMessageListPredicate =[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {if (![evaluatedObject isKindOfClass:[NSDictionary class]]) {return NO; // unexpected item. Throw it away}NSDictionary *impression = (NSDictionary *)evaluatedObject;return impression[FIRIAM_ImpressionDictKeyForID] &&![messageIDSet containsObject:impression[FIRIAM_ImpressionDictKeyForID]];}];NSArray<NSDictionary *> *updatedImpressions =[existingImpressions filteredArrayUsingPredicate:notInMessageListPredicate];if (existingImpressions.count != updatedImpressions.count) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270004",@"Updating the impression records after purging %d items based on the ""server fetch response",(int)(existingImpressions.count - updatedImpressions.count));[self.defaults setObject:updatedImpressions forKey:FIRIAM_UserDefaultsKeyForImpressions];} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270005",@"No impression records update due to no change after applying the server ""message list");}}}- (NSArray<FIRIAMImpressionRecord *> *)getImpressions {NSArray<NSDictionary *> *impressionsFromStorage = [self fetchImpressionArrayFromStorage];NSMutableArray<FIRIAMImpressionRecord *> *resultArray = [[NSMutableArray alloc] init];for (NSDictionary *next in impressionsFromStorage) {FIRIAMImpressionRecord *nextImpression =[[FIRIAMImpressionRecord alloc] initWithStorageDictionary:next];[resultArray addObject:nextImpression];}return resultArray;}- (NSArray<NSString *> *)getMessageIDsFromImpressions {NSArray<NSDictionary *> *impressionsFromStorage = [self fetchImpressionArrayFromStorage];NSMutableArray<NSString *> *resultArray = [[NSMutableArray alloc] init];for (NSDictionary *next in impressionsFromStorage) {[resultArray addObject:next[FIRIAM_ImpressionDictKeyForID]];}return resultArray;}- (void)recordNewFetchWithFetchCount:(NSInteger)fetchedMsgCountwithTimestampInSeconds:(double)fetchTimestampnextFetchWaitTime:(nullable NSNumber *)nextFetchWaitTime;{[self.defaults setDouble:fetchTimestamp forKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];self.lastFetchTime = fetchTimestamp;if (nextFetchWaitTime != nil) {if (nextFetchWaitTime.doubleValue > kMaxFetchWaitTimeInSeconds) {FIRLogInfo(kFIRLoggerInAppMessaging, @"I-IAM270006",@"next fetch wait time %lf is too large. Ignore it.",nextFetchWaitTime.doubleValue);} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM270008",@"Setting next fetch wait time as %lf from fetch response.",nextFetchWaitTime.doubleValue);self.nextFetchWaitTime = nextFetchWaitTime.doubleValue;[self.defaults setObject:nextFetchWaitTime forKey:kUserDefaultsKeyForFetchWaitTime];}}}- (void)cleanupImpressions {[self.defaults setObject:@[] forKey:FIRIAM_UserDefaultsKeyForImpressions];}- (void)cleanupFetchRecords {[self.defaults setDouble:0 forKey:FIRIAM_UserDefaultsKeyForLastFetchTimestamp];self.lastFetchTime = 0;}@end#endif // TARGET_OS_IOS || TARGET_OS_TV