@react-native-firebase/analytics 23.7.0 → 23.8.1
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/CHANGELOG.md +10 -0
- package/dist/commonjs/index.js +38 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/modular.js +613 -0
- package/dist/commonjs/modular.js.map +1 -0
- package/dist/commonjs/namespaced.js +441 -0
- package/dist/commonjs/namespaced.js.map +1 -0
- package/dist/commonjs/package.json +1 -0
- package/dist/commonjs/struct.js +54 -0
- package/dist/commonjs/struct.js.map +1 -0
- package/dist/commonjs/structs.js +214 -0
- package/dist/commonjs/structs.js.map +1 -0
- package/dist/commonjs/types/analytics.js +79 -0
- package/dist/commonjs/types/analytics.js.map +1 -0
- package/dist/commonjs/types/web.js +2 -0
- package/dist/commonjs/types/web.js.map +1 -0
- package/dist/commonjs/version.js +9 -0
- package/dist/commonjs/version.js.map +1 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.android.js +9 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.android.js.map +1 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.ios.js +9 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.ios.js.map +1 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.js +119 -0
- package/dist/commonjs/web/RNFBAnalyticsModule.js.map +1 -0
- package/dist/commonjs/web/api.js +294 -0
- package/dist/commonjs/web/api.js.map +1 -0
- package/dist/module/index.js +28 -0
- package/dist/module/index.js.map +1 -0
- package/{lib/modular/index.js → dist/module/modular.js} +43 -161
- package/dist/module/modular.js.map +1 -0
- package/dist/module/namespaced.js +438 -0
- package/dist/module/namespaced.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/{lib → dist/module}/struct.js +12 -14
- package/dist/module/struct.js.map +1 -0
- package/dist/module/structs.js +210 -0
- package/dist/module/structs.js.map +1 -0
- package/dist/module/types/analytics.js +75 -0
- package/dist/module/types/analytics.js.map +1 -0
- package/dist/module/types/web.js +2 -0
- package/dist/module/types/web.js.map +1 -0
- package/dist/module/version.js +5 -0
- package/dist/module/version.js.map +1 -0
- package/dist/module/web/RNFBAnalyticsModule.android.js +6 -0
- package/dist/module/web/RNFBAnalyticsModule.android.js.map +1 -0
- package/dist/module/web/RNFBAnalyticsModule.ios.js +6 -0
- package/dist/module/web/RNFBAnalyticsModule.ios.js.map +1 -0
- package/{lib → dist/module}/web/RNFBAnalyticsModule.js +17 -21
- package/dist/module/web/RNFBAnalyticsModule.js.map +1 -0
- package/{lib → dist/module}/web/api.js +34 -77
- package/dist/module/web/api.js.map +1 -0
- package/dist/typescript/commonjs/lib/index.d.ts +5 -0
- package/dist/typescript/commonjs/lib/index.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/modular.d.ts +476 -0
- package/dist/typescript/commonjs/lib/modular.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/namespaced.d.ts +12 -0
- package/dist/typescript/commonjs/lib/namespaced.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/struct.d.ts +3 -0
- package/dist/typescript/commonjs/lib/struct.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/structs.d.ts +1155 -0
- package/dist/typescript/commonjs/lib/structs.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/types/analytics.d.ts +944 -0
- package/dist/typescript/commonjs/lib/types/analytics.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/types/web.d.ts +36 -0
- package/dist/typescript/commonjs/lib/types/web.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/version.d.ts +2 -0
- package/dist/typescript/commonjs/lib/version.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.android.d.ts +3 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.android.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.d.ts +9 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.ios.d.ts +3 -0
- package/dist/typescript/commonjs/lib/web/RNFBAnalyticsModule.ios.d.ts.map +1 -0
- package/dist/typescript/commonjs/lib/web/api.d.ts +37 -0
- package/dist/typescript/commonjs/lib/web/api.d.ts.map +1 -0
- package/dist/typescript/commonjs/package.json +1 -0
- package/dist/typescript/module/lib/index.d.ts +5 -0
- package/dist/typescript/module/lib/index.d.ts.map +1 -0
- package/dist/typescript/module/lib/modular.d.ts +476 -0
- package/dist/typescript/module/lib/modular.d.ts.map +1 -0
- package/dist/typescript/module/lib/namespaced.d.ts +12 -0
- package/dist/typescript/module/lib/namespaced.d.ts.map +1 -0
- package/dist/typescript/module/lib/struct.d.ts +3 -0
- package/dist/typescript/module/lib/struct.d.ts.map +1 -0
- package/dist/typescript/module/lib/structs.d.ts +1155 -0
- package/dist/typescript/module/lib/structs.d.ts.map +1 -0
- package/dist/typescript/module/lib/types/analytics.d.ts +944 -0
- package/dist/typescript/module/lib/types/analytics.d.ts.map +1 -0
- package/dist/typescript/module/lib/types/web.d.ts +36 -0
- package/dist/typescript/module/lib/types/web.d.ts.map +1 -0
- package/dist/typescript/module/lib/version.d.ts +2 -0
- package/dist/typescript/module/lib/version.d.ts.map +1 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.android.d.ts +3 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.android.d.ts.map +1 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.d.ts +9 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.d.ts.map +1 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.ios.d.ts +3 -0
- package/dist/typescript/module/lib/web/RNFBAnalyticsModule.ios.d.ts.map +1 -0
- package/dist/typescript/module/lib/web/api.d.ts +37 -0
- package/dist/typescript/module/lib/web/api.d.ts.map +1 -0
- package/dist/typescript/module/package.json +1 -0
- package/lib/index.ts +73 -0
- package/lib/modular.ts +1026 -0
- package/lib/{index.js → namespaced.ts} +145 -72
- package/lib/struct.ts +61 -0
- package/lib/{structs.js → structs.ts} +3 -3
- package/lib/types/analytics.ts +1078 -0
- package/lib/types/web.ts +56 -0
- package/lib/version.ts +2 -0
- package/lib/web/RNFBAnalyticsModule.android.ts +3 -0
- package/lib/web/RNFBAnalyticsModule.ios.ts +3 -0
- package/lib/web/RNFBAnalyticsModule.ts +135 -0
- package/lib/web/api.ts +366 -0
- package/package.json +54 -7
- package/tsconfig.json +21 -0
- package/lib/index.d.ts +0 -1903
- package/lib/modular/index.d.ts +0 -1267
- package/lib/version.js +0 -2
- package/lib/web/RNFBAnalyticsModule.android.js +0 -2
- package/lib/web/RNFBAnalyticsModule.ios.js +0 -2
package/lib/types/web.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface AnalyticsEventParameters {
|
|
19
|
+
[key: string]: string | number | boolean | undefined | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AnalyticsUserProperties {
|
|
23
|
+
[key: string]: string | number | boolean | undefined | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AnalyticsConsent {
|
|
27
|
+
ad_personalization?: boolean;
|
|
28
|
+
[key: string]: boolean | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AnalyticsApi {
|
|
32
|
+
logEvent(name: string, params?: AnalyticsEventParameters): void;
|
|
33
|
+
setUserId(userId: string | null): void;
|
|
34
|
+
setUserProperty(key: string, value: string | null): void;
|
|
35
|
+
setUserProperties(properties: AnalyticsUserProperties): void;
|
|
36
|
+
setDefaultEventParameters(params: AnalyticsEventParameters | null): void;
|
|
37
|
+
setConsent(consent: AnalyticsConsent): void;
|
|
38
|
+
setAnalyticsCollectionEnabled(enabled: boolean): void;
|
|
39
|
+
setDebug(enabled: boolean): void;
|
|
40
|
+
setCurrentScreen(screenName: string | null): void;
|
|
41
|
+
_getCid(): Promise<string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface RNFBAnalyticsModule {
|
|
45
|
+
logEvent(name: string, params?: AnalyticsEventParameters): Promise<null>;
|
|
46
|
+
setUserId(userId: string | null): Promise<null>;
|
|
47
|
+
setUserProperty(key: string, value: string | null): Promise<null>;
|
|
48
|
+
setUserProperties(properties: AnalyticsUserProperties): Promise<null>;
|
|
49
|
+
setDefaultEventParameters(params: AnalyticsEventParameters | null): Promise<null>;
|
|
50
|
+
setConsent(consent: AnalyticsConsent): Promise<null>;
|
|
51
|
+
setAnalyticsCollectionEnabled(enabled: boolean): Promise<null>;
|
|
52
|
+
resetAnalyticsData(): Promise<null>;
|
|
53
|
+
setSessionTimeoutDuration(): Promise<null>;
|
|
54
|
+
getAppInstanceId(): Promise<string | null>;
|
|
55
|
+
getSessionId(): Promise<null>;
|
|
56
|
+
}
|
package/lib/version.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getApp } from '@react-native-firebase/app/lib/internal/web/firebaseApp';
|
|
2
|
+
import { guard } from '@react-native-firebase/app/lib/internal/web/utils';
|
|
3
|
+
|
|
4
|
+
import { AnalyticsApi } from './api';
|
|
5
|
+
import type {
|
|
6
|
+
AnalyticsEventParameters,
|
|
7
|
+
AnalyticsUserProperties,
|
|
8
|
+
AnalyticsConsent,
|
|
9
|
+
RNFBAnalyticsModule as RNFBAnalyticsModuleType,
|
|
10
|
+
} from '../types/web';
|
|
11
|
+
|
|
12
|
+
interface AnalyticsInstances {
|
|
13
|
+
[measurementId: string]: AnalyticsApi;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let analyticsInstances: AnalyticsInstances = {};
|
|
17
|
+
|
|
18
|
+
function getAnalyticsApi(appName: string): AnalyticsApi {
|
|
19
|
+
const app = getApp(appName);
|
|
20
|
+
const measurementId = app.options.measurementId;
|
|
21
|
+
if (!measurementId) {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.warn(
|
|
24
|
+
'No measurement id (`FirebaseOptions.measurementId`) found for Firebase Analytics. Analytics will be unavailable.',
|
|
25
|
+
);
|
|
26
|
+
// Return a default instance with empty measurementId for cases where it's not configured
|
|
27
|
+
const defaultKey = 'default';
|
|
28
|
+
if (!analyticsInstances[defaultKey]) {
|
|
29
|
+
analyticsInstances[defaultKey] = new AnalyticsApi('[DEFAULT]', '');
|
|
30
|
+
}
|
|
31
|
+
return analyticsInstances[defaultKey];
|
|
32
|
+
}
|
|
33
|
+
if (!analyticsInstances[measurementId]) {
|
|
34
|
+
analyticsInstances[measurementId] = new AnalyticsApi('[DEFAULT]', measurementId);
|
|
35
|
+
if ((globalThis as any).RNFBDebug) {
|
|
36
|
+
analyticsInstances[measurementId].setDebug(true);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return analyticsInstances[measurementId];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* This is a 'NativeModule' for the web platform.
|
|
44
|
+
* Methods here are identical to the ones found in
|
|
45
|
+
* the native android/ios modules e.g. `@ReactMethod` annotated
|
|
46
|
+
* java methods on Android.
|
|
47
|
+
*/
|
|
48
|
+
export const RNFBAnalyticsModule: RNFBAnalyticsModuleType = {
|
|
49
|
+
logEvent(name: string, params?: AnalyticsEventParameters): Promise<null> {
|
|
50
|
+
return guard(async () => {
|
|
51
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
52
|
+
api.logEvent(name, params);
|
|
53
|
+
return null;
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
setUserId(userId: string | null): Promise<null> {
|
|
58
|
+
return guard(async () => {
|
|
59
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
60
|
+
api.setUserId(userId);
|
|
61
|
+
return null;
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
setUserProperty(key: string, value: string | null): Promise<null> {
|
|
66
|
+
return guard(async () => {
|
|
67
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
68
|
+
api.setUserProperty(key, value);
|
|
69
|
+
return null;
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
setUserProperties(properties: AnalyticsUserProperties): Promise<null> {
|
|
74
|
+
return guard(async () => {
|
|
75
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
76
|
+
api.setUserProperties(properties);
|
|
77
|
+
return null;
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
setDefaultEventParameters(params: AnalyticsEventParameters | null): Promise<null> {
|
|
82
|
+
return guard(async () => {
|
|
83
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
84
|
+
api.setDefaultEventParameters(params);
|
|
85
|
+
return null;
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
setConsent(consent: AnalyticsConsent): Promise<null> {
|
|
90
|
+
return guard(async () => {
|
|
91
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
92
|
+
// TODO currently we only support ad_personalization
|
|
93
|
+
if (consent && consent.ad_personalization !== undefined) {
|
|
94
|
+
api.setConsent({ ad_personalization: consent.ad_personalization });
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
setAnalyticsCollectionEnabled(enabled: boolean): Promise<null> {
|
|
101
|
+
return guard(async () => {
|
|
102
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
103
|
+
api.setAnalyticsCollectionEnabled(enabled);
|
|
104
|
+
return null;
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
resetAnalyticsData(): Promise<null> {
|
|
109
|
+
// Unsupported for web.
|
|
110
|
+
return guard(async () => {
|
|
111
|
+
return null;
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
setSessionTimeoutDuration(): Promise<null> {
|
|
116
|
+
// Unsupported for web.
|
|
117
|
+
return guard(async () => {
|
|
118
|
+
return null;
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
getAppInstanceId(): Promise<string | null> {
|
|
123
|
+
return guard(async () => {
|
|
124
|
+
const api = getAnalyticsApi('[DEFAULT]');
|
|
125
|
+
return api._getCid();
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
getSessionId(): Promise<null> {
|
|
130
|
+
// Unsupported for web.
|
|
131
|
+
return guard(async () => {
|
|
132
|
+
return null;
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
};
|
package/lib/web/api.ts
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import {
|
|
3
|
+
getApp,
|
|
4
|
+
getId,
|
|
5
|
+
onIdChange,
|
|
6
|
+
getInstallations,
|
|
7
|
+
makeIDBAvailable,
|
|
8
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseInstallations';
|
|
9
|
+
import {
|
|
10
|
+
getItem,
|
|
11
|
+
setItem,
|
|
12
|
+
isMemoryStorage,
|
|
13
|
+
} from '@react-native-firebase/app/lib/internal/asyncStorage';
|
|
14
|
+
|
|
15
|
+
import { isNumber } from '@react-native-firebase/app/lib/common';
|
|
16
|
+
import type {
|
|
17
|
+
AnalyticsEventParameters,
|
|
18
|
+
AnalyticsUserProperties,
|
|
19
|
+
AnalyticsConsent,
|
|
20
|
+
AnalyticsApi as IAnalyticsApi,
|
|
21
|
+
} from '../types/web';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Generates a Google Analytics client ID.
|
|
25
|
+
* @returns {string} The generated client ID.
|
|
26
|
+
*/
|
|
27
|
+
function generateGAClientId(): string {
|
|
28
|
+
const randomNumber = Math.round(Math.random() * 2147483647);
|
|
29
|
+
// TODO: Don't seem to need this for now.
|
|
30
|
+
// var hash = 1;
|
|
31
|
+
// if (seed) {
|
|
32
|
+
// for (var i = seed.length - 1; i >= 0; i--) {
|
|
33
|
+
// var char = seed.charCodeAt(i);
|
|
34
|
+
// hash = ((hash << 6) & 268435455) + char + (char << 14);
|
|
35
|
+
// var flag = hash & 266338304;
|
|
36
|
+
// hash = flag !== 0 ? hash ^ (flag >> 21) : hash;
|
|
37
|
+
// }
|
|
38
|
+
// }
|
|
39
|
+
// const randomPart = seed ? String(randomNumber ^ (hash & 2147483647)) : String(randomNumber);
|
|
40
|
+
const randomPart = String(randomNumber);
|
|
41
|
+
const timestamp = Math.round(Date.now() / 1000);
|
|
42
|
+
return randomPart + '.' + timestamp;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface AnalyticsEvent {
|
|
46
|
+
name: string;
|
|
47
|
+
params: AnalyticsEventParameters;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class AnalyticsApi implements IAnalyticsApi {
|
|
51
|
+
public readonly appName: string;
|
|
52
|
+
public readonly measurementId: string;
|
|
53
|
+
private eventQueue: AnalyticsEvent[];
|
|
54
|
+
private queueTimer: number | null;
|
|
55
|
+
private readonly queueInterval: number;
|
|
56
|
+
private defaultEventParameters: AnalyticsEventParameters;
|
|
57
|
+
private userId: string | null;
|
|
58
|
+
private userProperties: AnalyticsUserProperties;
|
|
59
|
+
private consent: AnalyticsConsent;
|
|
60
|
+
private analyticsCollectionEnabled: boolean;
|
|
61
|
+
private started: boolean;
|
|
62
|
+
private installationId: string | null;
|
|
63
|
+
private debug: boolean;
|
|
64
|
+
private currentScreen: string | null;
|
|
65
|
+
private sessionId?: number;
|
|
66
|
+
private cid?: string | null;
|
|
67
|
+
|
|
68
|
+
constructor(appName: string, measurementId: string) {
|
|
69
|
+
this.appName = appName;
|
|
70
|
+
this.measurementId = measurementId;
|
|
71
|
+
this.eventQueue = [];
|
|
72
|
+
this.queueTimer = null;
|
|
73
|
+
this.queueInterval = 250;
|
|
74
|
+
this.defaultEventParameters = {};
|
|
75
|
+
this.userId = null;
|
|
76
|
+
this.userProperties = {};
|
|
77
|
+
this.consent = {};
|
|
78
|
+
this.analyticsCollectionEnabled = true;
|
|
79
|
+
this.started = false;
|
|
80
|
+
this.installationId = null;
|
|
81
|
+
this.debug = false;
|
|
82
|
+
this.currentScreen = null;
|
|
83
|
+
|
|
84
|
+
this._getInstallationId().catch(error => {
|
|
85
|
+
if ((globalThis as any).RNFBDebug) {
|
|
86
|
+
console.debug('[RNFB->Analytics][🔴] Error getting Firebase Installation Id:', error);
|
|
87
|
+
} else {
|
|
88
|
+
// No-op. This is a non-critical error.
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setDefaultEventParameters(params: AnalyticsEventParameters | null): void {
|
|
94
|
+
if (params === null || params === undefined) {
|
|
95
|
+
this.defaultEventParameters = {};
|
|
96
|
+
} else {
|
|
97
|
+
for (const [key, value] of Object.entries(params)) {
|
|
98
|
+
this.defaultEventParameters[key] = value;
|
|
99
|
+
if (value === null) {
|
|
100
|
+
delete this.defaultEventParameters[key];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setDebug(enabled: boolean): void {
|
|
107
|
+
this.debug = enabled;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setUserId(userId: string | null): void {
|
|
111
|
+
this.userId = userId;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setCurrentScreen(screenName: string | null): void {
|
|
115
|
+
this.currentScreen = screenName;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
setUserProperty(key: string, value: string | null): void {
|
|
119
|
+
this.userProperties[key] = value;
|
|
120
|
+
if (value === null) {
|
|
121
|
+
delete this.userProperties[key];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
setUserProperties(properties: AnalyticsUserProperties): void {
|
|
126
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
127
|
+
this.setUserProperty(key, value as string | null);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setConsent(consentSettings: AnalyticsConsent): void {
|
|
132
|
+
this.consent = { ...this.consent, ...consentSettings };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setAnalyticsCollectionEnabled(enabled: boolean): void {
|
|
136
|
+
this.analyticsCollectionEnabled = enabled;
|
|
137
|
+
if (!enabled) {
|
|
138
|
+
this._stopQueueProcessing();
|
|
139
|
+
} else {
|
|
140
|
+
this._startQueueProcessing();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
logEvent(eventName: string, eventParams: AnalyticsEventParameters = {}): void {
|
|
145
|
+
if (!this.analyticsCollectionEnabled) return;
|
|
146
|
+
this.eventQueue.push({
|
|
147
|
+
name: eventName,
|
|
148
|
+
params: { ...this.defaultEventParameters, ...eventParams },
|
|
149
|
+
});
|
|
150
|
+
this._startQueueProcessing();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private async _getInstallationId(): Promise<void> {
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
if (navigator !== null) {
|
|
156
|
+
// @ts-ignore
|
|
157
|
+
(navigator as any).onLine = true;
|
|
158
|
+
}
|
|
159
|
+
makeIDBAvailable();
|
|
160
|
+
const app = getApp(this.appName);
|
|
161
|
+
const installations = getInstallations(app);
|
|
162
|
+
const id = await getId(installations);
|
|
163
|
+
if ((globalThis as any).RNFBDebug) {
|
|
164
|
+
console.debug('[RNFB->Analytics][📊] Firebase Installation Id:', id);
|
|
165
|
+
}
|
|
166
|
+
this.installationId = id;
|
|
167
|
+
onIdChange(installations, (newId: string) => {
|
|
168
|
+
this.installationId = newId;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private _startQueueProcessing(): void {
|
|
173
|
+
if (this.started) return;
|
|
174
|
+
this.sessionId = Math.floor(Date.now() / 1000);
|
|
175
|
+
this.started = true;
|
|
176
|
+
this.queueTimer = setInterval(
|
|
177
|
+
() => this._processQueue().catch(console.error),
|
|
178
|
+
this.queueInterval,
|
|
179
|
+
) as unknown as number;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private _stopQueueProcessing(): void {
|
|
183
|
+
if (!this.started) return;
|
|
184
|
+
this.started = false;
|
|
185
|
+
if (this.queueTimer) {
|
|
186
|
+
clearInterval(this.queueTimer);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private async _processQueue(): Promise<void> {
|
|
191
|
+
if (this.eventQueue.length === 0) return;
|
|
192
|
+
const events = this.eventQueue.splice(0, 5);
|
|
193
|
+
await this._sendEvents(events);
|
|
194
|
+
if (this.eventQueue.length === 0) {
|
|
195
|
+
this._stopQueueProcessing();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async _getCid(): Promise<string> {
|
|
200
|
+
this.cid = await getItem('analytics:cid');
|
|
201
|
+
if (this.cid) {
|
|
202
|
+
return this.cid;
|
|
203
|
+
}
|
|
204
|
+
this.cid = generateGAClientId();
|
|
205
|
+
await setItem('analytics:cid', this.cid);
|
|
206
|
+
if (isMemoryStorage()) {
|
|
207
|
+
console.warn(
|
|
208
|
+
'Firebase Analytics is using in memory persistence. This means that the analytics\n' +
|
|
209
|
+
'client ID is reset every time your app is restarted which may result in\n' +
|
|
210
|
+
'inaccurate data being shown on the Firebase Analytics dashboard.\n' +
|
|
211
|
+
'\n' +
|
|
212
|
+
'To enable persistence, provide an Async Storage implementation.\n' +
|
|
213
|
+
'\n' +
|
|
214
|
+
'For example, to use React Native Async Storage:\n' +
|
|
215
|
+
'\n' +
|
|
216
|
+
" import AsyncStorage from '@react-native-async-storage/async-storage';\n" +
|
|
217
|
+
'\n' +
|
|
218
|
+
' // Before initializing Firebase set the Async Storage implementation\n' +
|
|
219
|
+
' // that will be used to persist user sessions.\n' +
|
|
220
|
+
' firebase.setReactNativeAsyncStorage(AsyncStorage);\n' +
|
|
221
|
+
'\n' +
|
|
222
|
+
' // Then initialize Firebase as normal.\n' +
|
|
223
|
+
' await firebase.initializeApp({ ... });\n',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return this.cid;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private async _sendEvents(events: AnalyticsEvent[]): Promise<void> {
|
|
230
|
+
const cid = this.cid || (await this._getCid());
|
|
231
|
+
for (const event of events) {
|
|
232
|
+
const queryParams = new URLSearchParams({
|
|
233
|
+
v: '2',
|
|
234
|
+
tid: this.measurementId,
|
|
235
|
+
en: event.name,
|
|
236
|
+
cid,
|
|
237
|
+
pscdl: 'noapi',
|
|
238
|
+
sid: String(this.sessionId),
|
|
239
|
+
'ep.origin': 'firebase',
|
|
240
|
+
_z: 'fetch',
|
|
241
|
+
_p: '' + Date.now(),
|
|
242
|
+
_s: '1',
|
|
243
|
+
_ee: '1',
|
|
244
|
+
dma: '0',
|
|
245
|
+
tfd: String(Math.round(performance.now())),
|
|
246
|
+
are: '1',
|
|
247
|
+
sct: '2',
|
|
248
|
+
seg: '1',
|
|
249
|
+
frm: '0',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
if (this.debug) {
|
|
253
|
+
queryParams.append('_dbg', '1');
|
|
254
|
+
queryParams.append('ep.debug_mode', '1');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (this.consent && !this.consent.ad_personalization) {
|
|
258
|
+
queryParams.append('npa', '1');
|
|
259
|
+
} else {
|
|
260
|
+
queryParams.append('npa', '0');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (this.userId) {
|
|
264
|
+
queryParams.append('uid', this.userId);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (this.installationId) {
|
|
268
|
+
queryParams.append('_fid', this.installationId);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (this.userProperties && Object.keys(this.userProperties).length > 0) {
|
|
272
|
+
for (const [key, value] of Object.entries(this.userProperties)) {
|
|
273
|
+
queryParams.append(`up.${key}`, `${value}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (this.currentScreen) {
|
|
278
|
+
queryParams.append('ep.screen_name', this.currentScreen);
|
|
279
|
+
queryParams.append('ep.firebase_screen', this.currentScreen);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (event.params && Object.keys(event.params).length > 0) {
|
|
283
|
+
// TODO we need to handle 'items' arrays and also key name conversions based on the following map;
|
|
284
|
+
// const keyConvert = {
|
|
285
|
+
// item_id: 'id',
|
|
286
|
+
// item_name: 'nm',
|
|
287
|
+
// item_brand: 'br',
|
|
288
|
+
// item_category: 'ca',
|
|
289
|
+
// item_category2: 'c2',
|
|
290
|
+
// item_category3: 'c3',
|
|
291
|
+
// item_category4: 'c4',
|
|
292
|
+
// item_category5: 'c5',
|
|
293
|
+
// item_variant: 'va',
|
|
294
|
+
// price: 'pr',
|
|
295
|
+
// quantity: 'qt',
|
|
296
|
+
// coupon: 'cp',
|
|
297
|
+
// item_list_name: 'ln',
|
|
298
|
+
// index: 'lp',
|
|
299
|
+
// item_list_id: 'li',
|
|
300
|
+
// discount: 'ds',
|
|
301
|
+
// affiliation: 'af',
|
|
302
|
+
// promotion_id: 'pi',
|
|
303
|
+
// promotion_name: 'pn',
|
|
304
|
+
// creative_name: 'cn',
|
|
305
|
+
// creative_slot: 'cs',
|
|
306
|
+
// location_id: 'lo',
|
|
307
|
+
// id: 'id',
|
|
308
|
+
// name: 'nm',
|
|
309
|
+
// brand: 'br',
|
|
310
|
+
// variant: 'va',
|
|
311
|
+
// list_name: 'ln',
|
|
312
|
+
// list_position: 'lp',
|
|
313
|
+
// list: 'ln',
|
|
314
|
+
// position: 'lp',
|
|
315
|
+
// creative: 'cn',
|
|
316
|
+
// };
|
|
317
|
+
// items array should for example become:
|
|
318
|
+
// pr1 for items[0]
|
|
319
|
+
// pr2 for items[1]
|
|
320
|
+
// ... etc
|
|
321
|
+
// with the format for each looking something like:
|
|
322
|
+
// iditem_id~nmitem_name~britem_brand~caitem_category~c2item_category2~c3item_category3~c4item_category4~c5item_category5~vaitem_variant~prprice~qtquantity~cpcoupon~lnitem_list_name~lpindex~liitem_list_id~dsdiscount~afaffiliation~pipromotion_id~pnpromotion_name~cncreative_name~cscreative_slot~lolocation_id
|
|
323
|
+
for (const [key, value] of Object.entries(event.params)) {
|
|
324
|
+
if (isNumber(value)) {
|
|
325
|
+
queryParams.append(`epn.${key}`, `${value}`);
|
|
326
|
+
} else {
|
|
327
|
+
queryParams.append(`ep.${key}`, `${value}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
const url = `https://www.google-analytics.com/g/collect?${queryParams.toString()}`;
|
|
334
|
+
if ((globalThis as any).RNFBDebug) {
|
|
335
|
+
console.debug(`[RNFB-->Fetch][📊] Sending analytics call: ${url}`);
|
|
336
|
+
}
|
|
337
|
+
const response = await fetch(url, {
|
|
338
|
+
method: 'POST',
|
|
339
|
+
mode: 'no-cors',
|
|
340
|
+
headers: {
|
|
341
|
+
accept: '*/*',
|
|
342
|
+
'accept-encoding': 'gzip, deflate, br',
|
|
343
|
+
'Content-Type': 'text/plain;charset=UTF-8',
|
|
344
|
+
'accept-language': 'en-US,en;q=0.9',
|
|
345
|
+
'cache-control': 'no-cache',
|
|
346
|
+
'content-length': '0',
|
|
347
|
+
origin: 'firebase',
|
|
348
|
+
pragma: 'no-cache',
|
|
349
|
+
'sec-fetch-dest': 'empty',
|
|
350
|
+
'sec-fetch-site': 'cross-site',
|
|
351
|
+
'user-agent': 'react-native-firebase',
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
if ((globalThis as any).RNFBDebug) {
|
|
355
|
+
console.debug(`[RNFB<--Fetch][📊] Response: ${response.status}`);
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if ((globalThis as any).RNFBDebug) {
|
|
359
|
+
console.debug('[RNFB<--Fetch][🔴] Error sending Analytics event:', error);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export { AnalyticsApi };
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-firebase/analytics",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.8.1",
|
|
4
4
|
"author": "Invertase <oss@invertase.io> (http://invertase.io)",
|
|
5
5
|
"description": "React Native Firebase - The analytics module provides out of the box support with Google Analytics for Firebase. Integration with the Android & iOS allows for in-depth analytical insight reporting, such as device information, location, user actions and more.",
|
|
6
|
-
"main": "
|
|
7
|
-
"
|
|
6
|
+
"main": "./dist/commonjs/index.js",
|
|
7
|
+
"module": "./dist/module/index.js",
|
|
8
|
+
"types": "./dist/typescript/commonjs/lib/index.d.ts",
|
|
8
9
|
"scripts": {
|
|
9
|
-
"build": "genversion --semi lib/version.
|
|
10
|
+
"build": "genversion --esm --semi lib/version.ts",
|
|
10
11
|
"build:clean": "rimraf android/build && rimraf ios/build",
|
|
11
|
-
"
|
|
12
|
+
"compile": "bob build",
|
|
13
|
+
"prepare": "yarn run build && yarn compile"
|
|
12
14
|
},
|
|
13
15
|
"repository": {
|
|
14
16
|
"type": "git",
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
"analytics"
|
|
23
25
|
],
|
|
24
26
|
"peerDependencies": {
|
|
25
|
-
"@react-native-firebase/app": "23.
|
|
27
|
+
"@react-native-firebase/app": "23.8.1"
|
|
26
28
|
},
|
|
27
29
|
"publishConfig": {
|
|
28
30
|
"access": "public",
|
|
@@ -31,5 +33,50 @@
|
|
|
31
33
|
"dependencies": {
|
|
32
34
|
"superstruct": "^2.0.2"
|
|
33
35
|
},
|
|
34
|
-
"
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"react-native-builder-bob": "^0.40.17"
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
".": {
|
|
41
|
+
"source": "./lib/index.ts",
|
|
42
|
+
"import": {
|
|
43
|
+
"types": "./dist/typescript/module/lib/index.d.ts",
|
|
44
|
+
"default": "./dist/module/index.js"
|
|
45
|
+
},
|
|
46
|
+
"require": {
|
|
47
|
+
"types": "./dist/typescript/commonjs/lib/index.d.ts",
|
|
48
|
+
"default": "./dist/commonjs/index.js"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"react-native-builder-bob": {
|
|
54
|
+
"source": "lib",
|
|
55
|
+
"output": "dist",
|
|
56
|
+
"targets": [
|
|
57
|
+
[
|
|
58
|
+
"module",
|
|
59
|
+
{
|
|
60
|
+
"esm": true
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"commonjs",
|
|
65
|
+
{
|
|
66
|
+
"esm": true
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
"typescript",
|
|
71
|
+
{
|
|
72
|
+
"tsc": "../../node_modules/.bin/tsc"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"eslintIgnore": [
|
|
78
|
+
"node_modules/",
|
|
79
|
+
"dist/"
|
|
80
|
+
],
|
|
81
|
+
"gitHead": "46b06d2b1100ec03c7807b4ff34b583b773a19d7"
|
|
35
82
|
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.packages.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@react-native-firebase/app/lib/common/*": ["../app/dist/typescript/commonjs/lib/common/*"],
|
|
8
|
+
"@react-native-firebase/app/lib/common": ["../app/dist/typescript/commonjs/lib/common"],
|
|
9
|
+
"@react-native-firebase/app/lib/internal/web/*": [
|
|
10
|
+
"../app/dist/typescript/commonjs/lib/internal/web/*"
|
|
11
|
+
],
|
|
12
|
+
"@react-native-firebase/app/lib/internal/*": [
|
|
13
|
+
"../app/dist/typescript/commonjs/lib/internal/*"
|
|
14
|
+
],
|
|
15
|
+
"@react-native-firebase/app/lib/internal": ["../app/dist/typescript/commonjs/lib/internal"],
|
|
16
|
+
"@react-native-firebase/app": ["../app/dist/typescript/commonjs/lib"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"include": ["lib/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "__tests__", "**/*.test.ts"]
|
|
21
|
+
}
|