@amplitude/analytics-react-native 1.3.2 → 1.3.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.
Files changed (31) hide show
  1. package/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativeModule.kt +101 -0
  2. package/android/src/main/java/com/amplitude/reactnative/LegacyDatabaseStorage.kt +313 -0
  3. package/ios/AmplitudeReactNative.m +3 -0
  4. package/ios/AmplitudeReactNative.swift +74 -0
  5. package/ios/AmplitudeReactNative.xcodeproj/project.pbxproj +9 -17
  6. package/ios/LegacyDatabaseStorage.swift +224 -0
  7. package/lib/commonjs/config.js +19 -7
  8. package/lib/commonjs/config.js.map +1 -1
  9. package/lib/commonjs/migration/remnant-data-migration.js +170 -0
  10. package/lib/commonjs/migration/remnant-data-migration.js.map +1 -0
  11. package/lib/commonjs/react-native-client.js +46 -27
  12. package/lib/commonjs/react-native-client.js.map +1 -1
  13. package/lib/commonjs/version.js +1 -1
  14. package/lib/module/config.js +18 -7
  15. package/lib/module/config.js.map +1 -1
  16. package/lib/module/migration/remnant-data-migration.js +163 -0
  17. package/lib/module/migration/remnant-data-migration.js.map +1 -0
  18. package/lib/module/react-native-client.js +46 -27
  19. package/lib/module/react-native-client.js.map +1 -1
  20. package/lib/module/version.js +1 -1
  21. package/lib/typescript/config.d.ts.map +1 -1
  22. package/lib/typescript/migration/remnant-data-migration.d.ts +20 -0
  23. package/lib/typescript/migration/remnant-data-migration.d.ts.map +1 -0
  24. package/lib/typescript/react-native-client.d.ts +3 -0
  25. package/lib/typescript/react-native-client.d.ts.map +1 -1
  26. package/lib/typescript/version.d.ts +1 -1
  27. package/package.json +5 -5
  28. package/src/config.ts +26 -7
  29. package/src/migration/remnant-data-migration.ts +168 -0
  30. package/src/react-native-client.ts +50 -26
  31. package/src/version.ts +1 -1
@@ -25,9 +25,12 @@ export declare class AmplitudeReactNative extends AmplitudeCore {
25
25
  process(event: Event): Promise<Result>;
26
26
  currentTimeMillis(): number;
27
27
  private startNewSessionIfNeeded;
28
+ private shouldStartNewSession;
28
29
  private isWithinMinTimeBetweenSessions;
29
30
  private inSession;
30
31
  private readonly handleAppStateChange;
32
+ private enterForeground;
33
+ private exitForeground;
31
34
  }
32
35
  export declare const createInstance: () => ReactNativeClient;
33
36
  declare const _default: ReactNativeClient;
@@ -1 +1 @@
1
- {"version":3,"file":"react-native-client.d.ts","sourceRoot":"","sources":["../../src/react-native-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,cAAc,EAA2B,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,aAAa,EAOd,MAAM,2BAA2B,CAAC;AAQnC,OAAO,EACL,iBAAiB,EAEjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,IAAI,SAAS,EACrB,YAAY,EACZ,KAAK,EACL,MAAM,EACP,MAAM,4BAA4B,CAAC;AASpC,qBAAa,oBAAqB,SAAQ,aAAa;IACrD,QAAQ,EAAE,cAAc,CAAgB;IACxC,OAAO,CAAC,qBAAqB,CAAsC;IACnE,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAGtC,MAAM,EAAE,iBAAiB,CAAC;IAE1B,IAAI,CAAC,MAAM,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;cAG/C,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE;IA6DtE,QAAQ;IAIF,sBAAsB,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,YAAY,UAAQ;IAkBzF,SAAS;IAIT,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS;IASpC,WAAW;IAIX,WAAW,CAAC,QAAQ,EAAE,MAAM;IAS5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,YAAY;IAUzD,KAAK;IAKL,YAAY;IAIZ,YAAY,CAAC,SAAS,EAAE,MAAM;IAU9B,aAAa;IAQb,OAAO,CAAC,oBAAoB;IAgCtB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IA4B5C,iBAAiB;IAIjB,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,8BAA8B;IAItC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAOnC;CACH;AAED,eAAO,MAAM,cAAc,QAAO,iBAsHjC,CAAC;;AAEF,wBAAgC"}
1
+ {"version":3,"file":"react-native-client.d.ts","sourceRoot":"","sources":["../../src/react-native-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,cAAc,EAA2B,MAAM,cAAc,CAAC;AACjF,OAAO,EACL,aAAa,EAOd,MAAM,2BAA2B,CAAC;AAQnC,OAAO,EACL,iBAAiB,EAEjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,QAAQ,IAAI,SAAS,EACrB,YAAY,EACZ,KAAK,EACL,MAAM,EACP,MAAM,4BAA4B,CAAC;AASpC,qBAAa,oBAAqB,SAAQ,aAAa;IACrD,QAAQ,EAAE,cAAc,CAAgB;IACxC,OAAO,CAAC,qBAAqB,CAAsC;IACnE,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAGtC,MAAM,EAAE,iBAAiB,CAAC;IAE1B,IAAI,CAAC,MAAM,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;cAG/C,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE;IA6DtE,QAAQ;IAIF,sBAAsB,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,YAAY,UAAQ;IAkBzF,SAAS;IAIT,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS;IASpC,WAAW;IAIX,WAAW,CAAC,QAAQ,EAAE,MAAM;IAS5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,YAAY;IAUzD,KAAK;IAKL,YAAY;IAIZ,YAAY,CAAC,SAAS,EAAE,MAAM;IAU9B,aAAa;IAQb,OAAO,CAAC,oBAAoB;IAgCtB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAiC5C,iBAAiB;IAIjB,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,8BAA8B;IAItC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAWnC;IAEF,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,cAAc;CAGvB;AAED,eAAO,MAAM,cAAc,QAAO,iBAsHjC,CAAC;;AAEF,wBAAgC"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.3.2";
1
+ export declare const VERSION = "1.3.4";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amplitude/analytics-react-native",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Official React Native SDK",
5
5
  "keywords": [
6
6
  "analytics",
@@ -58,9 +58,9 @@
58
58
  "url": "https://github.com/amplitude/Amplitude-TypeScript/issues"
59
59
  },
60
60
  "dependencies": {
61
- "@amplitude/analytics-client-common": "^1.1.1",
62
- "@amplitude/analytics-core": "^1.2.1",
63
- "@amplitude/analytics-types": "^1.3.1",
61
+ "@amplitude/analytics-client-common": "^1.1.2",
62
+ "@amplitude/analytics-core": "^1.2.2",
63
+ "@amplitude/analytics-types": "^1.3.2",
64
64
  "@amplitude/ua-parser-js": "^0.7.31",
65
65
  "@react-native-async-storage/async-storage": "^1.17.11",
66
66
  "tslib": "^2.4.1"
@@ -90,5 +90,5 @@
90
90
  ]
91
91
  ]
92
92
  },
93
- "gitHead": "6d9cf5f1a05293815917f2136914493a67a9256f"
93
+ "gitHead": "2957c0bbbce4dffc2e3f0f4767cf9d443bafd62c"
94
94
  }
package/src/config.ts CHANGED
@@ -10,6 +10,7 @@ import { Config, MemoryStorage, UUID } from '@amplitude/analytics-core';
10
10
  import { CookieStorage, getCookieName, getQueryParams, FetchTransport } from '@amplitude/analytics-client-common';
11
11
 
12
12
  import { LocalStorage } from './storage/local-storage';
13
+ import RemnantDataMigration from './migration/remnant-data-migration';
13
14
 
14
15
  export const getDefaultConfig = () => {
15
16
  const cookieStorage = new MemoryStorage<UserSession>();
@@ -189,21 +190,39 @@ export const useReactNativeConfig = async (
189
190
  const queryParams = getQueryParams();
190
191
 
191
192
  // reconcile user session
192
- const deviceId = options?.deviceId ?? queryParams.deviceId ?? previousCookies?.deviceId ?? UUID();
193
- const lastEventTime = options?.lastEventTime ?? previousCookies?.lastEventTime;
193
+ let deviceId = options?.deviceId ?? queryParams.deviceId ?? previousCookies?.deviceId;
194
+ let lastEventTime = options?.lastEventTime ?? previousCookies?.lastEventTime;
194
195
  const optOut = options?.optOut ?? Boolean(previousCookies?.optOut);
195
- const sessionId = options?.sessionId ?? previousCookies?.sessionId;
196
- const userId = options?.userId ?? previousCookies?.userId;
196
+ let sessionId = options?.sessionId ?? previousCookies?.sessionId;
197
+ let userId = options?.userId ?? previousCookies?.userId;
198
+ let lastEventId = previousCookies?.lastEventId;
199
+
200
+ const storageProvider = options?.storageProvider ?? (await createEventsStorage(options));
201
+
202
+ if (options?.migrateLegacyData !== false) {
203
+ const legacySessionData = await new RemnantDataMigration(
204
+ apiKey,
205
+ options?.instanceName,
206
+ storageProvider,
207
+ previousCookies?.lastEventTime === undefined,
208
+ options?.loggerProvider,
209
+ ).execute();
210
+ deviceId = deviceId ?? legacySessionData.deviceId;
211
+ userId = userId ?? legacySessionData.userId;
212
+ sessionId = sessionId ?? legacySessionData.sessionId;
213
+ lastEventTime = lastEventTime ?? legacySessionData.lastEventTime;
214
+ lastEventId = lastEventId ?? legacySessionData.lastEventId;
215
+ }
197
216
 
198
217
  const config = new ReactNativeConfig(apiKey, {
199
218
  ...options,
200
219
  cookieStorage,
201
- deviceId,
220
+ deviceId: deviceId ?? UUID(),
202
221
  domain,
203
222
  lastEventTime,
204
223
  optOut,
205
224
  sessionId,
206
- storageProvider: await createEventsStorage(options),
225
+ storageProvider,
207
226
  trackingOptions: {
208
227
  ...defaultConfig.trackingOptions,
209
228
  ...options?.trackingOptions,
@@ -212,7 +231,7 @@ export const useReactNativeConfig = async (
212
231
  userId,
213
232
  });
214
233
 
215
- config.lastEventId = previousCookies?.lastEventId;
234
+ config.lastEventId = lastEventId;
216
235
 
217
236
  config.loggerProvider?.log(
218
237
  `Init: storage=${cookieStorage.constructor.name} restoredSessionId = ${
@@ -0,0 +1,168 @@
1
+ import { NativeModules } from 'react-native';
2
+ import { Event, Logger, Storage, UserSession } from '@amplitude/analytics-types';
3
+
4
+ type LegacyEventKind = 'event' | 'identify' | 'interceptedIdentify';
5
+
6
+ interface AmplitudeReactNative {
7
+ getLegacySessionData(instanceName: string | undefined): Promise<Omit<UserSession, 'optOut'>>;
8
+ getLegacyEvents(instanceName: string | undefined, eventKind: LegacyEventKind): Promise<string[]>;
9
+ removeLegacyEvent(instanceName: string | undefined, eventKind: LegacyEventKind, eventId: number): void;
10
+ }
11
+
12
+ export default class RemnantDataMigration {
13
+ eventsStorageKey: string;
14
+ private readonly nativeModule: AmplitudeReactNative;
15
+
16
+ constructor(
17
+ private apiKey: string,
18
+ private instanceName: string | undefined,
19
+ private storage: Storage<Event[]> | undefined,
20
+ private firstRunSinceUpgrade: boolean,
21
+ private logger: Logger | undefined,
22
+ ) {
23
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
24
+ this.eventsStorageKey = `AMP_unsent_${this.apiKey.substring(0, 10)}`; // TODO Use StoragePrefix when it will be exported
25
+ this.nativeModule = NativeModules.AmplitudeReactNative as AmplitudeReactNative;
26
+ }
27
+
28
+ async execute(): Promise<Omit<UserSession, 'optOut'>> {
29
+ if (!this.nativeModule) {
30
+ return {};
31
+ }
32
+
33
+ if (this.firstRunSinceUpgrade) {
34
+ await this.moveIdentifies();
35
+ await this.moveInterceptedIdentifies();
36
+ }
37
+ await this.moveEvents();
38
+
39
+ const sessionData = await this.callNativeFunction(() => this.nativeModule.getLegacySessionData(this.instanceName));
40
+ return sessionData ?? {};
41
+ }
42
+
43
+ private async moveEvents() {
44
+ await this.moveLegacyEvents('event');
45
+ }
46
+
47
+ private async moveIdentifies() {
48
+ await this.moveLegacyEvents('identify');
49
+ }
50
+
51
+ private async moveInterceptedIdentifies() {
52
+ await this.moveLegacyEvents('interceptedIdentify');
53
+ }
54
+
55
+ private async callNativeFunction<T>(action: () => Promise<T>): Promise<T | undefined> {
56
+ try {
57
+ return await action();
58
+ } catch (e) {
59
+ this.logger?.error(`can't call native function: ${String(e)}`);
60
+ return undefined;
61
+ }
62
+ }
63
+
64
+ private callNativeAction(action: () => void) {
65
+ try {
66
+ action();
67
+ } catch (e) {
68
+ this.logger?.error(`can't call native function: ${String(e)}`);
69
+ }
70
+ }
71
+
72
+ private async moveLegacyEvents(eventKind: LegacyEventKind) {
73
+ const legacyJsonEvents = await this.callNativeFunction(() =>
74
+ this.nativeModule.getLegacyEvents(this.instanceName, eventKind),
75
+ );
76
+ if (!this.storage || !legacyJsonEvents || legacyJsonEvents.length === 0) {
77
+ return;
78
+ }
79
+
80
+ const events = (await this.storage.get(this.eventsStorageKey)) ?? [];
81
+ const eventIds: number[] = [];
82
+
83
+ legacyJsonEvents.forEach((jsonEvent) => {
84
+ const event = this.convertLegacyEvent(jsonEvent);
85
+ if (event) {
86
+ events.push(event);
87
+ if (event.event_id !== undefined) {
88
+ eventIds.push(event.event_id);
89
+ }
90
+ }
91
+ });
92
+
93
+ await this.storage.set(this.eventsStorageKey, events);
94
+ eventIds.forEach((eventId) =>
95
+ this.callNativeAction(() => this.nativeModule.removeLegacyEvent(this.instanceName, eventKind, eventId)),
96
+ );
97
+ }
98
+
99
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
100
+ private convertLegacyEvent(legacyJsonEvent: string): Event | null {
101
+ try {
102
+ const event = JSON.parse(legacyJsonEvent) as Event;
103
+
104
+ const { library, timestamp, uuid, api_properties } = event as any;
105
+ if (library !== undefined) {
106
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
107
+ event.library = `${library.name}/${library.version}`;
108
+ }
109
+ if (timestamp !== undefined) {
110
+ event.time = timestamp;
111
+ }
112
+ if (uuid !== undefined) {
113
+ event.insert_id = uuid;
114
+ }
115
+
116
+ if (api_properties) {
117
+ const { androidADID, android_app_set_id, ios_idfa, ios_idfv, productId, quantity, price, location } =
118
+ api_properties;
119
+ if (androidADID !== undefined) {
120
+ event.adid = androidADID;
121
+ }
122
+ if (android_app_set_id !== undefined) {
123
+ event.android_app_set_id = android_app_set_id;
124
+ }
125
+ if (ios_idfa !== undefined) {
126
+ event.idfa = ios_idfa;
127
+ }
128
+ if (ios_idfv !== undefined) {
129
+ event.idfv = ios_idfv;
130
+ }
131
+ if (productId !== undefined) {
132
+ event.productId = productId;
133
+ }
134
+ if (quantity !== undefined) {
135
+ event.quantity = quantity;
136
+ }
137
+ if (price !== undefined) {
138
+ event.price = price;
139
+ }
140
+ if (location !== undefined) {
141
+ const { lat, lng } = location;
142
+ event.location_lat = lat;
143
+ event.location_lng = lng;
144
+ }
145
+ }
146
+
147
+ const { $productId: productId, $quantity: quantity, $price: price, $revenueType: revenueType } = event as any;
148
+ if (productId !== undefined) {
149
+ event.productId = productId;
150
+ }
151
+ if (quantity !== undefined) {
152
+ event.quantity = quantity;
153
+ }
154
+ if (price !== undefined) {
155
+ event.price = price;
156
+ }
157
+ if (revenueType !== undefined) {
158
+ event.revenueType = revenueType;
159
+ }
160
+
161
+ return event;
162
+ } catch {
163
+ // skip invalid events
164
+ return null;
165
+ }
166
+ }
167
+ // eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
168
+ }
@@ -59,11 +59,11 @@ export class AmplitudeReactNative extends AmplitudeCore {
59
59
  // Step 2: Create react native config
60
60
  const reactNativeOptions = await useReactNativeConfig(options.apiKey, {
61
61
  ...options,
62
- deviceId: oldCookies.deviceId ?? options.deviceId,
62
+ deviceId: options.deviceId ?? oldCookies.deviceId,
63
63
  sessionId: oldCookies.sessionId,
64
64
  optOut: options.optOut ?? oldCookies.optOut,
65
65
  lastEventTime: oldCookies.lastEventTime,
66
- userId: options.userId || oldCookies.userId,
66
+ userId: options.userId ?? oldCookies.userId,
67
67
  });
68
68
  await super._init(reactNativeOptions);
69
69
 
@@ -84,7 +84,7 @@ export class AmplitudeReactNative extends AmplitudeCore {
84
84
 
85
85
  // Step 4: Manage session
86
86
  this.appState = AppState.currentState;
87
- const isNewSession = this.startNewSessionIfNeeded();
87
+ const isNewSession = this.startNewSessionIfNeeded(this.currentTimeMillis());
88
88
  this.config.loggerProvider?.log(
89
89
  `Init: startNewSessionIfNeeded = ${isNewSession ? 'yes' : 'no'}, sessionId = ${
90
90
  this.getSessionId() ?? 'undefined'
@@ -230,19 +230,24 @@ export class AmplitudeReactNative extends AmplitudeCore {
230
230
  event = { ...event, time: eventTime };
231
231
  }
232
232
 
233
- if (event.event_type != START_SESSION_EVENT && event.event_type != END_SESSION_EVENT) {
234
- if (this.appState !== 'active') {
235
- this.startNewSessionIfNeeded(eventTime);
233
+ const isSessionEvent = event.event_type === START_SESSION_EVENT || event.event_type === END_SESSION_EVENT;
234
+ const isCustomEventSessionId =
235
+ !isSessionEvent && event.session_id != undefined && event.session_id !== this.getSessionId();
236
+ if (!isCustomEventSessionId) {
237
+ if (!isSessionEvent) {
238
+ if (this.appState !== 'active') {
239
+ this.startNewSessionIfNeeded(eventTime);
240
+ }
236
241
  }
242
+ this.config.lastEventTime = eventTime;
237
243
  }
238
- this.config.lastEventTime = eventTime;
239
244
 
240
245
  if (event.session_id == undefined) {
241
246
  event.session_id = this.getSessionId();
242
247
  }
243
248
 
244
249
  if (event.event_id === undefined) {
245
- const eventId = (this.config.lastEventId ?? -1) + 1;
250
+ const eventId = (this.config.lastEventId ?? 0) + 1;
246
251
  event = { ...event, event_id: eventId };
247
252
  this.config.lastEventId = eventId;
248
253
  }
@@ -255,25 +260,31 @@ export class AmplitudeReactNative extends AmplitudeCore {
255
260
  return Date.now();
256
261
  }
257
262
 
258
- private startNewSessionIfNeeded(eventTime?: number): boolean {
259
- eventTime = eventTime ?? this.currentTimeMillis();
260
- const sessionId = this.explicitSessionId ?? eventTime;
261
-
262
- if (
263
- this.inSession() &&
264
- (this.explicitSessionId === this.config.sessionId ||
265
- (this.explicitSessionId === undefined && this.isWithinMinTimeBetweenSessions(sessionId)))
266
- ) {
267
- this.config.lastEventTime = eventTime;
268
- return false;
263
+ private startNewSessionIfNeeded(timestamp: number): boolean {
264
+ const sessionId = this.explicitSessionId ?? timestamp;
265
+
266
+ const shouldStartNewSession = this.shouldStartNewSession(timestamp);
267
+ if (shouldStartNewSession) {
268
+ this.setSessionIdInternal(sessionId, timestamp);
269
+ } else {
270
+ this.config.lastEventTime = timestamp;
269
271
  }
270
272
 
271
- this.setSessionIdInternal(sessionId, eventTime);
272
- return true;
273
+ return shouldStartNewSession;
274
+ }
275
+
276
+ private shouldStartNewSession(timestamp: number): boolean {
277
+ const sessionId = this.explicitSessionId ?? timestamp;
278
+
279
+ return (
280
+ !this.inSession() ||
281
+ (this.explicitSessionId !== this.config.sessionId &&
282
+ (this.explicitSessionId !== undefined || !this.isWithinMinTimeBetweenSessions(sessionId)))
283
+ );
273
284
  }
274
285
 
275
- private isWithinMinTimeBetweenSessions(eventTime: number) {
276
- return eventTime - (this.config.lastEventTime ?? 0) < this.config.sessionTimeout;
286
+ private isWithinMinTimeBetweenSessions(timestamp: number) {
287
+ return timestamp - (this.config.lastEventTime ?? 0) < this.config.sessionTimeout;
277
288
  }
278
289
 
279
290
  private inSession() {
@@ -283,11 +294,24 @@ export class AmplitudeReactNative extends AmplitudeCore {
283
294
  private readonly handleAppStateChange = (nextAppState: AppStateStatus) => {
284
295
  const currentAppState = this.appState;
285
296
  this.appState = nextAppState;
286
- if (currentAppState !== nextAppState && nextAppState === 'active') {
287
- this.config.loggerProvider?.log('App Activated');
288
- this.startNewSessionIfNeeded();
297
+ if (currentAppState !== nextAppState) {
298
+ const timestamp = this.currentTimeMillis();
299
+ if (nextAppState == 'active') {
300
+ this.enterForeground(timestamp);
301
+ } else {
302
+ this.exitForeground(timestamp);
303
+ }
289
304
  }
290
305
  };
306
+
307
+ private enterForeground(timestamp: number) {
308
+ this.config.loggerProvider?.log('App Activated');
309
+ return this.startNewSessionIfNeeded(timestamp);
310
+ }
311
+
312
+ private exitForeground(timestamp: number) {
313
+ this.config.lastEventTime = timestamp;
314
+ }
291
315
  }
292
316
 
293
317
  export const createInstance = (): ReactNativeClient => {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '1.3.2';
1
+ export const VERSION = '1.3.4';