cordova-plugin-reteno 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,12 +4,25 @@ Reteno SDK for Cordova and Capacitor apps.
4
4
 
5
5
  ## Installation
6
6
 
7
- - [iOS](docs/ios.md)
8
- - [Android](docs/android.md)
7
+ ```bash
8
+ npm install cordova-plugin-reteno
9
+ ```
9
10
 
10
- ## Usage
11
+ ## Documentation
11
12
 
12
- - [API](docs/api.md)
13
+ - [Cordova SDK Overview](https://docs.reteno.com/reference/cordova-sdk-setup)
14
+ - [Ionic SDK Overview](https://docs.reteno.com/reference/ionic-sdk)
15
+
16
+ ### Setup Guides
17
+
18
+ - [Cordova iOS SDK Setup](https://docs.reteno.com/reference/cordova-ios-sdk-setup)
19
+ - [Cordova Android SDK Setup](https://docs.reteno.com/reference/cordova-android-sdk-setup)
20
+ - [Ionic iOS SDK Setup](https://docs.reteno.com/reference/ionic-ios-sdk-setup)
21
+ - [Ionic Android SDK Setup](https://docs.reteno.com/reference/ionic-ios-sdk-android)
22
+
23
+ ### Additional
24
+
25
+ - [Release Notes](https://github.com/reteno-com/cordova-plugin-reteno/releases)
13
26
 
14
27
  ## License
15
28
 
package/docs/android.md CHANGED
@@ -60,6 +60,24 @@ RetenoPlugin
60
60
  });
61
61
  ```
62
62
 
63
+ For Android SDK `2.9.4+`, you can also configure session duration and split session lifecycle flags during init:
64
+
65
+ ```js
66
+ RetenoPlugin.init({
67
+ // Optional: session reset duration
68
+ sessionDurationSeconds: 30 * 60,
69
+ lifecycleTrackingOptions: {
70
+ appLifecycleEnabled: true,
71
+ // ApplicationForgrounded/ApplicationBackgrounded events (disabled by default in 2.9.4)
72
+ foregroundLifecycleEnabled: false,
73
+ pushSubscriptionEnabled: true,
74
+ // SessionStart/SessionEnd can now be managed separately
75
+ sessionStartEventsEnabled: true,
76
+ sessionEndEventsEnabled: false,
77
+ },
78
+ });
79
+ ```
80
+
63
81
  If you need advanced Reteno configuration (custom `RetenoConfig`, custom device id provider, etc), you can initialize Reteno in your custom `Application` as described here:
64
82
  [link](https://docs.reteno.com/reference/android-sdk-setup#step-4-initialize-the-reteno-sdk).
65
83
 
@@ -68,7 +86,7 @@ If you need advanced Reteno configuration (custom `RetenoConfig`, custom device
68
86
 
69
87
  ## Push notification listeners
70
88
 
71
- The plugin uses the listener-based API (`EventListener` / `Procedure`) for all push events.
89
+ The plugin uses the listener-based API (`EventListener` / `Procedure`, Android SDK `2.9.4`) for all push events.
72
90
 
73
91
  - `setOnRetenoPushDismissedListener(listener)` — called when a push notification is dismissed (swiped away).
74
92
  - `setOnRetenoCustomPushReceivedListener(listener)` — called when a custom push notification is received.
package/docs/api.md CHANGED
@@ -12,7 +12,7 @@ Notes:
12
12
 
13
13
  | Method | Supported platform | Description |
14
14
  | --- | --- | --- |
15
- | [init](../www/cordova-plugin-reteno.js) | iOS, Android | Initializes Reteno SDK. Accepts optional `RetenoInitializeOptions` with `accessKey`, `pauseInAppMessages`, `pausePushInAppMessages`, `inAppMessagesPauseBehaviour` (iOS), `lifecycleTrackingOptions`, `isAutomaticScreenReportingEnabled` (iOS; see note below) and `isDebugMode`. [Types](../types/index.ts) |
15
+ | [init](../www/cordova-plugin-reteno.js) | iOS, Android | Initializes Reteno SDK. Accepts optional `RetenoInitializeOptions` with `accessKey`, `pauseInAppMessages`, `pausePushInAppMessages`, `inAppMessagesPauseBehaviour` (iOS), `lifecycleTrackingOptions`, `sessionDurationSeconds` (Android 2.9.4+, iOS 2.7.0+), `isAutomaticScreenReportingEnabled` (iOS; see note below) and `isDebugMode`. [Types](../types/index.ts) |
16
16
  | [requestNotificationPermission](../www/cordova-plugin-reteno.js) | iOS, Android | Requests push permission (iOS) or `POST_NOTIFICATIONS` (Android 13+). Returns `0` or `1` on Android (`RequestNotificationPermissionResult`) in [types](../types/index.ts). |
17
17
  | [setLifecycleTrackingOptions](../www/cordova-plugin-reteno.js) | iOS, Android | Configures automatic tracking for app lifecycle, push subscription, and session events. Android: applies immediately. iOS: supported only before initialization (stored and applied during `init(...)`). [Types](../types/index.ts) |
18
18
 
@@ -99,6 +99,7 @@ RetenoPlugin.init()
99
99
  // pausePushInAppMessages: pauses in-app messages triggered by push notifications.
100
100
  // inAppMessagesPauseBehaviour: (iOS) defines handling while paused: 'SKIP_IN_APPS' or 'POSTPONE_IN_APPS'.
101
101
  // lifecycleTrackingOptions: configures app lifecycle, push subscription, and session event tracking ('ALL', 'NONE', or an object).
102
+ // sessionDurationSeconds (Android 2.9.4+, iOS 2.7.0+): optional session reset duration.
102
103
  // isAutomaticScreenReportingEnabled: enables automatic native screen view tracking on iOS.
103
104
  // Keep this false in Cordova/Ionic WebView apps (including Android demos).
104
105
  // Defaults to false. Note: in Cordova/Ionic apps the UI runs inside a single WebView,
@@ -115,10 +116,13 @@ RetenoPlugin.init({
115
116
  inAppMessagesPauseBehaviour: 'SKIP_IN_APPS', // iOS
116
117
  isAutomaticScreenReportingEnabled: false, // keep false for hybrid/WebView apps
117
118
  isDebugMode: true, // enables debug mode
119
+ sessionDurationSeconds: 30 * 60, // Android 2.9.4+, iOS 2.7.0+: 30 minutes
118
120
  lifecycleTrackingOptions: {
119
121
  appLifecycleEnabled: true,
122
+ foregroundLifecycleEnabled: false,
120
123
  pushSubscriptionEnabled: true,
121
- sessionEventsEnabled: false,
124
+ sessionStartEventsEnabled: true,
125
+ sessionEndEventsEnabled: false, // Android 2.9.4 default
122
126
  },
123
127
  })
124
128
  .then(() => console.log('init: OK'))
@@ -129,6 +133,8 @@ RetenoPlugin.init({
129
133
  // Shorthand lifecycle tracking values:
130
134
  RetenoPlugin.init({ lifecycleTrackingOptions: 'ALL' });
131
135
  RetenoPlugin.init({ lifecycleTrackingOptions: 'NONE' });
136
+ // Legacy alias (deprecated): sessionEventsEnabled controls both start/end at once.
137
+ RetenoPlugin.init({ lifecycleTrackingOptions: { sessionEventsEnabled: false } });
132
138
  ```
133
139
 
134
140
  ### setUserAttributes payload example
@@ -236,9 +242,11 @@ RetenoPlugin.setMultiAccountUserAttributes(
236
242
  // Unspecified fields default to true.
237
243
  // Android: applies immediately.
238
244
  // iOS: this works only BEFORE SDK initialization (before calling init()).
245
+ // Deprecated: sessionEventsEnabled (if used) toggles both sessionStart and sessionEnd.
239
246
  RetenoPlugin.setLifecycleTrackingOptions(
240
247
  {
241
- sessionEventsEnabled: true,
248
+ sessionStartEventsEnabled: true,
249
+ sessionEndEventsEnabled: true,
242
250
  }
243
251
  )
244
252
  .then(() => console.log('setLifecycleTrackingOptions: OK'))
@@ -485,7 +493,7 @@ Subscribe to push received events while the app is running.
485
493
 
486
494
  Notes:
487
495
 
488
- - On Android this is based on the SDK 2.9.2 `EventListener` / `Procedure` API (`RetenoNotifications.getReceived()`).
496
+ - On Android this is based on the SDK 2.9.4 `EventListener` / `Procedure` API (`RetenoNotifications.getReceived()`).
489
497
  - This listener is not a replacement for `getInitialNotification()` (cold start): if the app was launched by tapping a notification, use `getInitialNotification()`.
490
498
 
491
499
  ```js
package/docs/ios.md CHANGED
@@ -68,12 +68,12 @@ target 'App' do
68
68
 
69
69
  target 'NotificationServiceExtension' do
70
70
  inherit! :search_paths
71
- pod 'Reteno', '2.6.2'
71
+ pod 'Reteno', '2.7.0'
72
72
  end
73
73
 
74
74
  target 'NotificationContentExtension' do
75
75
  inherit! :search_paths
76
- pod 'Reteno', '2.6.2'
76
+ pod 'Reteno', '2.7.0'
77
77
  end
78
78
  end
79
79
  ```
@@ -187,12 +187,12 @@ target 'App' do
187
187
 
188
188
  target 'NotificationServiceExtension' do
189
189
  inherit! :search_paths
190
- pod 'Reteno', '2.6.2'
190
+ pod 'Reteno', '2.7.0'
191
191
  end
192
192
 
193
193
  target 'NotificationContentExtension' do
194
194
  inherit! :search_paths
195
- pod 'Reteno', '2.6.2'
195
+ pod 'Reteno', '2.7.0'
196
196
  end
197
197
  end
198
198
  ```
@@ -458,12 +458,17 @@ Lifecycle tracking note for iOS:
458
458
  - iOS lifecycle tracking is configured during SDK initialization (`RetenoPlugin.init({ lifecycleTrackingOptions: ... })`).
459
459
  - Calling `setLifecycleTrackingOptions(...)` after initialization is not supported on iOS.
460
460
  - `lifecycleTrackingOptions` accepts:
461
- - `'ALL'` -> enables app lifecycle, push subscription, and session event tracking.
462
- - `'NONE'` -> disables app lifecycle, push subscription, and session event tracking.
461
+ - `'ALL'` -> enables app lifecycle, foreground lifecycle (`ApplicationOpened`/`ApplicationBackgrounded`), push subscription, and session start/end tracking.
462
+ - `'NONE'` -> disables these automatic events.
463
463
  - object:
464
464
  - `appLifecycleEnabled`
465
+ - `foregroundLifecycleEnabled`
465
466
  - `pushSubscriptionEnabled`
466
- - `sessionEventsEnabled`
467
+ - `sessionStartEventsEnabled`
468
+ - `sessionEndEventsEnabled`
469
+ - `sessionEventsEnabled` (legacy alias; deprecated)
470
+ - Session duration can be configured during `init(...)` via:
471
+ - `sessionDurationSeconds`
467
472
 
468
473
  ## App Lifecycle Events (iOS)
469
474
 
@@ -479,7 +484,8 @@ When automatic tracking is enabled, the native iOS SDK can report these events:
479
484
  Related automatic events controlled by the same init options:
480
485
 
481
486
  - Push subscription status events (`pushSubscriptionEnabled`)
482
- - Session events (`sessionEventsEnabled`)
487
+ - Session events (`sessionStartEventsEnabled` / `sessionEndEventsEnabled`)
488
+ - Foreground lifecycle events (`foregroundLifecycleEnabled`)
483
489
 
484
490
  Screen view tracking:
485
491
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cordova-plugin-reteno",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "The Reteno Cordova Plugin for Mobile Customer Engagement and Analytics solutions",
5
5
  "types": "./types/index.ts",
6
6
  "files": [
@@ -23,6 +23,8 @@
23
23
  "LICENSE*"
24
24
  ],
25
25
  "scripts": {
26
+ "test": "jest --coverage",
27
+ "test:watch": "jest --watch",
26
28
  "lint": "eslint \"www/**/*.js\"",
27
29
  "lint:fix": "eslint --fix \"www/**/*.js\"",
28
30
  "format": "prettier --write \"{www,types,docs}/**/*.{js,ts,md,json,xml}\"",
@@ -39,7 +41,7 @@
39
41
  },
40
42
  "keywords": [
41
43
  "ecosystem:cordova",
42
- "cordova-android",
44
+ "cordova-android",
43
45
  "cordova-ios"
44
46
  ],
45
47
  "author": "mobile-sdk@reteno.com",
@@ -49,11 +51,12 @@
49
51
  },
50
52
  "homepage": "https://github.com/reteno-com/cordova-plugin-reteno#readme",
51
53
  "license": "MIT",
52
- "dependencies": {},
53
54
  "devDependencies": {
54
55
  "@cordova/eslint-config": "^5.0.0",
55
56
  "eslint": "^8.57.1",
56
57
  "eslint-config-prettier": "^9.1.0",
58
+ "jest": "^30.3.0",
59
+ "jest-environment-jsdom": "^30.3.0",
57
60
  "prettier": "^3.4.2",
58
61
  "typescript": "^5.7.3"
59
62
  }
package/plugin.xml CHANGED
@@ -1,5 +1,5 @@
1
1
  <?xml version='1.0' encoding='utf-8'?>
2
- <plugin id="cordova-plugin-reteno" version="2.0.2" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
2
+ <plugin id="cordova-plugin-reteno" version="2.0.4" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
3
3
  <name>cordova-plugin-reteno</name>
4
4
  <engines>
5
5
  <engine name="cordova-android" version=">=12.0.0" />
@@ -58,7 +58,7 @@
58
58
 
59
59
  <podspec>
60
60
  <pods>
61
- <pod name="Reteno" spec="2.6.2" />
61
+ <pod name="Reteno" spec="2.7.0" />
62
62
  <pod name="FirebaseMessaging" />
63
63
  </pods>
64
64
  </podspec>
@@ -1,6 +1,6 @@
1
1
  apply plugin: 'com.android.application'
2
2
 
3
- def retenoFcmVersion = '2.9.2'
3
+ def retenoFcmVersion = '2.9.4'
4
4
 
5
5
  android {
6
6
  namespace 'com.reteno.plugin'
@@ -40,4 +40,4 @@ dependencies {
40
40
  testImplementation 'junit:junit:4.13.2'
41
41
  androidTestImplementation 'androidx.test.ext:junit:1.1.3'
42
42
  androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
43
- }
43
+ }
@@ -572,6 +572,13 @@ public class RetenoPlugin extends CordovaPlugin {
572
572
  }
573
573
  }
574
574
 
575
+ if (options != null && options.has("sessionDurationSeconds")) {
576
+ long sessionDurationSeconds = options.optLong("sessionDurationSeconds", -1L);
577
+ if (sessionDurationSeconds > 0L) {
578
+ builder.sessionDuration(sessionDurationSeconds * 1000L);
579
+ }
580
+ }
581
+
575
582
  // Ensure AndroidX Startup initializer has created the Reteno instance.
576
583
  // We intentionally do not short-circuit initialization just because getInstance() is non-null;
577
584
  // the SDK still needs to receive config (access key/debug/etc.).
@@ -601,7 +608,7 @@ public class RetenoPlugin extends CordovaPlugin {
601
608
  }
602
609
 
603
610
  /**
604
- * Register notification event listeners using the SDK 2.9.2 EventListener API.
611
+ * Register notification event listeners using the SDK 2.9.4 EventListener API.
605
612
  * Each listener is a direct {@link Procedure} implementation — no reflection needed.
606
613
  */
607
614
  private void registerNotificationListeners() {
@@ -1145,10 +1152,10 @@ public class RetenoPlugin extends CordovaPlugin {
1145
1152
  if (value instanceof String) {
1146
1153
  String str = ((String) value).trim();
1147
1154
  if ("ALL".equalsIgnoreCase(str)) {
1148
- return new LifecycleTrackingOptions(true, true, true);
1155
+ return new LifecycleTrackingOptions(true, true, true, true, true);
1149
1156
  }
1150
1157
  if ("NONE".equalsIgnoreCase(str)) {
1151
- return new LifecycleTrackingOptions(false, false, false);
1158
+ return new LifecycleTrackingOptions(false, false, false, false, false);
1152
1159
  }
1153
1160
  return null;
1154
1161
  }
@@ -1158,13 +1165,34 @@ public class RetenoPlugin extends CordovaPlugin {
1158
1165
  boolean appLifecycleEnabled = payload.has("appLifecycleEnabled")
1159
1166
  ? payload.optBoolean("appLifecycleEnabled", true)
1160
1167
  : true;
1168
+ boolean foregroundLifecycleEnabled = payload.has("foregroundLifecycleEnabled")
1169
+ ? payload.optBoolean("foregroundLifecycleEnabled", false)
1170
+ : false;
1161
1171
  boolean pushSubscriptionEnabled = payload.has("pushSubscriptionEnabled")
1162
1172
  ? payload.optBoolean("pushSubscriptionEnabled", true)
1163
1173
  : true;
1164
- boolean sessionEventsEnabled = payload.has("sessionEventsEnabled")
1174
+
1175
+ // Back-compat flag from <=2.9.2 plugin API.
1176
+ boolean legacySessionEventsEnabled = payload.has("sessionEventsEnabled")
1165
1177
  ? payload.optBoolean("sessionEventsEnabled", true)
1166
1178
  : true;
1167
- return new LifecycleTrackingOptions(appLifecycleEnabled, pushSubscriptionEnabled, sessionEventsEnabled);
1179
+
1180
+ boolean sessionStartEventsEnabled = payload.has("sessionStartEventsEnabled")
1181
+ ? payload.optBoolean("sessionStartEventsEnabled", legacySessionEventsEnabled)
1182
+ : legacySessionEventsEnabled;
1183
+
1184
+ // SDK 2.9.4 default for session end is disabled unless explicitly enabled.
1185
+ boolean sessionEndEventsEnabled = payload.has("sessionEndEventsEnabled")
1186
+ ? payload.optBoolean("sessionEndEventsEnabled", false)
1187
+ : (payload.has("sessionEventsEnabled") ? legacySessionEventsEnabled : false);
1188
+
1189
+ return new LifecycleTrackingOptions(
1190
+ appLifecycleEnabled,
1191
+ foregroundLifecycleEnabled,
1192
+ pushSubscriptionEnabled,
1193
+ sessionStartEventsEnabled,
1194
+ sessionEndEventsEnabled
1195
+ );
1168
1196
  }
1169
1197
 
1170
1198
  return null;
@@ -5,7 +5,7 @@ allprojects {
5
5
  }
6
6
  }
7
7
 
8
- def retenoFcmVersion = '2.9.2'
8
+ def retenoFcmVersion = '2.9.4'
9
9
 
10
10
  def firebaseMessagingVersion = '23.1.0'
11
11
 
@@ -69,13 +69,15 @@ class RetenoPlugin: CDVPlugin {
69
69
  let lifecycleOptionsInput = options["lifecycleTrackingOptions"]
70
70
  let lifecycleOptions: (
71
71
  appLifecycleEnabled: Bool,
72
+ foregroundLifecycleEnabled: Bool,
72
73
  pushSubscriptionEnabled: Bool,
73
- sessionEventsEnabled: Bool
74
+ sessionStartEventsEnabled: Bool,
75
+ sessionEndEventsEnabled: Bool
74
76
  )?
75
77
  if let lifecycleOptionsInput, !(lifecycleOptionsInput is NSNull) {
76
78
  guard let parsedOptions = parseLifecycleTrackingOptions(lifecycleOptionsInput) else {
77
79
  sendError(
78
- "Invalid argument: lifecycleTrackingOptions. Expected 'ALL', 'NONE', or { appLifecycleEnabled, pushSubscriptionEnabled, sessionEventsEnabled }.",
80
+ "Invalid argument: lifecycleTrackingOptions. Expected 'ALL', 'NONE', or { appLifecycleEnabled, foregroundLifecycleEnabled, pushSubscriptionEnabled, sessionStartEventsEnabled, sessionEndEventsEnabled }.",
79
81
  to: command
80
82
  )
81
83
  return
@@ -85,8 +87,21 @@ class RetenoPlugin: CDVPlugin {
85
87
  lifecycleOptions = nil
86
88
  }
87
89
  let lifecycleAppEnabled = lifecycleOptions?.appLifecycleEnabled ?? true
90
+ let lifecycleForegroundEnabled = lifecycleOptions?.foregroundLifecycleEnabled ?? false
88
91
  let lifecyclePushEnabled = lifecycleOptions?.pushSubscriptionEnabled ?? true
89
- let lifecycleSessionEnabled = lifecycleOptions?.sessionEventsEnabled ?? true
92
+ let lifecycleSessionStartEnabled = lifecycleOptions?.sessionStartEventsEnabled ?? true
93
+ let lifecycleSessionEndEnabled = lifecycleOptions?.sessionEndEventsEnabled ?? false
94
+
95
+ let sessionDurationSeconds: TimeInterval = {
96
+ if let seconds = options["sessionDurationSeconds"] as? Double, seconds > 0 {
97
+ return seconds
98
+ }
99
+ if let seconds = options["sessionDurationSeconds"] as? Int, seconds > 0 {
100
+ return Double(seconds)
101
+ }
102
+ return RetenoSessionConfiguration.default.sessionDuration
103
+ }()
104
+
90
105
  let screenReportingEnabled = (options["isAutomaticScreenReportingEnabled"] as? Bool) ?? false
91
106
  let isDebugMode = (options["isDebugMode"] as? Bool) ?? false
92
107
 
@@ -101,8 +116,13 @@ class RetenoPlugin: CDVPlugin {
101
116
  let configuration = RetenoConfiguration(
102
117
  isAutomaticScreenReportingEnabled: screenReportingEnabled,
103
118
  isAutomaticAppLifecycleReportingEnabled: lifecycleAppEnabled,
119
+ isApplicationForegroundLifecycleReportingEnabled: lifecycleForegroundEnabled,
104
120
  isAutomaticPushSubsriptionReportingEnabled: lifecyclePushEnabled,
105
- isAutomaticSessionReportingEnabled: lifecycleSessionEnabled,
121
+ sessionConfiguration: RetenoSessionConfiguration(
122
+ sessionDuration: sessionDurationSeconds,
123
+ isSessionStartReportingEnabled: lifecycleSessionStartEnabled,
124
+ isSessionEndReportingEnabled: lifecycleSessionEndEnabled
125
+ ),
106
126
  isPausedInAppMessages: pauseInAppMessages,
107
127
  inAppMessagesPauseBehaviour: inAppMessagesPauseBehaviour,
108
128
  isDebugMode: isDebugMode,
@@ -1359,24 +1379,30 @@ class RetenoPlugin: CDVPlugin {
1359
1379
 
1360
1380
  private func parseLifecycleTrackingOptions(_ value: Any?) -> (
1361
1381
  appLifecycleEnabled: Bool,
1382
+ foregroundLifecycleEnabled: Bool,
1362
1383
  pushSubscriptionEnabled: Bool,
1363
- sessionEventsEnabled: Bool
1384
+ sessionStartEventsEnabled: Bool,
1385
+ sessionEndEventsEnabled: Bool
1364
1386
  )? {
1365
1387
  if let raw = stringValue(value) {
1366
1388
  if raw.caseInsensitiveCompare("ALL") == .orderedSame {
1367
- return (true, true, true)
1389
+ return (true, true, true, true, true)
1368
1390
  }
1369
1391
  if raw.caseInsensitiveCompare("NONE") == .orderedSame {
1370
- return (false, false, false)
1392
+ return (false, false, false, false, false)
1371
1393
  }
1372
1394
  return nil
1373
1395
  }
1374
1396
 
1375
1397
  guard let payload = dictionaryValue(value) else { return nil }
1398
+ let legacySessionEventsEnabled = (payload["sessionEventsEnabled"] as? Bool) ?? true
1376
1399
  return (
1377
1400
  appLifecycleEnabled: (payload["appLifecycleEnabled"] as? Bool) ?? true,
1401
+ foregroundLifecycleEnabled: (payload["foregroundLifecycleEnabled"] as? Bool) ?? false,
1378
1402
  pushSubscriptionEnabled: (payload["pushSubscriptionEnabled"] as? Bool) ?? true,
1379
- sessionEventsEnabled: (payload["sessionEventsEnabled"] as? Bool) ?? true
1403
+ sessionStartEventsEnabled: (payload["sessionStartEventsEnabled"] as? Bool) ?? legacySessionEventsEnabled,
1404
+ sessionEndEventsEnabled: (payload["sessionEndEventsEnabled"] as? Bool) ??
1405
+ (payload.keys.contains("sessionEventsEnabled") ? legacySessionEventsEnabled : false)
1380
1406
  )
1381
1407
  }
1382
1408
 
package/types/index.ts CHANGED
@@ -77,8 +77,13 @@ export type NotificationResponseHandlerOptions = {
77
77
  export type LifecycleTrackingOptions =
78
78
  | {
79
79
  appLifecycleEnabled?: boolean | null;
80
+ foregroundLifecycleEnabled?: boolean | null;
80
81
  pushSubscriptionEnabled?: boolean | null;
82
+ /** @deprecated Use sessionStartEventsEnabled/sessionEndEventsEnabled instead. */
83
+ /** Backward-compatible alias for setting both sessionStart/sessionEnd */
81
84
  sessionEventsEnabled?: boolean | null;
85
+ sessionStartEventsEnabled?: boolean | null;
86
+ sessionEndEventsEnabled?: boolean | null;
82
87
  }
83
88
  | 'ALL'
84
89
  | 'NONE'
@@ -92,6 +97,8 @@ export type RetenoInitializeOptions = {
92
97
  inAppMessagesPauseBehaviour?: InAppPauseBehaviour;
93
98
  isAutomaticScreenReportingEnabled?: boolean;
94
99
  lifecycleTrackingOptions?: LifecycleTrackingOptions;
100
+ /** Session reset duration in seconds (Android 2.9.4+, iOS 2.7.0+). */
101
+ sessionDurationSeconds?: number;
95
102
  /** Enables Reteno debug mode for near real-time event monitoring. Use only with test devices. */
96
103
  isDebugMode?: boolean;
97
104
  };
@@ -1,8 +1,8 @@
1
- var exec = require('cordova/exec');
1
+ const exec = require('cordova/exec');
2
2
 
3
- var PLUGIN_NAME = 'RetenoPlugin';
3
+ const PLUGIN_NAME = 'RetenoPlugin';
4
4
 
5
- var __retenoState = {
5
+ const __retenoState = {
6
6
  initialized: false,
7
7
  initPromise: null,
8
8
  pendingInitOptions: {},
@@ -23,7 +23,7 @@ function __promiseExec(action, args) {
23
23
  }
24
24
 
25
25
  function __callWithExec(action, args, success, error) {
26
- var p = __promiseExec(action, args);
26
+ const p = __promiseExec(action, args);
27
27
  if (__isFn(success) || __isFn(error)) {
28
28
  p.then(function (res) {
29
29
  if (__isFn(success)) success(res);
@@ -45,8 +45,8 @@ function __ensureInit(options) {
45
45
  return __retenoState.initPromise;
46
46
  }
47
47
 
48
- var pendingOptions = __retenoState.pendingInitOptions || {};
49
- var opts = Object.assign({}, pendingOptions, options || {});
48
+ const pendingOptions = __retenoState.pendingInitOptions || {};
49
+ const opts = Object.assign({}, pendingOptions, options || {});
50
50
  __retenoState.initPromise = __promiseExec('initialize', [opts])
51
51
  .then(function (res) {
52
52
  __retenoState.initialized = true;
@@ -64,7 +64,7 @@ function __ensureInit(options) {
64
64
  }
65
65
 
66
66
  function __callWithAutoInit(action, args, success, error) {
67
- var p = __ensureInit().then(function () {
67
+ const p = __ensureInit().then(function () {
68
68
  return __promiseExec(action, args);
69
69
  });
70
70
  if (__isFn(success) || __isFn(error)) {
@@ -134,7 +134,7 @@ var urlutil = require('cordova/urlutil');
134
134
  })();
135
135
  */
136
136
 
137
- var RetenoPluginFunctions = {
137
+ const RetenoPluginFunctions = {
138
138
  /*
139
139
  options: {
140
140
  accessKey?: string,
@@ -143,7 +143,15 @@ var RetenoPluginFunctions = {
143
143
  inAppMessagesPauseBehaviour?: 'SKIP_IN_APPS' | 'POSTPONE_IN_APPS',
144
144
  isAutomaticScreenReportingEnabled?: boolean,
145
145
  isDebugMode?: boolean,
146
- lifecycleTrackingOptions?: { appLifecycleEnabled?: boolean, pushSubscriptionEnabled?: boolean, sessionEventsEnabled?: boolean }
146
+ sessionDurationSeconds?: number, // Android 2.9.4+, iOS 2.7.0+
147
+ lifecycleTrackingOptions?: {
148
+ appLifecycleEnabled?: boolean,
149
+ foregroundLifecycleEnabled?: boolean,
150
+ pushSubscriptionEnabled?: boolean,
151
+ sessionEventsEnabled?: boolean, // backward-compatible alias
152
+ sessionStartEventsEnabled?: boolean,
153
+ sessionEndEventsEnabled?: boolean
154
+ }
147
155
  }
148
156
  */
149
157
  init: function (arg0, success, error) {
@@ -154,8 +162,8 @@ var RetenoPluginFunctions = {
154
162
  arg0 = {};
155
163
  }
156
164
 
157
- var options = arg0 || {};
158
- var p = __ensureInit(options);
165
+ const options = arg0 || {};
166
+ const p = __ensureInit(options);
159
167
  if (__isFn(success) || __isFn(error)) {
160
168
  p.then(function (res) {
161
169
  if (__isFn(success)) success(res);
@@ -185,7 +193,7 @@ var RetenoPluginFunctions = {
185
193
  */
186
194
  logEcommerceEvent: function (arg0, success, error) {
187
195
  // Accept either `payload` or legacy `[payload]`.
188
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
196
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
189
197
  if (!payload || typeof payload !== 'object') {
190
198
  return Promise.reject(new Error('Missing argument: payload'));
191
199
  }
@@ -200,7 +208,7 @@ var RetenoPluginFunctions = {
200
208
  */
201
209
  setUserAttributes: function (arg0, success, error) {
202
210
  // Accept either `payload` or legacy `[payload]`.
203
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
211
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
204
212
  if (
205
213
  !payload ||
206
214
  !payload.externalUserId ||
@@ -216,7 +224,7 @@ var RetenoPluginFunctions = {
216
224
  */
217
225
  setAnonymousUserAttributes: function (arg0, success, error) {
218
226
  // Accept either `payload` or legacy `[payload]`.
219
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
227
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
220
228
  if (!payload || typeof payload !== 'object') {
221
229
  return Promise.reject(new Error('Missing argument: payload'));
222
230
  }
@@ -247,7 +255,7 @@ var RetenoPluginFunctions = {
247
255
  */
248
256
  setMultiAccountUserAttributes: function (arg0, success, error) {
249
257
  // Accept either `payload` or legacy `[payload]`.
250
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
258
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
251
259
  if (
252
260
  !payload ||
253
261
  !payload.externalUserId ||
@@ -270,7 +278,7 @@ var RetenoPluginFunctions = {
270
278
  // Back-compat:
271
279
  // - setOnRetenoPushReceivedListener(listener)
272
280
  // - setOnRetenoPushReceivedListener(reteno, listener) (legacy)
273
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
281
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
274
282
  if (typeof listener !== 'function') return;
275
283
  document.addEventListener('reteno-push-received', listener);
276
284
  },
@@ -279,7 +287,7 @@ var RetenoPluginFunctions = {
279
287
  // Back-compat:
280
288
  // - setOnRetenoNotificationClickedListener(listener)
281
289
  // - setOnRetenoNotificationClickedListener(reteno, listener) (legacy)
282
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
290
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
283
291
  if (typeof listener !== 'function') return;
284
292
  document.addEventListener('reteno-notification-clicked', listener);
285
293
  },
@@ -298,20 +306,20 @@ var RetenoPluginFunctions = {
298
306
  // Back-compat:
299
307
  // - setOnInAppMessageCustomDataReceivedListener(listener)
300
308
  // - setOnInAppMessageCustomDataReceivedListener(reteno, listener) (legacy)
301
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
309
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
302
310
  if (typeof listener !== 'function') return;
303
311
  document.addEventListener('reteno-in-app-custom-data', listener);
304
312
  },
305
313
 
306
314
  removeOnInAppMessageCustomDataReceivedListener: function (arg0, arg1) {
307
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
315
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
308
316
  if (typeof listener !== 'function') return;
309
317
  document.removeEventListener('reteno-in-app-custom-data', listener);
310
318
  },
311
319
 
312
320
  // Push notification dismissed (swiped away)
313
321
  setOnRetenoPushDismissedListener: function (arg0, arg1) {
314
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
322
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
315
323
  if (typeof listener !== 'function') return;
316
324
  document.addEventListener('reteno-push-dismissed', listener);
317
325
  },
@@ -323,7 +331,7 @@ var RetenoPluginFunctions = {
323
331
 
324
332
  // Custom push notification received
325
333
  setOnRetenoCustomPushReceivedListener: function (arg0, arg1) {
326
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
334
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
327
335
  if (typeof listener !== 'function') return;
328
336
  document.addEventListener('reteno-custom-push-received', listener);
329
337
  },
@@ -335,7 +343,7 @@ var RetenoPluginFunctions = {
335
343
 
336
344
  // Push notification action button clicked (iOS & Android)
337
345
  setOnRetenoPushButtonClickedListener: function (arg0, arg1) {
338
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
346
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
339
347
  if (typeof listener !== 'function') return;
340
348
  document.addEventListener('reteno-push-button-clicked', listener);
341
349
  },
@@ -361,7 +369,7 @@ var RetenoPluginFunctions = {
361
369
  },
362
370
 
363
371
  setOnInAppLifecycleCallback: function (arg0, arg1) {
364
- var listener = typeof arg0 === 'function' ? arg0 : arg1;
372
+ const listener = typeof arg0 === 'function' ? arg0 : arg1;
365
373
  if (arg0 === null || listener === null) {
366
374
  return __callWithAutoInit('setInAppLifecycleCallback', [null]);
367
375
  }
@@ -384,13 +392,13 @@ var RetenoPluginFunctions = {
384
392
  */
385
393
  setLifecycleTrackingOptions: function (arg0, success, error) {
386
394
  // Accept either `options` or legacy `[options]`.
387
- var options = Array.isArray(arg0) ? arg0[0] : arg0;
395
+ const options = Array.isArray(arg0) ? arg0[0] : arg0;
388
396
  if (!options) {
389
397
  return Promise.reject(new Error('Missing argument: options'));
390
398
  }
391
399
 
392
400
  if (__isIosPlatform()) {
393
- var p;
401
+ let p;
394
402
  if (__retenoState.initialized || __retenoState.initPromise) {
395
403
  p = Promise.reject(
396
404
  new Error('iOS supports lifecycleTrackingOptions only during init(...) before SDK initialization.')
@@ -449,7 +457,7 @@ var RetenoPluginFunctions = {
449
457
  isPaused: boolean
450
458
  */
451
459
  pauseInAppMessages: function (arg0, success, error) {
452
- var isPaused = !!arg0;
460
+ const isPaused = !!arg0;
453
461
  return __callWithAutoInit('pauseInAppMessages', [isPaused], success, error);
454
462
  },
455
463
 
@@ -495,7 +503,7 @@ var RetenoPluginFunctions = {
495
503
  */
496
504
  updateDefaultNotificationChannel: function (arg0, success, error) {
497
505
  // Accept either `config` or legacy `[config]`.
498
- var config = Array.isArray(arg0) ? arg0[0] : arg0;
506
+ const config = Array.isArray(arg0) ? arg0[0] : arg0;
499
507
  if (!config || typeof config !== 'object') {
500
508
  return Promise.reject(new Error('Missing argument: config'));
501
509
  }
@@ -518,7 +526,7 @@ var RetenoPluginFunctions = {
518
526
  */
519
527
  getAppInboxMessages: function (arg0, success, error) {
520
528
  // Accept either `payload` or legacy `[payload]`.
521
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
529
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
522
530
  if (!payload || typeof payload !== 'object') {
523
531
  return Promise.reject(new Error('Missing argument: payload'));
524
532
  }
@@ -536,8 +544,8 @@ var RetenoPluginFunctions = {
536
544
  },
537
545
 
538
546
  subscribeOnMessagesCountChanged: function (arg0, arg1) {
539
- var success = typeof arg0 === 'function' ? arg0 : arg1;
540
- var error = typeof arg0 === 'function' ? arg1 : undefined;
547
+ const success = typeof arg0 === 'function' ? arg0 : arg1;
548
+ const error = typeof arg0 === 'function' ? arg1 : undefined;
541
549
  return __ensureInit().then(function () {
542
550
  exec(success, error, PLUGIN_NAME, 'subscribeOnMessagesCountChanged', []);
543
551
  return 1;
@@ -553,7 +561,7 @@ var RetenoPluginFunctions = {
553
561
  */
554
562
  markAsOpened: function (arg0, success, error) {
555
563
  // Accept either `messageId` or legacy `[messageId]`.
556
- var messageId = Array.isArray(arg0) ? arg0[0] : arg0;
564
+ const messageId = Array.isArray(arg0) ? arg0[0] : arg0;
557
565
  if (!messageId || typeof messageId !== 'string' || messageId.trim().length === 0) {
558
566
  return Promise.reject(new Error('Missing argument: messageId'));
559
567
  }
@@ -569,7 +577,7 @@ var RetenoPluginFunctions = {
569
577
  */
570
578
  getRecommendations: function (arg0, success, error) {
571
579
  // Accept either `payload` or legacy `[payload]`.
572
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
580
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
573
581
  if (!payload || typeof payload !== 'object') {
574
582
  return Promise.reject(new Error('Missing argument: payload'));
575
583
  }
@@ -588,7 +596,7 @@ var RetenoPluginFunctions = {
588
596
  */
589
597
  logRecommendations: function (arg0, success, error) {
590
598
  // Accept either `payload` or legacy `[payload]`.
591
- var payload = Array.isArray(arg0) ? arg0[0] : arg0;
599
+ const payload = Array.isArray(arg0) ? arg0[0] : arg0;
592
600
  if (!payload || typeof payload !== 'object') {
593
601
  return Promise.reject(new Error('Missing argument: payload'));
594
602
  }