@@ -45,7 +45,7 @@ @interface OSMessagingController ()
4545@property (strong , nonatomic , nonnull ) NSMutableSet <NSString *> *seenInAppMessages;
4646
4747// Tracking IAMs with redisplay, used to enable showing an IAM more than once after it has been dismissed
48- @property (strong , nonatomic , nonnull ) NSMutableDictionary <NSString *, OSInAppMessage *> *redisplayInAppMessages ;
48+ @property (strong , nonatomic , nonnull ) NSMutableDictionary <NSString *, OSInAppMessage *> *redisplayedInAppMessages ;
4949
5050// Tracking for click ids wihtin IAMs so that body, button, and image are only tracked on the dashboard once
5151@property (strong , nonatomic , nonnull ) NSMutableSet <NSString *> *clickedClickIds;
@@ -64,6 +64,7 @@ @interface OSMessagingController ()
6464
6565@implementation OSMessagingController
6666
67+ static long SIX_MONTHS_TIME_SECONDS = 6 * 30 * 24 * 60 * 60 ;
6768static OSMessagingController *sharedInstance = nil ;
6869static dispatch_once_t once;
6970+ (OSMessagingController *)sharedInstance {
@@ -118,7 +119,7 @@ - (instancetype)init {
118119
119120 // Get all cached IAM data from NSUserDefaults for shown, impressions, and clicks
120121 self.seenInAppMessages = [[NSMutableSet alloc ] initWithSet: [standardUserDefaults getSavedSetForKey: OS_IAM_SEEN_SET_KEY defaultValue: nil ]];
121- self.redisplayInAppMessages = [[NSMutableDictionary alloc ] initWithDictionary: [standardUserDefaults getSavedDictionaryForKey: OS_IAM_SEEN_WITH_REDISPLAY_DICTIONARY_KEY defaultValue: [NSMutableDictionary new ]]];
122+ self.redisplayedInAppMessages = [[NSMutableDictionary alloc ] initWithDictionary: [standardUserDefaults getSavedDictionaryForKey: OS_IAM_REDISPLAY_DICTIONARY defaultValue: [NSMutableDictionary new ]]];
122123 self.clickedClickIds = [[NSMutableSet alloc ] initWithSet: [standardUserDefaults getSavedSetForKey: OS_IAM_CLICKED_SET_KEY defaultValue: nil ]];
123124 self.impressionedInAppMessages = [[NSMutableSet alloc ] initWithSet: [standardUserDefaults getSavedSetForKey: OS_IAM_IMPRESSIONED_SET_KEY defaultValue: nil ]];
124125
@@ -131,32 +132,39 @@ - (instancetype)init {
131132
132133- (void )didUpdateMessagesForSession : (NSArray <OSInAppMessage *> *)newMessages {
133134 self.messages = newMessages;
134-
135- [self removeMessagesWithRedisplayFromCache: newMessages ];
135+
136+ [self resetRedisplayMessagesBySession ];
136137 [self evaluateMessages ];
138+ [self deleteOldRedisplayedInAppMessages ];
139+ }
140+
141+ - (void )resetRedisplayMessagesBySession {
142+ for (NSString *messageId in _redisplayedInAppMessages) {
143+ [_redisplayedInAppMessages objectForKey: messageId].isDisplayedInSession = false ;
144+ }
137145}
138146
139147/*
140148 Part of redisplay logic
141- Remove messages that aren't sent by the backend and keep IAM updated
149+ Remove IAMs that the last display time was six month ago
142150 */
143- - (void )removeMessagesWithRedisplayFromCache : ( NSArray <OSInAppMessage *> *) newMessages {
151+ - (void )deleteOldRedisplayedInAppMessages {
144152 NSMutableSet <NSString *> * messagesIdToRemove = [NSMutableSet new ];
145- NSMutableDictionary <NSString *, OSInAppMessage *> * newRedisplayDictionary = [_redisplayInAppMessages mutableCopy ];
146153
147- for (NSString *messageId in newRedisplayDictionary) {
148- if (![newMessages containsObject: [newRedisplayDictionary objectForKey: messageId]]) {
154+ let sixMonthsAgo = self.dateGenerator () - SIX_MONTHS_TIME_SECONDS;
155+ for (NSString *messageId in _redisplayedInAppMessages) {
156+ if ([_redisplayedInAppMessages objectForKey: messageId].displayStats .lastDisplayTime < sixMonthsAgo) {
149157 [messagesIdToRemove addObject: messageId];
150158 }
151159 }
152160
153161 if ([messagesIdToRemove count ] > 0 ) {
162+ NSMutableDictionary <NSString *, OSInAppMessage *> * newRedisplayDictionary = [_redisplayedInAppMessages mutableCopy ];
154163 for (NSString * messageId in messagesIdToRemove) {
155164 [newRedisplayDictionary removeObjectForKey: messageId];
156165 }
157-
158- _redisplayInAppMessages = newRedisplayDictionary;
159- [OneSignalUserDefaults.initStandard saveDictionaryForKey: OS_IAM_SEEN_WITH_REDISPLAY_DICTIONARY_KEY withValue: newRedisplayDictionary];
166+
167+ [OneSignalUserDefaults.initStandard saveDictionaryForKey: OS_IAM_REDISPLAY_DICTIONARY withValue: newRedisplayDictionary];
160168 }
161169}
162170
@@ -285,13 +293,13 @@ - (void)evaluateMessages {
285293/*
286294 Part of redisplay logic
287295
288- In order to an IAM to be re display , the following conditions need to be satisfied
289- - IAM has redisplay property
290- - Gap between displays is satisfied
291- - Quantity of displays is available
292- - Some IAM Trigger was fired
293-
294- For re display , the message need to be removed from the arrays that track the display/impression
296+ In order to redisplay an IAM, the following conditions must be satisfied:
297+ 1. IAM has redisplay property
298+ 2. Time delay between redisplay satisfied
299+ 3. Has more redisplays
300+ 4. An IAM trigger was satisfied
301+
302+ For redisplay , the message need to be removed from the arrays that track the display/impression
295303 For click counting, every message has it click id array
296304*/
297305- (void )setDataForRedisplay : (OSInAppMessage *)message {
@@ -300,15 +308,17 @@ - (void)setDataForRedisplay:(OSInAppMessage *)message {
300308 }
301309
302310 BOOL messageDismissed = [_seenInAppMessages containsObject: message.messageId];
303- let redisplayMessageSavedData = [_redisplayInAppMessages objectForKey: message.messageId];
311+ let redisplayMessageSavedData = [_redisplayedInAppMessages objectForKey: message.messageId];
304312
305313 if (messageDismissed && redisplayMessageSavedData != nil ) {
306314 [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: [NSString stringWithFormat: @" setDataForRedisplay with message: %@ " , message]];
307315 message.displayStats .displayQuantity = redisplayMessageSavedData.displayStats .displayQuantity ;
308316 message.displayStats .lastDisplayTime = redisplayMessageSavedData.displayStats .lastDisplayTime ;
309317
318+ // Message that don't have triggers should display only once per session
319+ BOOL triggerHasChanged = message.isTriggerChanged || (!redisplayMessageSavedData.isDisplayedInSession && [message.triggers count ] == 0 );
310320 // Check if conditions are correct for redisplay
311- if ([message isTriggerChanged ] &&
321+ if (triggerHasChanged &&
312322 [message.displayStats isDelayTimeSatisfied: self .dateGenerator ()] &&
313323 [message.displayStats shouldDisplayAgain ]) {
314324 [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: @" setDataForRedisplay clear arrays" ];
@@ -348,46 +358,27 @@ - (void)handleMessageActionWithURL:(OSInAppMessageAction *)action {
348358/*
349359 * Part of redisplay logic
350360 *
351- * If trigger key is part of message triggers, then return true, otherwise false
352- */
353- - (BOOL )checkOnMessage : (OSInAppMessage *)message newTriggersKeys : (NSArray <NSString *> *)newTriggersKeys {
354- for (NSString *triggerKey in newTriggersKeys) {
355- for (NSArray <OSTrigger *> *andConditions in message.triggers ) {
356- for (OSTrigger *trigger in andConditions) {
357- if ([triggerKey isEqual: trigger.property]) {
358- // At least one trigger has changed
359- return YES ;
360- }
361- }
362- }
363- }
364- return NO ;
365- }
366-
367- /*
368- * Part of redisplay logic
369- *
370- * Make all messages with redisplay enable available for redisplay if:
361+ * Make all messages with redisplay available if:
371362 * - Already displayed
372- * - Trigger changed
363+ * - At least one Trigger has changed
373364 */
374- - (void )checkTriggerChanges : (NSArray <NSString *> *)newTriggersKeys {
365+ - (void )makeRedisplayedMessagesAvailableWithTriggers : (NSArray <NSString *> *)newTriggersKeys {
375366 for (OSInAppMessage *message in _messages) {
376- if ([_redisplayInAppMessages objectForKey: message.messageId] &&
377- [self checkOnMessage : message newTriggersKeys: newTriggersKeys]) {
367+ if ([_redisplayedInAppMessages objectForKey: message.messageId] &&
368+ [self .triggerController isTriggerOnMessage : message newTriggersKeys: newTriggersKeys]) {
378369 message.isTriggerChanged = true ;
379370 }
380371 }
381372}
382373
383374#pragma mark Trigger Methods
384375- (void )addTriggers : (NSDictionary <NSString *, id> *)triggers {
385- [self checkTriggerChanges : triggers.allKeys];
376+ [self makeRedisplayedMessagesAvailableWithTriggers : triggers.allKeys];
386377 [self .triggerController addTriggers: triggers];
387378}
388379
389380- (void )removeTriggersForKeys : (NSArray <NSString *> *)keys {
390- [self checkTriggerChanges : keys];
381+ [self makeRedisplayedMessagesAvailableWithTriggers : keys];
391382 [self .triggerController removeTriggersForKeys: keys];
392383}
393384
@@ -411,7 +402,7 @@ - (void)messageViewControllerWasDismissed {
411402 [OneSignalUserDefaults.initStandard saveSetForKey: OS_IAM_SEEN_SET_KEY withValue: self .seenInAppMessages];
412403 // Remove dismissed IAM from messageDisplayQueue
413404 [self .messageDisplayQueue removeObjectAtIndex: 0 ];
414- [self persisIAMessageForReDisplay : showingIAM];
405+ [self persistInAppMessageForRedisplay : showingIAM];
415406 }
416407
417408 // Reset the IAM viewController to prepare for next IAM if one exists
@@ -441,24 +432,25 @@ - (void)hideWindow {
441432 [UIApplication.sharedApplication.delegate.window makeKeyWindow ];
442433}
443434
444- - (void )persisIAMessageForReDisplay : (OSInAppMessage *)message {
445- // If the IAM doesn't have the re display prop there is no need to save it
435+ - (void )persistInAppMessageForRedisplay : (OSInAppMessage *)message {
436+ // If the IAM doesn't have the re display prop there is no need to save it
446437 if (![message.displayStats isRedisplayEnabled ])
447438 return ;
448439
449440 let displayTimeSeconds = self.dateGenerator ();
450441 message.displayStats .lastDisplayTime = displayTimeSeconds;
451442 [message.displayStats incrementDisplayQuantity ];
452443 message.isTriggerChanged = false ;
444+ message.isDisplayedInSession = true ;
453445
454- [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: [NSString stringWithFormat: @" redisplayInAppMessages : %@ " , [_redisplayInAppMessages description ]]];
446+ [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: [NSString stringWithFormat: @" redisplayedInAppMessages : %@ " , [_redisplayedInAppMessages description ]]];
455447
456- // Update the data to enable future re displays
457- // Avoid calling the userdefault data again
458- [_redisplayInAppMessages setObject: message forKey: message.messageId];
448+ // Update the data to enable future re displays
449+ // Avoid calling the userdefault data again
450+ [_redisplayedInAppMessages setObject: message forKey: message.messageId];
459451
460- [OneSignalUserDefaults.initStandard saveDictionaryForKey: OS_IAM_SEEN_WITH_REDISPLAY_DICTIONARY_KEY withValue: self .redisplayInAppMessages ];
461- [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: [NSString stringWithFormat: @" persisIAMessageForReDisplay : %@ \n redisplayInAppMessages : %@ " , [message description ], [_redisplayInAppMessages description ]]];
452+ [OneSignalUserDefaults.initStandard saveDictionaryForKey: OS_IAM_REDISPLAY_DICTIONARY withValue: self .redisplayedInAppMessages ];
453+ [OneSignal onesignal_Log: ONE_S_LL_VERBOSE message: [NSString stringWithFormat: @" persistInAppMessageForRedisplay : %@ \n redisplayedInAppMessages : %@ " , [message description ], [_redisplayedInAppMessages description ]]];
462454}
463455
464456- (void )messageViewDidSelectAction : (OSInAppMessage *)message withAction : (OSInAppMessageAction *)action {
@@ -472,6 +464,7 @@ - (void)messageViewDidSelectAction:(OSInAppMessage *)message withAction:(OSInApp
472464 self.actionClickBlock (action);
473465
474466 let clickId = action.clickId ;
467+ // If IAM has redisplay the clickId may be available
475468 BOOL clickAvailableByRedisplay = [message.displayStats isRedisplayEnabled ] && [message isClickAvailable: clickId];
476469
477470 // Make sure no click tracking is performed for IAM previews
@@ -483,6 +476,7 @@ - (void)messageViewDidSelectAction:(OSInAppMessage *)message withAction:(OSInApp
483476
484477 // Add clickId to clickedClickIds
485478 [self .clickedClickIds addObject: clickId];
479+ // Track clickId per IAM
486480 [message addClickId: clickId];
487481
488482 let metricsRequest = [OSRequestInAppMessageClicked withAppId: OneSignal.app_id
0 commit comments