From 82ebb44b7de18034459eb70ef1fe22ce1fab3471 Mon Sep 17 00:00:00 2001 From: emawby Date: Tue, 15 Sep 2020 12:33:21 -0700 Subject: [PATCH 1/6] making session duration triggers allow redisplay --- .../OneSignalSDK/Source/OSDynamicTriggerController.h | 2 +- .../OneSignalSDK/Source/OSDynamicTriggerController.m | 2 +- iOS_SDK/OneSignalSDK/Source/OSMessagingController.m | 12 +++++++++++- iOS_SDK/OneSignalSDK/Source/OSTriggerController.h | 2 +- iOS_SDK/OneSignalSDK/Source/OSTriggerController.m | 6 +++--- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h index ef9c61686..53b2f39dc 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol OSDynamicTriggerControllerDelegate -- (void)dynamicTriggerFired; +- (void)dynamicTriggerFired:(NSString *triggerId); @end diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m index 9d3fde49a..d4d94a2c0 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m @@ -147,7 +147,7 @@ - (void)timerFiredForMessage:(NSTimer *)timer { [self.scheduledMessages removeObject:trigger.triggerId]; - [self.delegate dynamicTriggerFired]; + [self.delegate dynamicTriggerFired:trigger.triggerId]; } } diff --git a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m index 078726a32..e378c03bd 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m @@ -697,8 +697,18 @@ - (void)addKeySceneToWindow:(UIWindow*)window { } } +- (void)makeRedisplayMessagesAvailableWithTriggers:(NSArray *)triggerIds { + for (OSInAppMessage *message in self.messages) { + if ([self.redisplayedInAppMessages objectForKey:message.messageId] + && [_triggerController hasSharedTriggers:message newTriggersKeys:triggerIds]) { + message.isTriggerChanged = YES; + } + } +} + #pragma mark OSTriggerControllerDelegate Methods -- (void)triggerConditionChanged { +- (void)triggerConditionChanged:(NSString *)triggerId { + [self makeRedisplayMessagesAvailableWithTriggers:@[triggerId]]; // We should re-evaluate all in-app messages [self evaluateMessages]; } diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h index 0ac1d723e..fd3f89e04 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h @@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN The message should be shown (assuming no other triggers are false for that message) It is also called when the app changes trigger values */ -- (void)triggerConditionChanged; +- (void)triggerConditionChanged:(NSString *)triggerId; @end diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m index 98df5e4f2..bb227ccd0 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m @@ -85,7 +85,7 @@ - (BOOL)hasSharedTriggers:(OSInAppMessage *)message newTriggersKeys:(NSArray *andConditions in message.triggers) { for (OSTrigger *trigger in andConditions) { - if ([triggerKey isEqual:trigger.property]) { + if ([triggerKey isEqual:trigger.property] || [triggerKey isEqualToString:trigger.triggerId]) { // At least one trigger has changed return YES; } @@ -259,8 +259,8 @@ - (BOOL)trigger:(NSNumber *)value matchesNumericValue:(id)realValue operatorType return false; } -- (void)dynamicTriggerFired { - [self.delegate triggerConditionChanged]; +- (void)dynamicTriggerFired:(NSString *)triggerId { + [self.delegate triggerConditionChanged:triggerId]; } @end From dedcb6290507747d48776321ff9f0922b17f2328 Mon Sep 17 00:00:00 2001 From: emawby Date: Tue, 15 Sep 2020 13:56:35 -0700 Subject: [PATCH 2/6] add triggerConditionCompleted for short session times --- .../Source/OSDynamicTriggerController.h | 4 +++- .../Source/OSDynamicTriggerController.m | 8 +++---- .../Source/OSMessagingController.m | 22 ++++++++++++++----- .../OneSignalSDK/Source/OSTriggerController.h | 3 ++- .../OneSignalSDK/Source/OSTriggerController.m | 6 +++++ 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h index 53b2f39dc..55abb1111 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h @@ -32,7 +32,9 @@ NS_ASSUME_NONNULL_BEGIN @protocol OSDynamicTriggerControllerDelegate -- (void)dynamicTriggerFired:(NSString *triggerId); +- (void)dynamicTriggerFired:(NSString *)triggerId; +// Alerts the observer that a trigger evaluated to true +- (void)dynamicTriggerCompleted:(NSString *)triggerId; @end diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m index d4d94a2c0..8a6f73dd1 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m @@ -58,7 +58,6 @@ - (instancetype)init { } - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *)messageId { - if (!trigger.value) return false; @@ -79,10 +78,10 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) // Check what type of trigger it is if ([trigger.kind isEqualToString:OS_DYNAMIC_TRIGGER_KIND_SESSION_TIME]) { let currentDuration = fabs([[OneSignal sessionLaunchTime] timeIntervalSinceNow]); - - if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:currentDuration forOperator:trigger.operatorType]) + if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:currentDuration forOperator:trigger.operatorType]) { + [self.delegate dynamicTriggerCompleted:trigger.triggerId]; return true; - + } offset = requiredTimeValue - currentDuration; } else if ([trigger.kind isEqualToString:OS_DYNAMIC_TRIGGER_KIND_MIN_TIME_SINCE]) { @@ -113,7 +112,6 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) [self.scheduledMessages addObject:trigger.triggerId]; } - return false; } diff --git a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m index e378c03bd..210ae6164 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m @@ -322,11 +322,13 @@ - (void)messageViewImpressionRequest:(OSInAppMessage *)message { - (void)evaluateMessages { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Evaluating in app messages"]; for (OSInAppMessage *message in self.messages) { - // Make changes to IAM if redisplay available - [self setDataForRedisplay:message]; - // Should we show the in app message - if ([self shouldShowInAppMessage:message]) { - [self presentInAppMessage:message]; + if ([self.triggerController messageMatchesTriggers:message]) { + // Make changes to IAM if redisplay available + [self setDataForRedisplay:message]; + // Should we show the in app message + if ([self shouldShowInAppMessage:message]) { + [self presentInAppMessage:message]; + } } } } @@ -697,6 +699,11 @@ - (void)addKeySceneToWindow:(UIWindow*)window { } } +- (void)dynamicTriggerCompleted:(NSString *)triggerId { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"messageDynamicTriggerCompleted called with triggerId: %@", triggerId]]; + [self makeRedisplayMessagesAvailableWithTriggers:@[triggerId]]; +} + - (void)makeRedisplayMessagesAvailableWithTriggers:(NSArray *)triggerIds { for (OSInAppMessage *message in self.messages) { if ([self.redisplayedInAppMessages objectForKey:message.messageId] @@ -709,6 +716,10 @@ - (void)makeRedisplayMessagesAvailableWithTriggers:(NSArray *)trigge #pragma mark OSTriggerControllerDelegate Methods - (void)triggerConditionChanged:(NSString *)triggerId { [self makeRedisplayMessagesAvailableWithTriggers:@[triggerId]]; + [self triggerConditionChanged]; +} + +- (void)triggerConditionChanged { // We should re-evaluate all in-app messages [self evaluateMessages]; } @@ -751,5 +762,6 @@ - (void)messageViewDidSelectAction:(OSInAppMessage *)message withAction:(OSInApp - (void)webViewContentFinishedLoading {} #pragma mark OSTriggerControllerDelegate Methods - (void)triggerConditionChanged {} +- (void)dynamicTriggerCompleted:(NSString *)triggerId {} @end diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h index fd3f89e04..13b3b647a 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h @@ -38,8 +38,9 @@ NS_ASSUME_NONNULL_BEGIN The message should be shown (assuming no other triggers are false for that message) It is also called when the app changes trigger values */ +- (void)triggerConditionChanged; - (void)triggerConditionChanged:(NSString *)triggerId; - +- (void)dynamicTriggerCompleted:(NSString *)triggerId; @end @interface OSTriggerController : NSObject diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m index bb227ccd0..85569eeec 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m @@ -85,6 +85,8 @@ - (BOOL)hasSharedTriggers:(OSInAppMessage *)message newTriggersKeys:(NSArray *andConditions in message.triggers) { for (OSTrigger *trigger in andConditions) { + // Dynamic triggers depends on triggerId + // Common triggers changed by user depends on property if ([triggerKey isEqual:trigger.property] || [triggerKey isEqualToString:trigger.triggerId]) { // At least one trigger has changed return YES; @@ -263,4 +265,8 @@ - (void)dynamicTriggerFired:(NSString *)triggerId { [self.delegate triggerConditionChanged:triggerId]; } +- (void)dynamicTriggerCompleted:(NSString *)triggerId { + [self.delegate dynamicTriggerCompleted:triggerId]; +} + @end From 60bb6b1d532bc204ec8c44c2a5e0ae727c789542 Mon Sep 17 00:00:00 2001 From: emawby Date: Fri, 18 Sep 2020 11:16:55 -0700 Subject: [PATCH 3/6] adding more logging to in app trigger evaluation --- .../OneSignalSDK/Source/OSDynamicTriggerController.m | 11 +++++++---- .../OneSignalSDK/Source/OSInAppMessageDisplayStats.m | 4 +++- iOS_SDK/OneSignalSDK/Source/OSMessagingController.m | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m index 8a6f73dd1..88120a88a 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m @@ -79,6 +79,7 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) if ([trigger.kind isEqualToString:OS_DYNAMIC_TRIGGER_KIND_SESSION_TIME]) { let currentDuration = fabs([[OneSignal sessionLaunchTime] timeIntervalSinceNow]); if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:currentDuration forOperator:trigger.operatorType]) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"session time trigger completed: %@", trigger.triggerId]]; [self.delegate dynamicTriggerCompleted:trigger.triggerId]; return true; } @@ -91,9 +92,10 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) let timestampSinceLastMessage = fabs([self.timeSinceLastMessage timeIntervalSinceNow]); - if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:timestampSinceLastMessage forOperator:trigger.operatorType]) + if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:timestampSinceLastMessage forOperator:trigger.operatorType]) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"time since last inapp trigger completed: %@", trigger.triggerId]]; return true; - + } offset = requiredTimeValue - timestampSinceLastMessage; } @@ -107,9 +109,10 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) selector:@selector(timerFiredForMessage:) userInfo:@{@"trigger" : trigger} repeats:false]; - if (timer) + if (timer) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"timer added for triggerId: %@, messageId: %@", trigger.triggerId, messageId]]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; - + } [self.scheduledMessages addObject:trigger.triggerId]; } return false; diff --git a/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m b/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m index 96a446356..fc1d9c40f 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m +++ b/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m @@ -111,7 +111,9 @@ - (BOOL)isDelayTimeSatisfied:(NSTimeInterval)date { } - (BOOL)shouldDisplayAgain { - return _displayQuantity < _displayLimit; + BOOL result = _displayQuantity < _displayLimit; + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"In app message shouldDisplayAgain: %hhu", result]]; + return result; } - (void)incrementDisplayQuantity { diff --git a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m index 210ae6164..a258f578c 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m @@ -715,6 +715,7 @@ - (void)makeRedisplayMessagesAvailableWithTriggers:(NSArray *)trigge #pragma mark OSTriggerControllerDelegate Methods - (void)triggerConditionChanged:(NSString *)triggerId { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"trigger condition changed for triggerId: %@", triggerId]]; [self makeRedisplayMessagesAvailableWithTriggers:@[triggerId]]; [self triggerConditionChanged]; } From 8cbb181b81b2d8f6cc6bc51c80a6f6a73ff66bac Mon Sep 17 00:00:00 2001 From: emawby Date: Fri, 18 Sep 2020 14:19:35 -0700 Subject: [PATCH 4/6] unit test for session duration redisplay --- .../InAppMessagingIntegrationTests.m | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m index 1df4ab877..fb02eb088 100644 --- a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m +++ b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m @@ -1422,6 +1422,64 @@ - (void)testIAMHTMLLoadWithDefaultLanguage { XCTAssertTrue([url containsString:OS_TEST_MESSAGE_ID]); } +- (void)testInAppMessageDisplayMultipleTimesSessionDurationTrigger { + [OneSignal pauseInAppMessages:NO]; + let trigger = [OSTrigger dynamicTriggerWithKind:OS_DYNAMIC_TRIGGER_KIND_SESSION_TIME withOperator:OSTriggerOperatorTypeGreaterThan withValue:@0.05]; + let message = [OSInAppMessageTestHelper testMessageWithTriggers:@[@[trigger]] withRedisplayLimit:5 delay:@30]; + let registrationJson = [OSInAppMessageTestHelper testRegistrationJsonWithMessages:@[message.jsonRepresentation]]; + + // Init OneSignal IAM with redisplay + [self initOneSignalWithRegistrationJSON:registrationJson]; + + // No schedule should happen, IAM should evaluate to true + XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 1); + + // Dismiss IAM will make display quantity increase and last display time to change + [OSMessagingControllerOverrider dismissCurrentMessage]; + // Check IAMs was removed from queue + XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 0); + // Check if data after dismiss is set correctly + XCTAssertEqual(OSMessagingControllerOverrider.messagesForRedisplay.count, 1); + let displayQuantity = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.displayQuantity; + let displayTime = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.lastDisplayTime; + XCTAssertEqual(displayQuantity, 1); + XCTAssertTrue(displayTime > 0); + + // 3. Kill the app and wait 31 seconds + [UnitTestCommonMethods backgroundApp]; + [UnitTestCommonMethods clearStateForAppRestart:self]; + [NSDateOverrider advanceSystemTimeBy:31]; + [UnitTestCommonMethods runBackgroundThreads]; + + [OSInAppMessageTestHelper testRegistrationJsonWithMessages:@[message]]; + + // Init OneSignal IAM with redisplay + [UnitTestCommonMethods initOneSignalAndThreadWait]; + + // No schedule should happen since session time period is very small, should evaluate to true on first run + // Wait for redisplay logic + let expectation = [self expectationWithDescription:@"wait for message to show"]; + expectation.expectedFulfillmentCount = 1; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 1); + + [expectation fulfill]; + }); + + [self waitForExpectations:@[expectation] timeout:1.5]; + + [OSMessagingControllerOverrider dismissCurrentMessage]; + // Check IAMs was removed from queue + XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 0); + // Check if data after dismiss is set correctly + XCTAssertEqual(OSMessagingControllerOverrider.messagesForRedisplay.count, 1); + let secondDisplayQuantity = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.displayQuantity; + let secondDisplayTime = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.lastDisplayTime; + XCTAssertEqual(secondDisplayQuantity, 2); + XCTAssertTrue(secondDisplayTime - displayTime > 30); +} + // Helper method that adds an OSInAppMessage to the IAM messageDisplayQueue // Mock response JSON and initializes the OneSignal SDK - (void)initOneSignalWithInAppMessage:(OSInAppMessage *)message { From b34e530e78937e8db5a52bf1bf841579e85adedd Mon Sep 17 00:00:00 2001 From: emawby Date: Fri, 18 Sep 2020 17:36:30 -0700 Subject: [PATCH 5/6] fixing sessionLaunchTime to get set more than once --- .../Source/OSDynamicTriggerController.m | 3 +- iOS_SDK/OneSignalSDK/Source/OneSignal.m | 3 +- .../InAppMessagingIntegrationTests.m | 53 ++++++++++++------- .../UnitTests/InAppMessagingTests.m | 2 +- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m index 88120a88a..d7f1746f3 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m @@ -104,7 +104,7 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) return false; // If we reach this point, it means we need to return false and set up a timer for a future time - let timer = [NSTimer timerWithTimeInterval:offset + NSTimer *timer = [NSTimer timerWithTimeInterval:offset target:self selector:@selector(timerFiredForMessage:) userInfo:@{@"trigger" : trigger} @@ -113,6 +113,7 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"timer added for triggerId: %@, messageId: %@", trigger.triggerId, messageId]]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } + [self.scheduledMessages addObject:trigger.triggerId]; } return false; diff --git a/iOS_SDK/OneSignalSDK/Source/OneSignal.m b/iOS_SDK/OneSignalSDK/Source/OneSignal.m index b91719977..a8ce082a4 100755 --- a/iOS_SDK/OneSignalSDK/Source/OneSignal.m +++ b/iOS_SDK/OneSignalSDK/Source/OneSignal.m @@ -1712,6 +1712,7 @@ + (void)registerUserInternal { } [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Calling OneSignal create/on_session"]; + sessionLaunchTime = [NSDate date]; if (mShareLocation && [OneSignalLocation lastLocation]) { @@ -2801,7 +2802,6 @@ @implementation OneSignal (SessionStatusDelegate) + (void)onSessionEnding:(NSArray *)lastInfluences { if (_outcomeEventsController) [_outcomeEventsController clearOutcomes]; - [OneSignalTracker onSessionEnded:lastInfluences]; } @@ -2850,7 +2850,6 @@ + (void)load { injectToProperClass(@selector(onesignalSetApplicationIconBadgeNumber:), @selector(setApplicationIconBadgeNumber:), @[], [OneSignalAppDelegate class], [UIApplication class]); [self setupUNUserNotificationCenterDelegate]; - sessionLaunchTime = [NSDate date]; } diff --git a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m index fb02eb088..87f9ff59e 100644 --- a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m +++ b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m @@ -1424,14 +1424,29 @@ - (void)testIAMHTMLLoadWithDefaultLanguage { - (void)testInAppMessageDisplayMultipleTimesSessionDurationTrigger { [OneSignal pauseInAppMessages:NO]; - let trigger = [OSTrigger dynamicTriggerWithKind:OS_DYNAMIC_TRIGGER_KIND_SESSION_TIME withOperator:OSTriggerOperatorTypeGreaterThan withValue:@0.05]; + let trigger = [OSTrigger dynamicTriggerWithKind:OS_DYNAMIC_TRIGGER_KIND_SESSION_TIME withOperator:OSTriggerOperatorTypeGreaterThanOrEqualTo withValue:@0]; let message = [OSInAppMessageTestHelper testMessageWithTriggers:@[@[trigger]] withRedisplayLimit:5 delay:@30]; let registrationJson = [OSInAppMessageTestHelper testRegistrationJsonWithMessages:@[message.jsonRepresentation]]; + //Time interval mock + NSDateComponents* comps = [[NSDateComponents alloc]init]; + comps.year = 2020; + comps.month = 9; + comps.day = 10; + comps.hour = 10; + comps.minute = 1; + + NSCalendar* calendar = [NSCalendar currentCalendar]; + NSDate* date = [calendar dateFromComponents:comps]; + NSTimeInterval firstInterval = [date timeIntervalSince1970]; + // Init OneSignal IAM with redisplay [self initOneSignalWithRegistrationJSON:registrationJson]; + + [OSMessagingControllerOverrider setMockDateGenerator: ^NSTimeInterval(void) { + return firstInterval; + }]; - // No schedule should happen, IAM should evaluate to true XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 1); // Dismiss IAM will make display quantity increase and last display time to change @@ -1444,30 +1459,31 @@ - (void)testInAppMessageDisplayMultipleTimesSessionDurationTrigger { let displayTime = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.lastDisplayTime; XCTAssertEqual(displayQuantity, 1); XCTAssertTrue(displayTime > 0); + + [UnitTestCommonMethods runBackgroundThreads]; // 3. Kill the app and wait 31 seconds [UnitTestCommonMethods backgroundApp]; - [UnitTestCommonMethods clearStateForAppRestart:self]; [NSDateOverrider advanceSystemTimeBy:31]; [UnitTestCommonMethods runBackgroundThreads]; - - [OSInAppMessageTestHelper testRegistrationJsonWithMessages:@[message]]; - + //Time interval mock + comps.minute = 32; + NSDate* secondDate = [calendar dateFromComponents:comps]; + NSTimeInterval secondInterval = [secondDate timeIntervalSince1970]; + [OSMessagingControllerOverrider setMockDateGenerator: ^NSTimeInterval(void) { + return secondInterval; + }]; + // Init OneSignal IAM with redisplay - [UnitTestCommonMethods initOneSignalAndThreadWait]; - - // No schedule should happen since session time period is very small, should evaluate to true on first run - // Wait for redisplay logic - let expectation = [self expectationWithDescription:@"wait for message to show"]; - expectation.expectedFulfillmentCount = 1; + [self initOneSignalWithRegistrationJSON:registrationJson]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 1); - - [expectation fulfill]; - }); + [OSMessagingControllerOverrider setMockDateGenerator: ^NSTimeInterval(void) { + return firstInterval; + }]; + [UnitTestCommonMethods foregroundApp]; + [UnitTestCommonMethods runBackgroundThreads]; - [self waitForExpectations:@[expectation] timeout:1.5]; + XCTAssertEqual(OSMessagingControllerOverrider.messageDisplayQueue.count, 1); [OSMessagingControllerOverrider dismissCurrentMessage]; // Check IAMs was removed from queue @@ -1477,7 +1493,6 @@ - (void)testInAppMessageDisplayMultipleTimesSessionDurationTrigger { let secondDisplayQuantity = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.displayQuantity; let secondDisplayTime = OSMessagingControllerOverrider.messagesForRedisplay.allValues[0].displayStats.lastDisplayTime; XCTAssertEqual(secondDisplayQuantity, 2); - XCTAssertTrue(secondDisplayTime - displayTime > 30); } // Helper method that adds an OSInAppMessage to the IAM messageDisplayQueue diff --git a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingTests.m b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingTests.m index 26406c393..6698400b4 100644 --- a/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingTests.m +++ b/iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingTests.m @@ -541,7 +541,7 @@ - (void)testDynamicTriggerSessionDurationLaunchesTimer { XCTAssertFalse(triggered); XCTAssertTrue(NSTimerOverrider.hasScheduledTimer); - XCTAssertTrue(fabs(NSTimerOverrider.mostRecentTimerInterval - 30.0f) < 0.1f); + XCTAssertTrue(fabs(NSTimerOverrider.mostRecentTimerInterval - 30.0f) < 1.1f); } From d0c7a0677b4437dd0d1cf7851538ce3677efc272 Mon Sep 17 00:00:00 2001 From: emawby Date: Tue, 22 Sep 2020 16:43:58 -0700 Subject: [PATCH 6/6] removing dynamictriggerfired:triggerid --- .../OneSignalDevApp/OneSignalDevApp/AppDelegate.m | 4 ++-- .../Source/OSDynamicTriggerController.h | 2 +- .../Source/OSDynamicTriggerController.m | 3 ++- .../Source/OSInAppMessageDisplayStats.m | 2 ++ iOS_SDK/OneSignalSDK/Source/OSMessagingController.m | 13 ++++++------- iOS_SDK/OneSignalSDK/Source/OSTriggerController.h | 1 - iOS_SDK/OneSignalSDK/Source/OSTriggerController.m | 4 ++-- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m index 7f697eca9..4d5428739 100644 --- a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m +++ b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m @@ -85,12 +85,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( return YES; } -#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"ONESIGNAL_APP_ID_KEY_FOR_TESTING" +#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"77e32082-ea27-42e3-a898-c72e141824ef" + (NSString*)getOneSignalAppId { NSString* onesignalAppId = [[NSUserDefaults standardUserDefaults] objectForKey:ONESIGNAL_APP_ID_KEY_FOR_TESTING]; if (!onesignalAppId) - onesignalAppId = @"0ba9731b-33bd-43f4-8b59-61172e27447d"; + onesignalAppId = @"77e32082-ea27-42e3-a898-c72e141824ef"; return onesignalAppId; } diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h index 55abb1111..5dbcf3e3a 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol OSDynamicTriggerControllerDelegate -- (void)dynamicTriggerFired:(NSString *)triggerId; +- (void)dynamicTriggerFired; // Alerts the observer that a trigger evaluated to true - (void)dynamicTriggerCompleted:(NSString *)triggerId; diff --git a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m index d7f1746f3..90e9f2cc0 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSDynamicTriggerController.m @@ -81,6 +81,7 @@ - (BOOL)dynamicTriggerShouldFire:(OSTrigger *)trigger withMessageId:(NSString *) if ([self evaluateTimeInterval:requiredTimeValue withCurrentValue:currentDuration forOperator:trigger.operatorType]) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"session time trigger completed: %@", trigger.triggerId]]; [self.delegate dynamicTriggerCompleted:trigger.triggerId]; + //[self.delegate dynamicTriggerFired:trigger.triggerId]; return true; } offset = requiredTimeValue - currentDuration; @@ -149,7 +150,7 @@ - (void)timerFiredForMessage:(NSTimer *)timer { [self.scheduledMessages removeObject:trigger.triggerId]; - [self.delegate dynamicTriggerFired:trigger.triggerId]; + [self.delegate dynamicTriggerFired]; } } diff --git a/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m b/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m index fc1d9c40f..76004877a 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m +++ b/iOS_SDK/OneSignalSDK/Source/OSInAppMessageDisplayStats.m @@ -133,6 +133,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeInteger:_displayQuantity forKey:@"displayQuantity"]; [encoder encodeDouble:_displayDelay forKey:@"displayDelay"]; [encoder encodeDouble:_lastDisplayTime forKey:@"lastDisplayTime"]; + [encoder encodeBool:_redisplayEnabled forKey:@"redisplayEnabled"]; } - (id)initWithCoder:(NSCoder *)decoder { @@ -141,6 +142,7 @@ - (id)initWithCoder:(NSCoder *)decoder { _displayQuantity = [decoder decodeIntegerForKey:@"displayQuantity"]; _displayDelay = [decoder decodeDoubleForKey:@"displayDelay"]; _lastDisplayTime = [decoder decodeDoubleForKey:@"lastDisplayTime"]; + _redisplayEnabled = [decoder decodeBoolForKey:@"redisplayEnabled"]; } return self; } diff --git a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m index a258f578c..bfdc7186e 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSMessagingController.m @@ -493,8 +493,11 @@ - (void)hideWindow { - (void)persistInAppMessageForRedisplay:(OSInAppMessage *)message { // If the IAM doesn't have the re display prop or is a preview IAM there is no need to save it - if (![message.displayStats isRedisplayEnabled] || message.isPreview) - return; + if (![message.displayStats isRedisplayEnabled] || message.isPreview) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"not persisting %@",message.displayStats]]; + return; + } + let displayTimeSeconds = self.dateGenerator(); message.displayStats.lastDisplayTime = displayTimeSeconds; @@ -714,14 +717,10 @@ - (void)makeRedisplayMessagesAvailableWithTriggers:(NSArray *)trigge } #pragma mark OSTriggerControllerDelegate Methods -- (void)triggerConditionChanged:(NSString *)triggerId { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"trigger condition changed for triggerId: %@", triggerId]]; - [self makeRedisplayMessagesAvailableWithTriggers:@[triggerId]]; - [self triggerConditionChanged]; -} - (void)triggerConditionChanged { // We should re-evaluate all in-app messages + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Trigger condition changed"]; [self evaluateMessages]; } diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h index 13b3b647a..4a25dd2f7 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.h @@ -39,7 +39,6 @@ NS_ASSUME_NONNULL_BEGIN It is also called when the app changes trigger values */ - (void)triggerConditionChanged; -- (void)triggerConditionChanged:(NSString *)triggerId; - (void)dynamicTriggerCompleted:(NSString *)triggerId; @end diff --git a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m index 85569eeec..5327eaaad 100644 --- a/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m +++ b/iOS_SDK/OneSignalSDK/Source/OSTriggerController.m @@ -261,8 +261,8 @@ - (BOOL)trigger:(NSNumber *)value matchesNumericValue:(id)realValue operatorType return false; } -- (void)dynamicTriggerFired:(NSString *)triggerId { - [self.delegate triggerConditionChanged:triggerId]; +- (void)dynamicTriggerFired { + [self.delegate triggerConditionChanged]; } - (void)dynamicTriggerCompleted:(NSString *)triggerId {