Skip to content

Commit 977e300

Browse files
committed
Add Click Action handler for outcomes
* If the user sends and outcome from the click action handler callback, that outcome should be DIRECT influenced by IAM * DIRECT influences by IAM can be from click action handler or click action outcome * Reset and cache indirect state to avoid direct being the last cached state
1 parent de9c0a4 commit 977e300

File tree

10 files changed

+140
-24
lines changed

10 files changed

+140
-24
lines changed

iOS_SDK/OneSignalSDK/Source/OSChannelTracker.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ - (void)resetAndInitInfluence {
7979
_indirectIds = [self lastReceivedIds];
8080
_influenceType = _indirectIds != nil && _indirectIds.count > 0 ? INDIRECT : UNATTRIBUTED;
8181

82+
[self cacheState];
8283
[OneSignal onesignal_Log:ONE_S_LL_DEBUG message:[NSString stringWithFormat:@"OSChannelTracker resetAndInitInfluence for: %@ finish with influenceType: %@", [self idTag], OS_INFLUENCE_TYPE_TO_STRING(_influenceType)]];
8384
}
8485

iOS_SDK/OneSignalSDK/Source/OSInAppMessageTracker.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,4 @@ - (void)cacheState {
8989
[self.dataRepository cacheIAMInfluenceType:self.influenceType];
9090
}
9191

92-
9392
@end

iOS_SDK/OneSignalSDK/Source/OSMessagingController.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,9 @@ - (id)getTriggerValueForKey:(NSString *)key {
437437
- (void)messageViewControllerWasDismissed {
438438
@synchronized (self.messageDisplayQueue) {
439439
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Dismissing IAM and preparing to show next IAM"];
440-
440+
// Remove DIRECT influence due to ClickHandler of ClickAction outcomes
441+
[OneSignal.sessionManager onDirectInfluenceFromIAMClickFinished];
442+
441443
// Add current dismissed messageId to seenInAppMessages set and save it to NSUserDefaults
442444
if (self.isInAppMessageShowing) {
443445
OSInAppMessage *showingIAM = self.messageDisplayQueue.firstObject;
@@ -569,8 +571,11 @@ - (void)messageViewDidSelectAction:(OSInAppMessage *)message withAction:(OSInApp
569571
if (action.promptActions && action.promptActions.count > 0)
570572
[self handlePromptActions:action.promptActions withMessage:message];
571573

572-
if (self.actionClickBlock)
574+
if (self.actionClickBlock) {
575+
// Any outcome sent on this callback should count as DIRECT from this IAM
576+
[OneSignal.sessionManager onDirectInfluenceFromIAMClick:message.messageId];
573577
self.actionClickBlock(action);
578+
}
574579

575580
if (message.isPreview) {
576581
[self processPreviewInAppMessage:message withAction:action];

iOS_SDK/OneSignalSDK/Source/OSSessionManager.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ - (void)onInAppMessageReceived:(NSString *)messageId {
9393

9494
OSChannelTracker *inAppMessageTracker = [_trackerFactory iamChannelTracker];
9595
[inAppMessageTracker saveLastId:messageId];
96-
[inAppMessageTracker resetAndInitInfluence];
9796
}
9897

9998
- (void)onDirectInfluenceFromIAMClick:(NSString *)directIAMId {

iOS_SDK/OneSignalSDK/Source/OneSignalOutcomeEventsController.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ - (void)sendClickActionOutcomes:(NSArray<OSInAppMessageOutcome *> *)outcomes
8484
else
8585
[self sendOutcomeEvent:name appId:appId deviceType:deviceType successBlock:nil];
8686
}
87-
// Requests are sent or cached at this point
88-
[_sessionManager onDirectInfluenceFromIAMClickFinished];
8987
}
9088

9189
- (void)sendUniqueOutcomeEvent:(NSString * _Nonnull)name

iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ - (void)setUp {
9595
- (void)tearDown {
9696
// Wait for IAM viewDidLoad if available to not conflict with other tests
9797
[UnitTestCommonMethods runBackgroundThreads];
98-
98+
[OneSignal setInAppMessageClickHandler:nil];
99+
[OneSignal pauseInAppMessages:true];
100+
99101
OneSignalOverrider.shouldOverrideSessionLaunchTime = false;
100102

101103
[OSMessagingController.sharedInstance resetState];
@@ -877,6 +879,98 @@ - (void)testIAMClickedLaunchesOutcomeWithValueAPIV2Request {
877879
XCTAssertEqual(outcomeWeight, [[OneSignalClientOverrider.lastHTTPRequest objectForKey:@"weight"] intValue]);
878880
}
879881

882+
- (void)testIAMClickedLaunchesClickHandlerSendDirectOutcomeV2Request {
883+
[self setOutcomesParamsEnabled];
884+
[self setOutcomesV2Enabled];
885+
886+
let firstTrigger = [OSTrigger customTriggerWithProperty:@"testProp" withOperator:OSTriggerOperatorTypeExists withValue:nil];
887+
888+
OSInAppMessage * message = [OSInAppMessageTestHelper testMessageWithTriggers:@[@[firstTrigger]]];
889+
890+
[self initOneSignalWithInAppMessage:message];
891+
892+
XCTAssertEqual(0, OSMessagingControllerOverrider.messageDisplayQueue.count);
893+
894+
__block OSInAppMessageAction *actionReceived = nil;
895+
id inAppMessagingActionClickBlock = ^(OSInAppMessageAction *action) {
896+
actionReceived = action;
897+
898+
[OneSignal sendOutcome:@"test"];
899+
[UnitTestCommonMethods runBackgroundThreads];
900+
901+
// The action should cause an "outcome" API request
902+
XCTAssertEqualObjects(OneSignalClientOverrider.lastUrl, @"https://api.onesignal.com/outcomes/measure_sources");
903+
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequestType, NSStringFromClass([OSRequestSendOutcomesV2ToServer class]));
904+
id source = [OneSignalClientOverrider.lastHTTPRequest objectForKey:@"sources"];
905+
id directBody = [source objectForKey:@"direct"];
906+
id indirectBody = [source objectForKey:@"indirect"];
907+
id iamIds = [directBody objectForKey:@"in_app_message_ids"];
908+
XCTAssertEqual(1, [iamIds count]);
909+
XCTAssertNil(indirectBody);
910+
XCTAssertNil([OneSignalClientOverrider.lastHTTPRequest objectForKey:@"weight"]);
911+
};
912+
[OneSignal setInAppMessageClickHandler:inAppMessagingActionClickBlock];
913+
914+
[OneSignal addTrigger:@"testProp" withValue:@2];
915+
[UnitTestCommonMethods runBackgroundThreads];
916+
// the message should now be displayed
917+
// simulate a button press (action) on the inapp message
918+
let action = [OSInAppMessageAction instanceWithJson: OSInAppMessageTestHelper.testActionJson];
919+
[OSMessagingController.sharedInstance messageViewDidSelectAction:message withAction:action];
920+
921+
XCTAssertNotNil(actionReceived);
922+
}
923+
924+
- (void)testIAMClickedLaunchesClickHandlerDismissIAMSendIndirectOutcomeV2Request {
925+
[OneSignal pauseInAppMessages:false];
926+
[self setOutcomesParamsEnabled];
927+
[self setOutcomesV2Enabled];
928+
929+
let firstTrigger = [OSTrigger customTriggerWithProperty:@"testProp" withOperator:OSTriggerOperatorTypeExists withValue:nil];
930+
931+
OSInAppMessage * message = [OSInAppMessageTestHelper testMessageWithTriggers:@[@[firstTrigger]]];
932+
933+
[self initOneSignalWithInAppMessage:message];
934+
935+
XCTAssertEqual(0, OSMessagingControllerOverrider.messageDisplayQueue.count);
936+
937+
// Check no influence id saved
938+
NSArray *lastReceivedIds = [[[[OSTrackerFactory alloc] init] iamChannelTracker] lastReceivedIds];
939+
XCTAssertEqual(lastReceivedIds.count, 0);
940+
941+
__block OSInAppMessageAction *actionReceived = nil;
942+
id inAppMessagingActionClickBlock = ^(OSInAppMessageAction *action) {
943+
actionReceived = action;
944+
};
945+
[OneSignal setInAppMessageClickHandler:inAppMessagingActionClickBlock];
946+
947+
[OneSignal addTrigger:@"testProp" withValue:@2];
948+
[UnitTestCommonMethods runBackgroundThreads];
949+
950+
// the message should now be displayed
951+
// simulate a button press (action) on the inapp message
952+
let action = [OSInAppMessageAction instanceWithJson: OSInAppMessageTestHelper.testActionJson];
953+
[OSMessagingController.sharedInstance messageViewDidSelectAction:message withAction:action];
954+
955+
XCTAssertNotNil(actionReceived);
956+
957+
[OSMessagingControllerOverrider dismissCurrentMessage];
958+
959+
[OneSignal sendOutcome:@"test"];
960+
[UnitTestCommonMethods runBackgroundThreads];
961+
962+
// The action should cause an "outcome" API request
963+
XCTAssertEqualObjects(OneSignalClientOverrider.lastUrl, @"https://api.onesignal.com/outcomes/measure_sources");
964+
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequestType, NSStringFromClass([OSRequestSendOutcomesV2ToServer class]));
965+
id source = [OneSignalClientOverrider.lastHTTPRequest objectForKey:@"sources"];
966+
id directBody = [source objectForKey:@"direct"];
967+
id indirectBody = [source objectForKey:@"indirect"];
968+
id iamIds = [indirectBody objectForKey:@"in_app_message_ids"];
969+
XCTAssertEqual(1, [iamIds count]);
970+
XCTAssertNil(directBody);
971+
XCTAssertNil([OneSignalClientOverrider.lastHTTPRequest objectForKey:@"weight"]);
972+
}
973+
880974
- (void)testIAMClickedLaunchesMultipleOutcomesAPIRequest {
881975
[self setOutcomesParamsEnabled];
882976

iOS_SDK/OneSignalSDK/UnitTests/OutcomeIntegrationV2Tests.m

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,8 +654,10 @@ - (void)testSendingOutcome_inIAMIndirectSession {
654654
// 2. Receive 2 iam
655655
[[OneSignal sessionManager] onInAppMessageReceived:@"test_in_app_message_1"];
656656
[[OneSignal sessionManager] onInAppMessageReceived:@"test_in_app_message_2"];
657+
// 3. Dismiss iam
658+
[[OneSignal sessionManager] onDirectInfluenceFromIAMClickFinished];
657659

658-
// 3. Validate IN_APP_MESSAGE influence is INDIRECT and send 2 outcomes
660+
// 4. Validate IN_APP_MESSAGE influence is INDIRECT and send 2 outcomes
659661
let sessionInfluences = [OneSignal.sessionManager getInfluences];
660662
for (OSInfluence *influence in sessionInfluences) {
661663
switch (influence.influenceChannel) {
@@ -672,7 +674,7 @@ - (void)testSendingOutcome_inIAMIndirectSession {
672674
[OneSignal sendOutcome:@"normal_1"];
673675
[OneSignal sendOutcome:@"normal_2"];
674676

675-
// 6. Make sure 2 measure requests were made with correct params
677+
// 5. Make sure 2 measure requests were made with correct params
676678
[RestClientAsserts assertMeasureSourcesAtIndex:2 payload:@{
677679
@"sources": @{
678680
@"indirect": @{
@@ -731,8 +733,10 @@ - (void)testSendingOutcomeWithValue_inIAMIndirectSession {
731733
// 2. Receive 2 iam
732734
[[OneSignal sessionManager] onInAppMessageReceived:@"test_in_app_message_1"];
733735
[[OneSignal sessionManager] onInAppMessageReceived:@"test_in_app_message_2"];
736+
// 3. Dismiss iam
737+
[[OneSignal sessionManager] onDirectInfluenceFromIAMClickFinished];
734738

735-
// 3. Validate IN_APP_MESSAGE influence is INDIRECT and send 2 outcomes
739+
// 4. Validate IN_APP_MESSAGE influence is INDIRECT and send 2 outcomes
736740
let sessionInfluences = [OneSignal.sessionManager getInfluences];
737741
for (OSInfluence *influence in sessionInfluences) {
738742
switch (influence.influenceChannel) {
@@ -751,7 +755,7 @@ - (void)testSendingOutcomeWithValue_inIAMIndirectSession {
751755
let val2 = [NSNumber numberWithDouble:9.95];
752756
[OneSignal sendOutcomeWithValue:@"value_2" value:val2];
753757

754-
// 6. Make sure 2 measure requests were made with correct params
758+
// 5. Make sure 2 measure requests were made with correct params
755759
[RestClientAsserts assertMeasureSourcesAtIndex:2 payload:@{
756760
@"sources": @{
757761
@"indirect": @{

iOS_SDK/OneSignalSDK/UnitTests/OutcomeTests.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ - (void)testUnattributedSessionToIndirectSession {
185185
XCTAssertEqual(influence.ids, nil);
186186
}
187187

188-
// 4. Rceive 3 notifications
188+
// 4. Receive 3 notifications
189189
[sessionManager onNotificationReceived:testNotificationId];
190190
[sessionManager onNotificationReceived:testNotificationId];
191191
[sessionManager onNotificationReceived:testNotificationId];

iOS_SDK/OneSignalSDK/UnitTests/OutcomeV2Tests.m

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ - (void)testIAMIndirectSession {
115115
// 2. Receive 2 iam
116116
[sessionManager onInAppMessageReceived:testInAppMessageId];
117117
[sessionManager onInAppMessageReceived:testGenericId];
118+
// 3. Dismiss iam
119+
[sessionManager onDirectInfluenceFromIAMClickFinished];
118120

119-
// 3. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 notifications
121+
// 4. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 notifications
120122
let sessionInfluences = [sessionManager getInfluences];
121123
for (OSInfluence *influence in sessionInfluences) {
122124
switch (influence.influenceChannel) {
@@ -140,8 +142,10 @@ - (void)testIAMIndirectSessionWithRedisplay {
140142
[sessionManager onInAppMessageReceived:testInAppMessageId];
141143
[sessionManager onInAppMessageReceived:testGenericId];
142144
[sessionManager onInAppMessageReceived:testInAppMessageId];
145+
// 3. Dismiss iam
146+
[sessionManager onDirectInfluenceFromIAMClickFinished];
143147

144-
// 3. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 notifications
148+
// 4. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 notifications
145149
let sessionInfluences = [sessionManager getInfluences];
146150
for (OSInfluence *influence in sessionInfluences) {
147151
switch (influence.influenceChannel) {
@@ -195,10 +199,12 @@ - (void)testUnattributedSessionToIndirectSession {
195199
XCTAssertEqual(influence.ids, nil);
196200
}
197201

198-
// 4. Rceive 3 notifications
202+
// 4. Receive 3 notifications
199203
[sessionManager onInAppMessageReceived:testInAppMessageId];
204+
// 5. Dismiss iam
205+
[sessionManager onDirectInfluenceFromIAMClickFinished];
200206

201-
// 5. Make sure IN_APP_MESSAGE influence is INDIRECT and has 1 iam
207+
// 6. Make sure IN_APP_MESSAGE influence is INDIRECT and has 1 iam
202208
sessionInfluences = [sessionManager getInfluences];
203209
for (OSInfluence *influence in sessionInfluences) {
204210
switch (influence.influenceChannel) {
@@ -219,8 +225,10 @@ - (void)testIndirectSessionWithIAMInfluence_overrideIndirectSession_withoutNewSe
219225

220226
// 2. Receive a notification
221227
[sessionManager onInAppMessageReceived:testInAppMessageId];
228+
// 3. Dismiss iam
229+
[sessionManager onDirectInfluenceFromIAMClickFinished];
222230

223-
// 3. Make sure IN_APP_MESSAGE influence is INDIRECT and has 1 iam
231+
// 4. Make sure IN_APP_MESSAGE influence is INDIRECT and has 1 iam
224232
NSArray<OSInfluence *> *sessionInfluences = [sessionManager getInfluences];
225233
for (OSInfluence *influence in sessionInfluences) {
226234
switch (influence.influenceChannel) {
@@ -234,11 +242,13 @@ - (void)testIndirectSessionWithIAMInfluence_overrideIndirectSession_withoutNewSe
234242
}
235243
}
236244

237-
// 4. Receive 2 more iams
245+
// 5. Receive 2 more iams
238246
[sessionManager onInAppMessageReceived:testNotificationId];
239247
[sessionManager onInAppMessageReceived:testGenericId];
240-
241-
// 5. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 iams because IAM influence does not depend on session
248+
// 6. Dismiss iam
249+
[sessionManager onDirectInfluenceFromIAMClickFinished];
250+
251+
// 7. Make sure IN_APP_MESSAGE influence is INDIRECT and has 3 iams because IAM influence does not depend on session
242252
sessionInfluences = [sessionManager getInfluences];
243253
for (OSInfluence *influence in sessionInfluences) {
244254
switch (influence.influenceChannel) {
@@ -284,8 +294,10 @@ - (void)testIndirectSessionToDirectSession {
284294
// 2. Receive 2 notifications
285295
[sessionManager onInAppMessageReceived:testInAppMessageId];
286296
[sessionManager onInAppMessageReceived:testGenericId];
287-
288-
// 3. Make sure IN_APP_MESSAGE influence is INDIRECT and has 2 iam
297+
// 4. Dismiss iam
298+
[sessionManager onDirectInfluenceFromIAMClickFinished];
299+
300+
// 5. Make sure IN_APP_MESSAGE influence is INDIRECT and has 2 iam
289301
NSArray<OSInfluence *> *sessionInfluences = [sessionManager getInfluences];
290302
for (OSInfluence *influence in sessionInfluences) {
291303
switch (influence.influenceChannel) {
@@ -299,11 +311,11 @@ - (void)testIndirectSessionToDirectSession {
299311
}
300312
}
301313

302-
// 5. Receive a notification and open it
314+
// 6. Receive a notification and open it
303315
[sessionManager onInAppMessageReceived:testNotificationId];
304316
[sessionManager onDirectInfluenceFromIAMClick:testNotificationId];
305317

306-
// 6. Make sure IN_APP_MESSAGE influence is DIRECT and has 1 iam
318+
// 7. Make sure IN_APP_MESSAGE influence is DIRECT and has 1 iam
307319
sessionInfluences = [sessionManager getInfluences];
308320
for (OSInfluence *influence in sessionInfluences) {
309321
switch (influence.influenceChannel) {

iOS_SDK/OneSignalSDK/UnitTests/SessionManagerTests.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ - (void)testSessionUpgradeFromUnattributedToIndirect {
318318

319319
[sessionManager onNotificationReceived:testGenericId];
320320
[sessionManager onInAppMessageReceived:testGenericId];
321+
[sessionManager onDirectInfluenceFromIAMClickFinished];
321322

322323
[sessionManager attemptSessionUpgrade:APP_OPEN];
323324

@@ -350,6 +351,7 @@ - (void)testSessionUpgradeFromUnattributedToDirectNotification {
350351

351352
[sessionManager onNotificationReceived:testGenericId];
352353
[sessionManager onInAppMessageReceived:testGenericId];
354+
[sessionManager onDirectInfluenceFromIAMClickFinished];
353355
[sessionManager onDirectInfluenceFromNotificationOpen:NOTIFICATION_CLICK withNotificationId:testGenericId];
354356

355357
iamInfluence = [[trackerFactory iamChannelTracker] currentSessionInfluence];
@@ -511,6 +513,7 @@ - (void)testRestartSessionIfNeededFromOpen {
511513
[self setOutcomesParamsEnabled];
512514

513515
[sessionManager onInAppMessageReceived:testIAMId];
516+
[sessionManager onDirectInfluenceFromIAMClickFinished];
514517
[sessionManager onNotificationReceived:testNotificationId];
515518

516519
[sessionManager restartSessionIfNeeded:APP_OPEN];
@@ -528,6 +531,7 @@ - (void)testRestartSessionIfNeededFromClose {
528531
[self setOutcomesParamsEnabled];
529532

530533
[sessionManager onInAppMessageReceived:testIAMId];
534+
[sessionManager onDirectInfluenceFromIAMClickFinished];
531535
[sessionManager onNotificationReceived:testNotificationId];
532536

533537
[sessionManager restartSessionIfNeeded:APP_CLOSE];

0 commit comments

Comments
 (0)