@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.
- package/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativeModule.kt +101 -0
- package/android/src/main/java/com/amplitude/reactnative/LegacyDatabaseStorage.kt +313 -0
- package/ios/AmplitudeReactNative.m +3 -0
- package/ios/AmplitudeReactNative.swift +74 -0
- package/ios/AmplitudeReactNative.xcodeproj/project.pbxproj +9 -17
- package/ios/LegacyDatabaseStorage.swift +224 -0
- package/lib/commonjs/config.js +19 -7
- package/lib/commonjs/config.js.map +1 -1
- package/lib/commonjs/migration/remnant-data-migration.js +170 -0
- package/lib/commonjs/migration/remnant-data-migration.js.map +1 -0
- package/lib/commonjs/react-native-client.js +46 -27
- package/lib/commonjs/react-native-client.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/config.js +18 -7
- package/lib/module/config.js.map +1 -1
- package/lib/module/migration/remnant-data-migration.js +163 -0
- package/lib/module/migration/remnant-data-migration.js.map +1 -0
- package/lib/module/react-native-client.js +46 -27
- package/lib/module/react-native-client.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/config.d.ts.map +1 -1
- package/lib/typescript/migration/remnant-data-migration.d.ts +20 -0
- package/lib/typescript/migration/remnant-data-migration.d.ts.map +1 -0
- package/lib/typescript/react-native-client.d.ts +3 -0
- package/lib/typescript/react-native-client.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +5 -5
- package/src/config.ts +26 -7
- package/src/migration/remnant-data-migration.ts +168 -0
- package/src/react-native-client.ts +50 -26
- 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;
|
|
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.
|
|
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.
|
|
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.
|
|
62
|
-
"@amplitude/analytics-core": "^1.2.
|
|
63
|
-
"@amplitude/analytics-types": "^1.3.
|
|
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": "
|
|
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
|
-
|
|
193
|
-
|
|
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
|
-
|
|
196
|
-
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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 ??
|
|
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(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (
|
|
263
|
-
this.
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
272
|
-
|
|
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(
|
|
276
|
-
return
|
|
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
|
|
287
|
-
this.
|
|
288
|
-
|
|
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.
|
|
1
|
+
export const VERSION = '1.3.4';
|