浏览代码

ref(Amplitude): device id syncing

master
Hristo Terezov 5 年前
父节点
当前提交
b64260e554

+ 82
- 54
react/features/analytics/functions.js 查看文件

@@ -35,28 +35,23 @@ export function resetAnalytics() {
35 35
 }
36 36
 
37 37
 /**
38
- * Loads the analytics scripts and inits JitsiMeetJS.analytics by setting
39
- * permanent properties and setting the handlers from the loaded scripts.
40
- * NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
41
- * null.
38
+ * Creates the analytics handlers.
42 39
  *
43
- * @param {Store} store - The redux store in which the specified {@code action}
44
- * is being dispatched.
45
- * @returns {void}
40
+ * @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
41
+ * @returns {Promise} Resolves with the handlers that have been successfully loaded.
46 42
  */
47
-export function initAnalytics({ getState }: { getState: Function }) {
43
+export function createHandlers({ getState }: { getState: Function }) {
48 44
     getJitsiMeetGlobalNS().analyticsHandlers = [];
49 45
     window.analyticsHandlers = []; // Legacy support.
50 46
 
51
-    if (!analytics || !isAnalyticsEnabled(getState)) {
52
-        return;
47
+    if (!isAnalyticsEnabled(getState)) {
48
+        return Promise.resolve([]);
53 49
     }
54 50
 
55 51
     const state = getState();
56 52
     const config = state['features/base/config'];
57 53
     const { locationURL } = state['features/base/connection'];
58 54
     const host = locationURL ? locationURL.host : '';
59
-
60 55
     const {
61 56
         analytics: analyticsConfig = {},
62 57
         deploymentInfo
@@ -68,7 +63,7 @@ export function initAnalytics({ getState }: { getState: Function }) {
68 63
         googleAnalyticsTrackingId,
69 64
         whiteListedEvents
70 65
     } = analyticsConfig;
71
-    const { group, server, user } = state['features/base/jwt'];
66
+    const { group, user } = state['features/base/jwt'];
72 67
     const handlerConstructorOptions = {
73 68
         amplitudeAPPKey,
74 69
         blackListedEvents,
@@ -82,54 +77,93 @@ export function initAnalytics({ getState }: { getState: Function }) {
82 77
         version: JitsiMeetJS.version,
83 78
         whiteListedEvents
84 79
     };
80
+    const handlers = [];
85 81
 
86
-    _loadHandlers(scriptURLs, handlerConstructorOptions)
87
-        .then(handlers => {
88
-            const roomName = state['features/base/conference'].room;
89
-            const permanentProperties = {};
82
+    try {
83
+        const amplitude = new AmplitudeHandler(handlerConstructorOptions);
84
+
85
+        handlers.push(amplitude);
86
+    // eslint-disable-next-line no-empty
87
+    } catch (e) {}
88
+
89
+    return (
90
+        _loadHandlers(scriptURLs, handlerConstructorOptions)
91
+            .then(externalHandlers => {
92
+                handlers.push(...externalHandlers);
93
+                if (handlers.length === 0) {
94
+                    // Throwing an error in  order to dispose the analytics in the catch clause due to the lack of any
95
+                    // analytics handlers.
96
+                    throw new Error('No analytics handlers created!');
97
+                }
90 98
 
91
-            if (server) {
92
-                permanentProperties.server = server;
93
-            }
94
-            if (group) {
95
-                permanentProperties.group = group;
96
-            }
99
+                return handlers;
100
+            })
101
+            .catch(e => {
102
+                analytics.dispose();
103
+                logger.error(e);
97 104
 
98
-            //  Report if user is using websocket
99
-            permanentProperties.websocket = navigator.product !== 'ReactNative' && typeof config.websocket === 'string';
105
+                return [];
106
+            }));
100 107
 
101
-            // Optionally, include local deployment information based on the
102
-            // contents of window.config.deploymentInfo.
103
-            if (deploymentInfo) {
104
-                for (const key in deploymentInfo) {
105
-                    if (deploymentInfo.hasOwnProperty(key)) {
106
-                        permanentProperties[key] = deploymentInfo[key];
107
-                    }
108
-                }
108
+}
109
+
110
+/**
111
+ * Inits JitsiMeetJS.analytics by setting permanent properties and setting the handlers from the loaded scripts.
112
+ * NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be null.
113
+ *
114
+ * @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
115
+ * @param {Array<Object>} handlers - The analytics handlers.
116
+ * @returns {void}
117
+ */
118
+export function initAnalytics({ getState }: { getState: Function }, handlers: Array<Object>) {
119
+    if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
120
+        return;
121
+    }
122
+
123
+    const state = getState();
124
+    const config = state['features/base/config'];
125
+    const {
126
+        deploymentInfo
127
+    } = config;
128
+    const { group, server } = state['features/base/jwt'];
129
+    const roomName = state['features/base/conference'].room;
130
+    const permanentProperties = {};
131
+
132
+    if (server) {
133
+        permanentProperties.server = server;
134
+    }
135
+    if (group) {
136
+        permanentProperties.group = group;
137
+    }
138
+
139
+    //  Report if user is using websocket
140
+    permanentProperties.websocket = navigator.product !== 'ReactNative' && typeof config.websocket === 'string';
141
+
142
+    // Optionally, include local deployment information based on the
143
+    // contents of window.config.deploymentInfo.
144
+    if (deploymentInfo) {
145
+        for (const key in deploymentInfo) {
146
+            if (deploymentInfo.hasOwnProperty(key)) {
147
+                permanentProperties[key] = deploymentInfo[key];
109 148
             }
149
+        }
150
+    }
110 151
 
111
-            analytics.addPermanentProperties(permanentProperties);
112
-            analytics.setConferenceName(roomName);
152
+    analytics.addPermanentProperties(permanentProperties);
153
+    analytics.setConferenceName(roomName);
113 154
 
114
-            // Set the handlers last, since this triggers emptying of the cache
115
-            analytics.setAnalyticsHandlers(handlers);
116
-        })
117
-        .catch(error => {
118
-            analytics.dispose();
119
-            logger.error(error);
120
-        });
155
+    // Set the handlers last, since this triggers emptying of the cache
156
+    analytics.setAnalyticsHandlers(handlers);
121 157
 }
122 158
 
123 159
 /**
124
- * Tries to load the scripts for the analytics handlers.
160
+ * Tries to load the scripts for the analytics handlers and creates them.
125 161
  *
126 162
  * @param {Array} scriptURLs - The array of script urls to load.
127
- * @param {Object} handlerConstructorOptions - The default options to pass when
128
- * creating handlers.
163
+ * @param {Object} handlerConstructorOptions - The default options to pass when creating handlers.
129 164
  * @private
130
- * @returns {Promise} Resolves with the handlers that have been
131
- * successfully loaded and rejects if there are no handlers loaded or the
132
- * analytics is disabled.
165
+ * @returns {Promise} Resolves with the handlers that have been successfully loaded and rejects if there are no handlers
166
+ * loaded or the analytics is disabled.
133 167
  */
134 168
 function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
135 169
     const promises = [];
@@ -161,13 +195,8 @@ function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
161 195
         // check the old location to provide legacy support
162 196
         const analyticsHandlers = [
163 197
             ...getJitsiMeetGlobalNS().analyticsHandlers,
164
-            ...window.analyticsHandlers,
165
-
166
-            // NOTE: when we add second handler it will be good to put all
167
-            // build-in handlers in an array and destruct it here.
168
-            AmplitudeHandler
198
+            ...window.analyticsHandlers
169 199
         ];
170
-
171 200
         const handlers = [];
172 201
 
173 202
         for (const Handler of analyticsHandlers) {
@@ -179,7 +208,6 @@ function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
179 208
                 logger.warn(`Error creating analytics handler: ${error}`);
180 209
             }
181 210
         }
182
-
183 211
         logger.debug(`Loaded ${handlers.length} analytics handlers`);
184 212
 
185 213
         return handlers;

+ 2
- 2
react/features/analytics/handlers/AmplitudeHandler.js 查看文件

@@ -1,5 +1,5 @@
1 1
 import AbstractHandler from './AbstractHandler';
2
-import { amplitude } from './amplitude';
2
+import { amplitude, fixDeviceID } from './amplitude';
3 3
 
4 4
 /**
5 5
  * Analytics handler for Amplitude.
@@ -28,7 +28,7 @@ export default class AmplitudeHandler extends AbstractHandler {
28 28
         };
29 29
 
30 30
         amplitude.getInstance(this._amplitudeOptions).init(amplitudeAPPKey, undefined, { includeReferrer: true });
31
-        amplitude.fixDeviceID(this._amplitudeOptions);
31
+        fixDeviceID(amplitude.getInstance(this._amplitudeOptions));
32 32
 
33 33
         if (user) {
34 34
             amplitude.getInstance(this._amplitudeOptions).setUserId(user);

+ 1
- 8
react/features/analytics/handlers/amplitude/Amplitude.native.js 查看文件

@@ -111,12 +111,5 @@ export default {
111 111
         }
112 112
 
113 113
         return instance;
114
-    },
115
-
116
-    /**
117
-     * Currently not implemented.
118
-     *
119
-     * @returns {void}
120
-     */
121
-    fixDeviceID() { } // eslint-disable-line no-empty-function
114
+    }
122 115
 };

+ 0
- 24
react/features/analytics/handlers/amplitude/Amplitude.web.js 查看文件

@@ -10,29 +10,5 @@ export default {
10 10
      */
11 11
     getInstance(options = {}) {
12 12
         return amplitude.getInstance(options.instanceName);
13
-    },
14
-
15
-    /**
16
-     * Sets the device id to the value of __AMDID cookie or sets the __AMDID cookie value to the current device id in
17
-     * case the __AMDID cookie is not set.
18
-     *
19
-     * @param {*} options - Optional parameters.
20
-     * @property {string} options.instanceName - The name of the AmplitudeClient instance.
21
-     * @property {string} options.host - The host from the original URL.
22
-     * @returns {void}
23
-     */
24
-    fixDeviceID(options) {
25
-        const deviceId = document.cookie.replace(/(?:(?:^|.*;\s*)__AMDID\s*=\s*([^;]*).*$)|^.*$/, '$1');
26
-        const instance = this.getInstance(options);
27
-
28
-        if (deviceId === '') {
29
-            const { host = '' } = options;
30
-
31
-            document.cookie
32
-                = `__AMDID=${instance.options.deviceId};max-age=630720000${
33
-                    host === '' ? '' : `;domain=.${host}`}`; // max-age=10 years
34
-        } else {
35
-            instance.setDeviceId(deviceId);
36
-        }
37 13
     }
38 14
 };

+ 9
- 0
react/features/analytics/handlers/amplitude/fixDeviceID.native.js 查看文件

@@ -0,0 +1,9 @@
1
+/**
2
+ * Custom logic for setting the correct device id.
3
+ *
4
+ * @param {AmplitudeClient} amplitude - The amplitude instance.
5
+ * @returns {void}
6
+ */
7
+export function fixDeviceID(amplitude) { // eslint-disable-line no-unused-vars
8
+
9
+}

+ 9
- 0
react/features/analytics/handlers/amplitude/fixDeviceID.web.js 查看文件

@@ -0,0 +1,9 @@
1
+/**
2
+ * Custom logic for setting the correct device id.
3
+ *
4
+ * @param {AmplitudeClient} amplitude - The amplitude instance.
5
+ * @returns {void}
6
+ */
7
+export function fixDeviceID(amplitude) { // eslint-disable-line no-unused-vars
8
+
9
+}

+ 1
- 0
react/features/analytics/handlers/amplitude/index.js 查看文件

@@ -1 +1,2 @@
1 1
 export { default as amplitude } from './Amplitude';
2
+export * from './fixDeviceID';

+ 17
- 6
react/features/analytics/middleware.js 查看文件

@@ -18,7 +18,7 @@ import {
18 18
 
19 19
 import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
20 20
 import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents';
21
-import { initAnalytics, resetAnalytics, sendAnalytics } from './functions';
21
+import { createHandlers, initAnalytics, resetAnalytics, sendAnalytics } from './functions';
22 22
 
23 23
 /**
24 24
  * Calculates the duration of the local tracks.
@@ -79,13 +79,28 @@ function calculateLocalTrackDuration(state) {
79 79
  * @returns {Function}
80 80
  */
81 81
 MiddlewareRegistry.register(store => next => action => {
82
-    if (action.type === SET_CONFIG) {
82
+    switch (action.type) {
83
+    case SET_CONFIG:
83 84
         if (navigator.product === 'ReactNative') {
84 85
             // Reseting the analytics is currently not needed for web because
85 86
             // the user will be redirected to another page and new instance of
86 87
             // Analytics will be created and initialized.
87 88
             resetAnalytics();
88 89
         }
90
+        break;
91
+    case SET_ROOM: {
92
+        // createHandlers is called before the SET_ROOM action is executed in order for Amplitude to initialize before
93
+        // the deeplinking logic is executed (after the SET_ROOM action) so that the Amplitude device id is available
94
+        // if needed.
95
+        const createHandlersPromise = createHandlers(store);
96
+        const result = next(action);
97
+
98
+        createHandlersPromise.then(handlers => {
99
+            initAnalytics(store, handlers);
100
+        });
101
+
102
+        return result;
103
+    }
89 104
     }
90 105
 
91 106
     const result = next(action);
@@ -136,10 +151,6 @@ MiddlewareRegistry.register(store => next => action => {
136 151
                 networkType: action.networkType
137 152
             }));
138 153
         break;
139
-    case SET_ROOM: {
140
-        initAnalytics(store);
141
-        break;
142
-    }
143 154
     case TRACK_ADDED:
144 155
     case TRACK_REMOVED:
145 156
     case TRACK_UPDATED: {

正在加载...
取消
保存