@appmetrica/react-native-analytics 3.2.0 → 3.4.0

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 (55) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/io/appmetrica/analytics/reactnative/AppMetricaModule.java +73 -7
  3. package/android/src/main/java/io/appmetrica/analytics/reactnative/AppMetricaPackage.java +1 -0
  4. package/android/src/main/java/io/appmetrica/analytics/reactnative/ExceptionSerializer.java +91 -0
  5. package/android/src/main/java/io/appmetrica/analytics/reactnative/ExternalAttributionSerializer.java +44 -0
  6. package/android/src/main/java/io/appmetrica/analytics/reactnative/ReactNativeDeferredDeeplinkListener.java +48 -0
  7. package/android/src/main/java/io/appmetrica/analytics/reactnative/ReactNativeDeferredDeeplinkParametersListener.java +53 -0
  8. package/android/src/main/java/io/appmetrica/analytics/reactnative/ReporterModule.java +130 -0
  9. package/android/src/main/java/io/appmetrica/analytics/reactnative/Utils.java +55 -1
  10. package/appmetrica-react-native-analytics.podspec +1 -1
  11. package/ios/AMARNAppMetrica.m +92 -4
  12. package/ios/AMARNAppMetricaUtils.h +1 -0
  13. package/ios/AMARNAppMetricaUtils.m +46 -0
  14. package/ios/AMARNExceptionSerializer.h +6 -0
  15. package/ios/AMARNExceptionSerializer.m +65 -0
  16. package/ios/AMARNExternalAttribution.h +4 -0
  17. package/ios/AMARNExternalAttribution.m +28 -0
  18. package/ios/AMARNReporter.h +6 -0
  19. package/ios/AMARNReporter.m +131 -0
  20. package/lib/commonjs/deferredDeeplink.js +2 -0
  21. package/lib/commonjs/deferredDeeplink.js.map +1 -0
  22. package/lib/commonjs/error.js +71 -0
  23. package/lib/commonjs/error.js.map +1 -0
  24. package/lib/commonjs/externalAttribution.js +46 -0
  25. package/lib/commonjs/externalAttribution.js.map +1 -0
  26. package/lib/commonjs/index.js +68 -1
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/reporter.js +69 -0
  29. package/lib/commonjs/reporter.js.map +1 -0
  30. package/lib/module/deferredDeeplink.js +2 -0
  31. package/lib/module/deferredDeeplink.js.map +1 -0
  32. package/lib/module/error.js +63 -0
  33. package/lib/module/error.js.map +1 -0
  34. package/lib/module/externalAttribution.js +39 -0
  35. package/lib/module/externalAttribution.js.map +1 -0
  36. package/lib/module/index.js +46 -1
  37. package/lib/module/index.js.map +1 -1
  38. package/lib/module/reporter.js +62 -0
  39. package/lib/module/reporter.js.map +1 -0
  40. package/lib/typescript/src/deferredDeeplink.d.ts +10 -0
  41. package/lib/typescript/src/deferredDeeplink.d.ts.map +1 -0
  42. package/lib/typescript/src/error.d.ts +19 -0
  43. package/lib/typescript/src/error.d.ts.map +1 -0
  44. package/lib/typescript/src/externalAttribution.d.ts +15 -0
  45. package/lib/typescript/src/externalAttribution.d.ts.map +1 -0
  46. package/lib/typescript/src/index.d.ts +22 -1
  47. package/lib/typescript/src/index.d.ts.map +1 -1
  48. package/lib/typescript/src/reporter.d.ts +51 -0
  49. package/lib/typescript/src/reporter.d.ts.map +1 -0
  50. package/package.json +3 -1
  51. package/src/deferredDeeplink.ts +11 -0
  52. package/src/error.ts +87 -0
  53. package/src/externalAttribution.ts +56 -0
  54. package/src/index.ts +87 -4
  55. package/src/reporter.ts +126 -0
@@ -0,0 +1,11 @@
1
+ export type DeferredDeeplinkError = 'NO_REFERRER' | 'NOT_A_FIRST_LAUNCH' | 'PARSE_ERROR' | 'UNKNOWN';
2
+
3
+ export interface DeferredDeeplinkListener {
4
+ onSuccess: (deeplink: string) => void;
5
+ onFailure: (error: DeferredDeeplinkError, referrer?: string) => void;
6
+ }
7
+
8
+ export interface DeferredDeeplinkParametersListener {
9
+ onSuccess: (parameters: Record<string, string>) => void;
10
+ onFailure: (error: DeferredDeeplinkError, referrer?: string) => void;
11
+ }
package/src/error.ts ADDED
@@ -0,0 +1,87 @@
1
+ import { Platform } from 'react-native';
2
+ import React from 'react';
3
+
4
+ const traceRegex = /^\s*at (.*?) ?\((.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
5
+
6
+ function parseTraceLine(line: string): StackTraceItem | undefined {
7
+ const parts = traceRegex.exec(line);
8
+ if (parts === null) {
9
+ return undefined;
10
+ }
11
+ return {
12
+ fileName: parts[2],
13
+ methodName: parts[1],
14
+ column: parts[3],
15
+ line: parts[4],
16
+ };
17
+ }
18
+
19
+ function getRNVersion(): string {
20
+ const versions = Platform.constants.reactNativeVersion;
21
+ return versions.major + '.' + versions.minor + '.' + versions.patch;
22
+ }
23
+
24
+ function getReactVersion(): string {
25
+ return React.version;
26
+ }
27
+
28
+ function getPluginEnvironment(): Record<string, string> | undefined {
29
+ return {
30
+ reactVersion: getReactVersion(),
31
+ };
32
+ }
33
+
34
+ function parseStackTrace(
35
+ stackTrace?: string
36
+ ): Array<StackTraceItem> | undefined {
37
+ if (stackTrace === undefined) {
38
+ return undefined;
39
+ }
40
+ try {
41
+ const lines = stackTrace.split('\n');
42
+ const array: Array<StackTraceItem> = [];
43
+ lines?.forEach((line: string) => {
44
+ const item = parseTraceLine(line);
45
+ if (item !== undefined) {
46
+ array.push(item);
47
+ }
48
+ });
49
+ return array;
50
+ } catch(e) {
51
+ console.log(e);
52
+ return undefined;
53
+ }
54
+ }
55
+
56
+ type StackTraceItem = {
57
+ fileName?: string;
58
+ className?: string;
59
+ methodName?: string;
60
+ line?: string;
61
+ column?: string;
62
+ };
63
+
64
+ export class AppMetricaError {
65
+ message?: string;
66
+ stackTrace?: Array<StackTraceItem>;
67
+ errorName?: string;
68
+ pluginEnvironment?: Record<string, string>;
69
+ virtualMachineVersion?: string;
70
+
71
+ constructor(errorName?: string, message?: string) {
72
+ this.errorName = errorName;
73
+ this.message = message;
74
+ this.pluginEnvironment = getPluginEnvironment();
75
+ this.virtualMachineVersion = getRNVersion();
76
+ }
77
+
78
+ static withError(error: Error): AppMetricaError {
79
+ const newError = new AppMetricaError(error.name, error.message);
80
+ newError.stackTrace = parseStackTrace(error.stack);
81
+ return newError;
82
+ }
83
+
84
+ static withObject(error?: Object): AppMetricaError {
85
+ return new AppMetricaError(undefined, JSON.stringify(error));
86
+ }
87
+ }
@@ -0,0 +1,56 @@
1
+ type ExternalAttributionSource =
2
+ | 'Adjust'
3
+ | 'Airbridge'
4
+ | 'AppsFlyer'
5
+ | 'Kochava'
6
+ | 'Singular'
7
+ | 'Tenjin';
8
+
9
+ export interface ExternalAttribution {
10
+ source: ExternalAttributionSource;
11
+ value: Record<string, object>;
12
+ }
13
+
14
+ export class ExternalAttributions {
15
+ static adjust(data: Record<string, any>): ExternalAttribution {
16
+ return {
17
+ source: 'Adjust',
18
+ value: data,
19
+ };
20
+ }
21
+
22
+ static airbridge(data: Record<string, any>): ExternalAttribution {
23
+ return {
24
+ source: 'Airbridge',
25
+ value: data,
26
+ };
27
+ }
28
+
29
+ static appsflyer(data: Record<string, any>): ExternalAttribution {
30
+ return {
31
+ source: 'AppsFlyer',
32
+ value: data.data,
33
+ };
34
+ }
35
+
36
+ static kochava(data: Record<string, any>): ExternalAttribution {
37
+ return {
38
+ source: 'Kochava',
39
+ value: data.raw,
40
+ };
41
+ }
42
+
43
+ static singular(data: Map<string, object>): ExternalAttribution {
44
+ return {
45
+ source: 'Singular',
46
+ value: Object.fromEntries(data),
47
+ };
48
+ }
49
+
50
+ static tenjin(data: Record<string, any>): ExternalAttribution {
51
+ return {
52
+ source: 'Tenjin',
53
+ value: data,
54
+ };
55
+ }
56
+ }
package/src/index.ts CHANGED
@@ -2,7 +2,14 @@ import { Linking, NativeModules, Platform } from 'react-native';
2
2
  import type { ECommerceEvent } from './ecommerce';
3
3
  import type { AdRevenue, Revenue } from './revenue';
4
4
  import type { UserProfile } from './userProfile';
5
+ import type { ExternalAttribution } from './externalAttribution';
5
6
  import { normalizeAdRevenue } from './utils';
7
+ import { AppMetricaError } from './error';
8
+ import { Reporter, type IReporter, type ReporterConfig } from './reporter';
9
+ import type {
10
+ DeferredDeeplinkListener,
11
+ DeferredDeeplinkParametersListener,
12
+ } from './deferredDeeplink';
6
13
 
7
14
  const LINKING_ERROR =
8
15
  `The package '@appmetrica/react-native-analytics' doesn't seem to be linked. Make sure: \n\n` +
@@ -55,7 +62,10 @@ export type AppMetricaConfig = {
55
62
  appOpenTrackingEnabled?: boolean;
56
63
  userProfileID?: string;
57
64
 
58
- errorEnvironment?: Record<string, string | undefined>
65
+ errorEnvironment?: Record<string, string | undefined>;
66
+ appEnvironment?: Record<string, string | undefined>;
67
+ maxReportsCount?: number;
68
+ dispatchPeriodSeconds?: number;
59
69
  };
60
70
 
61
71
  export type PreloadInfo = {
@@ -93,8 +103,14 @@ export const UUID_KEY = 'appmetrica_uuid';
93
103
  export * from './ecommerce';
94
104
  export * from './revenue';
95
105
  export * from './userProfile';
106
+ export * from './externalAttribution';
107
+ export type { IReporter, ReporterConfig } from './reporter';
108
+ export * from './deferredDeeplink';
96
109
 
97
110
  export default class AppMetrica {
111
+
112
+ private static reporters: Map<string, Reporter> = new Map();
113
+
98
114
  static activate(config: AppMetricaConfig) {
99
115
  if (!activated) {
100
116
  AppMetricaNative.activate(config);
@@ -122,8 +138,24 @@ export default class AppMetrica {
122
138
  AppMetricaNative.reportAppOpen(deeplink);
123
139
  }
124
140
 
125
- static reportError(identifier: string, message: string, _reason?: Object) {
126
- AppMetricaNative.reportError(identifier, message);
141
+ static reportError(
142
+ identifier: string,
143
+ message?: string,
144
+ _reason?: Error | Object
145
+ ) {
146
+ AppMetricaNative.reportError(
147
+ identifier,
148
+ message,
149
+ _reason instanceof Error ? AppMetricaError.withError(_reason) : AppMetricaError.withObject(_reason)
150
+ );
151
+ }
152
+
153
+ static reportUnhandledException(error: Error) {
154
+ AppMetricaNative.reportUnhandledException(AppMetricaError.withError(error));
155
+ }
156
+
157
+ static reportErrorWithoutIdentifier(message: string | undefined, error: Error) {
158
+ AppMetricaNative.reportErrorWithoutIdentifier(message, AppMetricaError.withError(error));
127
159
  }
128
160
 
129
161
  static reportEvent(eventName: string, attributes?: Record<string, any>) {
@@ -174,10 +206,61 @@ export default class AppMetrica {
174
206
  }
175
207
 
176
208
  static reportUserProfile(userProfile: UserProfile) {
177
- AppMetricaNative.reportUserProfile(userProfile)
209
+ AppMetricaNative.reportUserProfile(userProfile);
178
210
  }
179
211
 
180
212
  static putErrorEnvironmentValue(key: string, value?: string) {
181
213
  AppMetricaNative.putErrorEnvironmentValue(key, value);
182
214
  }
215
+
216
+ static reportExternalAttribution(attribution: ExternalAttribution) {
217
+ AppMetricaNative.reportExternalAttribution(attribution);
218
+ }
219
+
220
+ static putAppEnvironmentValue(key: string, value?: string) {
221
+ AppMetricaNative.putAppEnvironmentValue(key, value);
222
+ }
223
+
224
+ static clearAppEnvironment() {
225
+ AppMetricaNative.clearAppEnvironment();
226
+ }
227
+
228
+ static getReporter(apiKey: string): IReporter {
229
+ if (AppMetrica.reporters.has(apiKey)) {
230
+ return AppMetrica.reporters.get(apiKey)!;
231
+ } else {
232
+ AppMetricaNative.touchReporter(apiKey);
233
+ const reporter = new Reporter(apiKey);
234
+ AppMetrica.reporters.set(apiKey, reporter);
235
+ return reporter;
236
+ }
237
+ }
238
+
239
+ static activateReporter(config: ReporterConfig) {
240
+ AppMetricaNative.activateReporter(config);
241
+ }
242
+
243
+ static getDeviceId(): Promise<string | null> {
244
+ return AppMetricaNative.getDeviceId();
245
+ }
246
+
247
+ static getUuid(): Promise<string | null> {
248
+ return AppMetricaNative.getUuid();
249
+ }
250
+
251
+ static requestDeferredDeeplink(listener: DeferredDeeplinkListener) {
252
+ AppMetricaNative.requestDeferredDeeplink(
253
+ listener.onFailure,
254
+ listener.onSuccess
255
+ );
256
+ }
257
+
258
+ static requestDeferredDeeplinkParameters(
259
+ listener: DeferredDeeplinkParametersListener
260
+ ) {
261
+ AppMetricaNative.requestDeferredDeeplinkParameters(
262
+ listener.onFailure,
263
+ listener.onSuccess
264
+ );
265
+ }
183
266
  }
@@ -0,0 +1,126 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ import type { UserProfile } from './userProfile';
3
+ import type { AdRevenue, Revenue } from './revenue';
4
+ import type { ECommerceEvent } from './ecommerce';
5
+ import { AppMetricaError } from './error';
6
+
7
+ const LINKING_ERROR =
8
+ `The package '@appmetrica/react-native-analytics' doesn't seem to be linked. Make sure: \n\n` +
9
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
10
+ '- You rebuilt the app after installing the package\n' +
11
+ '- You are not using Expo Go\n';
12
+
13
+ const ReporterNativeModule = NativeModules.AppMetricaReporter
14
+ ? NativeModules.AppMetricaReporter
15
+ : new Proxy(
16
+ {},
17
+ {
18
+ get() {
19
+ throw new Error(LINKING_ERROR);
20
+ },
21
+ }
22
+ );
23
+
24
+ export interface IReporter {
25
+ reportError(identifier: string, message?: string, _reason?: Error | Object): void;
26
+ reportErrorWithoutIdentifier(message: string | undefined, error: Error): void;
27
+ reportUnhandledException(error: Error): void;
28
+ reportEvent(eventName: string, attributes?: Record<string, any>): void;
29
+ pauseSession(): void;
30
+ resumeSession(): void;
31
+ sendEventsBuffer(): void;
32
+ clearAppEnvironment(): void;
33
+ putAppEnvironmentValue(key: string, value?: string): void;
34
+ setUserProfileID(userProfileID?: string): void;
35
+ setDataSendingEnabled(enabled: boolean): void;
36
+ reportUserProfile(userProfile: UserProfile): void;
37
+ reportAdRevenue(adRevenue: AdRevenue): void;
38
+ reportECommerce(event: ECommerceEvent): void;
39
+ reportRevenue(revenue: Revenue): void;
40
+ }
41
+
42
+ export class Reporter implements IReporter {
43
+
44
+ private apiKey: string;
45
+
46
+ constructor(apiKey: string) {
47
+ this.apiKey = apiKey;
48
+ }
49
+
50
+ reportError(identifier: string, message?: string, _reason?: Error | Object) {
51
+ ReporterNativeModule.reportError(
52
+ this.apiKey,
53
+ identifier,
54
+ message,
55
+ _reason instanceof Error ? AppMetricaError.withError(_reason) : AppMetricaError.withObject(_reason)
56
+ );
57
+ }
58
+
59
+ reportErrorWithoutIdentifier(message: string | undefined, error: Error) {
60
+ ReporterNativeModule.reportErrorWithoutIdentifier(this.apiKey, message, AppMetricaError.withError(error));
61
+ }
62
+
63
+ reportUnhandledException(error: Error) {
64
+ ReporterNativeModule.reportUnhandledException(this.apiKey, AppMetricaError.withError(error));
65
+ }
66
+
67
+ reportEvent(eventName: string, attributes?: Record<string, any>) {
68
+ ReporterNativeModule.reportEvent(this.apiKey, eventName, attributes);
69
+ }
70
+
71
+ pauseSession() {
72
+ ReporterNativeModule.pauseSession(this.apiKey);
73
+ }
74
+
75
+ resumeSession() {
76
+ ReporterNativeModule.resumeSession(this.apiKey);
77
+ }
78
+
79
+ sendEventsBuffer() {
80
+ ReporterNativeModule.sendEventsBuffer(this.apiKey);
81
+ }
82
+
83
+ clearAppEnvironment() {
84
+ ReporterNativeModule.clearAppEnvironment(this.apiKey);
85
+ }
86
+
87
+ putAppEnvironmentValue(key: string, value?: string) {
88
+ ReporterNativeModule.putAppEnvironmentValue(this.apiKey, key, value);
89
+ }
90
+
91
+ setUserProfileID(userProfileID: string) {
92
+ ReporterNativeModule.setUserProfileID(this.apiKey, userProfileID);
93
+ }
94
+
95
+ setDataSendingEnabled(enabled: boolean) {
96
+ ReporterNativeModule.setDataSendingEnabled(this.apiKey, enabled);
97
+ }
98
+
99
+ reportUserProfile(profile: UserProfile) {
100
+ ReporterNativeModule.reportUserProfile(this.apiKey, profile);
101
+ }
102
+
103
+ reportAdRevenue(adRevenue: AdRevenue) {
104
+ ReporterNativeModule.reportAdRevenue(this.apiKey, adRevenue);
105
+ }
106
+
107
+ reportECommerce(ecommerce: ECommerceEvent) {
108
+ ReporterNativeModule.reportECommerce(this.apiKey, ecommerce);
109
+ }
110
+
111
+ reportRevenue(revenue: Revenue) {
112
+ ReporterNativeModule.reportRevenue(this.apiKey, revenue)
113
+ }
114
+ }
115
+
116
+ export type ReporterConfig = {
117
+ apiKey: string;
118
+ logs?: boolean;
119
+ maxReportsInDatabaseCount?: number;
120
+ sessionTimeout?: number;
121
+ dataSendingEnabled?: boolean;
122
+ appEnvironment?: Record<string, string | undefined>;
123
+ dispatchPeriodSeconds?: number;
124
+ userProfileID?: string;
125
+ maxReportsCount?: number;
126
+ }