Skip to content

Commit 44cf1a3

Browse files
Expose push notification custom payload data to JavaScript
Add pushPayload field to IterableActionContext and auto-populate it when URL or custom action handlers are triggered from push notifications. This allows JS handlers to access custom metadata from push campaigns via context.pushPayload. Fixes #135. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e69c305 commit 44cf1a3

2 files changed

Lines changed: 73 additions & 7 deletions

File tree

src/core/classes/Iterable.ts

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IterableInAppMessage } from '../../inApp/classes/IterableInAppMessage';
99
import { IterableInAppCloseSource } from '../../inApp/enums/IterableInAppCloseSource';
1010
import { IterableInAppDeleteSource } from '../../inApp/enums/IterableInAppDeleteSource';
1111
import { IterableInAppLocation } from '../../inApp/enums/IterableInAppLocation';
12+
import { IterableActionSource } from '../enums/IterableActionSource';
1213
import { IterableAuthResponseResult } from '../enums/IterableAuthResponseResult';
1314
import { IterableEventName } from '../enums/IterableEventName';
1415
import type { IterableAuthFailure } from '../types/IterableAuthFailure';
@@ -967,7 +968,11 @@ export class Iterable {
967968
*
968969
* Event Handlers:
969970
* - `handleUrlCalled`: Invokes the URL handler if configured, with a delay on Android to allow the activity to wake up.
971+
* When the action source is a push notification, the last push payload is automatically fetched and
972+
* attached to the `IterableActionContext` as `pushPayload`, making custom push data available in the handler.
970973
* - `handleCustomActionCalled`: Invokes the custom action handler if configured.
974+
* When the action source is a push notification, the last push payload is automatically fetched and
975+
* attached to the `IterableActionContext` as `pushPayload`.
971976
* - `handleInAppCalled`: Invokes the in-app handler if configured and sets the in-app show response.
972977
* - `handleAuthCalled`: Invokes the authentication handler if configured and handles the promise result.
973978
* - `handleAuthSuccessCalled`: Sets the authentication response callback to success.
@@ -988,13 +993,34 @@ export class Iterable {
988993
const context = IterableActionContext.fromDict(dict.context);
989994
Iterable.wakeApp();
990995

991-
if (Platform.OS === 'android') {
992-
//Give enough time for Activity to wake up.
993-
setTimeout(() => {
994-
callUrlHandler(Iterable.savedConfig, url, context);
995-
}, 1000);
996+
// When the action originates from a push notification, fetch the last
997+
// push payload and attach it to the context so that URL handlers can
998+
// access custom push data (e.g. promo codes, deep link metadata).
999+
const enrichAndHandle = (ctx: IterableActionContext) => {
1000+
if (Platform.OS === 'android') {
1001+
//Give enough time for Activity to wake up.
1002+
setTimeout(() => {
1003+
callUrlHandler(Iterable.savedConfig, url, ctx);
1004+
}, 1000);
1005+
} else {
1006+
callUrlHandler(Iterable.savedConfig, url, ctx);
1007+
}
1008+
};
1009+
1010+
if (context.source === IterableActionSource.push) {
1011+
Iterable.getLastPushPayload()
1012+
.then((payload) => {
1013+
if (payload && typeof payload === 'object') {
1014+
context.pushPayload = payload as Record<string, unknown>;
1015+
}
1016+
enrichAndHandle(context);
1017+
})
1018+
.catch(() => {
1019+
// If fetching the payload fails, proceed without it
1020+
enrichAndHandle(context);
1021+
});
9961022
} else {
997-
callUrlHandler(Iterable.savedConfig, url, context);
1023+
enrichAndHandle(context);
9981024
}
9991025
});
10001026
}
@@ -1005,7 +1031,25 @@ export class Iterable {
10051031
(dict) => {
10061032
const action = IterableAction.fromDict(dict.action);
10071033
const context = IterableActionContext.fromDict(dict.context);
1008-
Iterable.savedConfig.customActionHandler!(action, context);
1034+
1035+
// When the action originates from a push notification, fetch the last
1036+
// push payload and attach it to the context so that custom action
1037+
// handlers can access custom push data.
1038+
if (context.source === IterableActionSource.push) {
1039+
Iterable.getLastPushPayload()
1040+
.then((payload) => {
1041+
if (payload && typeof payload === 'object') {
1042+
context.pushPayload = payload as Record<string, unknown>;
1043+
}
1044+
Iterable.savedConfig.customActionHandler!(action, context);
1045+
})
1046+
.catch(() => {
1047+
// If fetching the payload fails, proceed without it
1048+
Iterable.savedConfig.customActionHandler!(action, context);
1049+
});
1050+
} else {
1051+
Iterable.savedConfig.customActionHandler!(action, context);
1052+
}
10091053
}
10101054
);
10111055
}

src/core/classes/IterableActionContext.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ export class IterableActionContext {
1414
*/
1515
source: IterableActionSource;
1616

17+
/**
18+
* The push notification payload, if the action originated from a push notification.
19+
*
20+
* This field is automatically populated when the action source is
21+
* {@link IterableActionSource.push}. It contains the custom payload data
22+
* from the push notification that triggered the action, allowing you to
23+
* access campaign-specific metadata in your URL or custom action handlers.
24+
*
25+
* @example
26+
* ```typescript
27+
* const config = new IterableConfig();
28+
* config.urlHandler = (url, context) => {
29+
* if (context.pushPayload) {
30+
* const promoCode = context.pushPayload.promoCode;
31+
* // Use the custom payload data from the push notification
32+
* }
33+
* return true;
34+
* };
35+
* ```
36+
*/
37+
pushPayload?: Record<string, unknown>;
38+
1739
/**
1840
* Creates an instance of IterableActionContext.
1941
*/

0 commit comments

Comments
 (0)