Browse Source

feat(amplitude): add mobile implementation

master
Hristo Terezov 6 years ago
parent
commit
59fc3642a6

+ 0
- 2
Makefile View File

@@ -45,8 +45,6 @@ deploy-appbundle:
45 45
 		$(OUTPUT_DIR)/analytics-ga.js \
46 46
 		$(BUILD_DIR)/analytics-ga.min.js \
47 47
 		$(BUILD_DIR)/analytics-ga.min.map \
48
-		$(BUILD_DIR)/analytics-amplitude.min.js \
49
-		$(BUILD_DIR)/analytics-amplitude.min.map \
50 48
 		$(DEPLOY_DIR)
51 49
 
52 50
 deploy-lib-jitsi-meet:

+ 1
- 0
android/sdk/build.gradle View File

@@ -25,6 +25,7 @@ dependencies {
25 25
     implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
26 26
 
27 27
     implementation 'org.webkit:android-jsc:+'
28
+    implementation 'com.amplitude:android-sdk:2.14.1'
28 29
     implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
29 30
     api 'com.facebook.react:react-native:+'
30 31
 

+ 1
- 0
android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java View File

@@ -53,6 +53,7 @@ class ReactInstanceManagerHolder {
53 53
                 new PictureInPictureModule(reactContext),
54 54
                 new ProximityModule(reactContext),
55 55
                 new WiFiStatsModule(reactContext),
56
+                new org.jitsi.meet.sdk.analytics.AmplitudeModule(reactContext),
56 57
                 new org.jitsi.meet.sdk.dropbox.Dropbox(reactContext),
57 58
                 new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext)));
58 59
 

+ 87
- 0
android/sdk/src/main/java/org/jitsi/meet/sdk/analytics/AmplitudeModule.java View File

@@ -0,0 +1,87 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file 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
+package org.jitsi.meet.sdk.analytics;
18
+
19
+import com.facebook.react.bridge.ReactApplicationContext;
20
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
21
+import com.facebook.react.bridge.ReactMethod;
22
+import com.facebook.react.bridge.ReadableMap;
23
+
24
+import com.amplitude.api.Amplitude;
25
+
26
+import org.json.JSONException;
27
+import org.json.JSONObject;
28
+
29
+/**
30
+ * Implements the react-native module for the Amplitude integration.
31
+ */
32
+public class AmplitudeModule
33
+        extends ReactContextBaseJavaModule {
34
+
35
+    public AmplitudeModule(ReactApplicationContext reactContext) {
36
+        super(reactContext);
37
+    }
38
+
39
+    /**
40
+     * Initializes the Amplitude SDK.
41
+     *
42
+     * @param instanceName The name of the Amplitude instance. Should
43
+     * be used only for multi-project logging.
44
+     * @param apiKey The API_KEY of the Amplitude project.
45
+     */
46
+    @ReactMethod
47
+    public void init(String instanceName, String apiKey) {
48
+        Amplitude.getInstance(instanceName).initialize(getCurrentActivity(), apiKey);
49
+    }
50
+
51
+    /**
52
+     * Sets the user properties for an Amplitude instance.
53
+     *
54
+     * @param instanceName The name of the Amplitude instance.
55
+     * @param userProps JSON string with user properties to be set.
56
+     */
57
+    @ReactMethod
58
+    public void setUserProperties(String instanceName, ReadableMap userProps) {
59
+        if (userProps != null) {
60
+            Amplitude.getInstance(instanceName).setUserProperties(
61
+                    new JSONObject(userProps.toHashMap()));
62
+        }
63
+    }
64
+
65
+    /**
66
+     * Log an analytics event.
67
+     *
68
+     * @param instanceName The name of the Amplitude instance.
69
+     * @param eventType The event type.
70
+     * @param eventPropsString JSON string with the event properties.
71
+     */
72
+    @ReactMethod
73
+    public void logEvent(String instanceName, String eventType, String eventPropsString) {
74
+        JSONObject eventProps = null;
75
+        try {
76
+            eventProps = new JSONObject(eventPropsString);
77
+            Amplitude.getInstance(instanceName).logEvent(eventType, eventProps);
78
+        } catch (JSONException e) {
79
+            e.printStackTrace();
80
+        }
81
+    }
82
+
83
+    @Override
84
+    public String getName() {
85
+        return "Amplitude";
86
+    }
87
+}

+ 1
- 0
ios/Podfile View File

@@ -35,6 +35,7 @@ target 'JitsiMeet' do
35 35
   pod 'Folly',
36 36
     :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
37 37
 
38
+  pod 'Amplitude-iOS', '~> 4.0.4'
38 39
   pod 'ObjectiveDropboxOfficial'
39 40
 
40 41
   pod 'react-native-background-timer',

+ 6
- 2
ios/Podfile.lock View File

@@ -1,4 +1,5 @@
1 1
 PODS:
2
+  - Amplitude-iOS (4.0.4)
2 3
   - boost-for-react-native (1.63.0)
3 4
   - BVLinearGradient (2.5.3):
4 5
     - React
@@ -154,6 +155,7 @@ PODS:
154 155
   - yoga (0.57.8.React)
155 156
 
156 157
 DEPENDENCIES:
158
+  - Amplitude-iOS (~> 4.0.4)
157 159
   - BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
158 160
   - Crashlytics
159 161
   - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
@@ -185,6 +187,7 @@ DEPENDENCIES:
185 187
 
186 188
 SPEC REPOS:
187 189
   https://github.com/cocoapods/specs.git:
190
+    - Amplitude-iOS
188 191
     - boost-for-react-native
189 192
     - Crashlytics
190 193
     - Fabric
@@ -235,6 +238,7 @@ EXTERNAL SOURCES:
235 238
     :path: "../node_modules/react-native/ReactCommon/yoga"
236 239
 
237 240
 SPEC CHECKSUMS:
241
+  Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7
238 242
   boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
239 243
   BVLinearGradient: 0d985ec461359c82bc254f26d11008bdae50d17a
240 244
   Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933
@@ -268,6 +272,6 @@ SPEC CHECKSUMS:
268 272
   SDWebImage: c5594f1a19c48d526d321e548902b56b479cd508
269 273
   yoga: 74cdf036c30820443b25ade59916236b1e95ee93
270 274
 
271
-PODFILE CHECKSUM: 7d1909450626f31f9ea2de80122a66a50af2e1ea
275
+PODFILE CHECKSUM: b300161e95d65c24b91368803afb8873f4b873cc
272 276
 
273
-COCOAPODS: 1.6.0
277
+COCOAPODS: 1.6.1

+ 21
- 0
ios/sdk/sdk.xcodeproj/project.pbxproj View File

@@ -34,6 +34,7 @@
34 34
 		75635B0B20751D6D00F29C9F /* left.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0920751D6D00F29C9F /* left.wav */; };
35 35
 		87FE6F3321E52437004A5DC7 /* incomingMessage.wav in Resources */ = {isa = PBXBuildFile; fileRef = 87FE6F3221E52437004A5DC7 /* incomingMessage.wav */; };
36 36
 		A4414AE020B37F1A003546E6 /* rejected.wav in Resources */ = {isa = PBXBuildFile; fileRef = A4414ADF20B37F1A003546E6 /* rejected.wav */; };
37
+		A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = A480429B21EE335600289B73 /* AmplitudeModule.m */; };
37 38
 		A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; };
38 39
 		C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
39 40
 		C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
@@ -80,6 +81,7 @@
80 81
 		98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
81 82
 		9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
82 83
 		A4414ADF20B37F1A003546E6 /* rejected.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = rejected.wav; path = ../../sounds/rejected.wav; sourceTree = "<group>"; };
84
+		A480429B21EE335600289B73 /* AmplitudeModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AmplitudeModule.m; path = src/analytics/AmplitudeModule.m; sourceTree = SOURCE_ROOT; };
83 85
 		A4A934E8212F3ADB001E9388 /* Dropbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Dropbox.m; sourceTree = "<group>"; };
84 86
 		A4A934EB21349A06001E9388 /* Dropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dropbox.h; sourceTree = "<group>"; };
85 87
 		C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = "<group>"; };
@@ -148,6 +150,7 @@
148 150
 		0BD906E71EC0C00300C8C18E /* src */ = {
149 151
 			isa = PBXGroup;
150 152
 			children = (
153
+				A480429821ECE2D800289B73 /* analytics */,
151 154
 				0BB9AD7C1F60356D001C08DB /* AppInfo.m */,
152 155
 				0BCA495C1EC4B6C600B793EE /* AudioMode.m */,
153 156
 				C69EFA02209A0EFD0027712B /* callkit */,
@@ -183,6 +186,15 @@
183 186
 			name = Frameworks;
184 187
 			sourceTree = "<group>";
185 188
 		};
189
+		A480429821ECE2D800289B73 /* analytics */ = {
190
+			isa = PBXGroup;
191
+			children = (
192
+				A480429B21EE335600289B73 /* AmplitudeModule.m */,
193
+			);
194
+			name = analytics;
195
+			path = "New Group";
196
+			sourceTree = "<group>";
197
+		};
186 198
 		A4A934E7212F3AB8001E9388 /* dropbox */ = {
187 199
 			isa = PBXGroup;
188 200
 			children = (
@@ -374,6 +386,10 @@
374 386
 			);
375 387
 			inputPaths = (
376 388
 				"${PODS_ROOT}/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet-resources.sh",
389
+				"${PODS_ROOT}/Amplitude-iOS/Amplitude/api.amplitude.com.der",
390
+				"${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoCaLimitedRsaCertificationAuthority.der",
391
+				"${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoRsaCA.der",
392
+				"${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoRsaDomainValidationCA.der",
377 393
 				"${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
378 394
 				"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
379 395
 				"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
@@ -393,6 +409,10 @@
393 409
 			);
394 410
 			name = "[CP] Copy Pods Resources";
395 411
 			outputPaths = (
412
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/api.amplitude.com.der",
413
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoCaLimitedRsaCertificationAuthority.der",
414
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaCA.der",
415
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaDomainValidationCA.der",
396 416
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
397 417
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
398 418
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
@@ -433,6 +453,7 @@
433 453
 				0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
434 454
 				0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */,
435 455
 				0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
456
+				A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */,
436 457
 				C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,
437 458
 				C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
438 459
 				A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */,

+ 55
- 0
ios/sdk/src/analytics/AmplitudeModule.m View File

@@ -0,0 +1,55 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file 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
+#import <React/RCTBridgeModule.h>
18
+#import "Amplitude.h"
19
+
20
+@interface AmplitudeModule : NSObject<RCTBridgeModule>
21
+
22
+@end
23
+
24
+@implementation AmplitudeModule
25
+
26
+RCT_EXPORT_MODULE(Amplitude)
27
+
28
++ (BOOL)requiresMainQueueSetup {
29
+    return NO;
30
+}
31
+
32
+RCT_EXPORT_METHOD(init:(NSString*)instanceName API_KEY:(NSString*)apiKey) {
33
+    [[Amplitude instanceWithName:instanceName] initializeApiKey:apiKey];
34
+}
35
+
36
+RCT_EXPORT_METHOD(setUserProperties:(NSString*)instanceName userPropsString:(NSDictionary*)userProps) {
37
+    if (userProps != nil) {
38
+        [[Amplitude instanceWithName:instanceName] setUserProperties:userProps];
39
+    }
40
+}
41
+
42
+RCT_EXPORT_METHOD(logEvent:(NSString*)instanceName eventType:(NSString*)eventType eventPropsString:(NSString*)eventPropsString) {
43
+    NSError *error;
44
+    NSData *eventPropsData = [eventPropsString dataUsingEncoding:NSUTF8StringEncoding];
45
+    NSDictionary *eventProperties = [NSJSONSerialization JSONObjectWithData:eventPropsData
46
+                                                                   options:NSJSONReadingMutableContainers
47
+                                                                     error:&error];
48
+    if (eventProperties == nil) {
49
+        NSLog(@"[Amplitude handler] Error parsing event properties: %@", error);
50
+    } else {
51
+        [[Amplitude instanceWithName:instanceName] logEvent:eventType withEventProperties:eventProperties];
52
+    }
53
+}
54
+
55
+@end

+ 22
- 6
react/features/analytics/functions.js View File

@@ -6,6 +6,8 @@ import JitsiMeetJS, {
6 6
 } from '../base/lib-jitsi-meet';
7 7
 import { getJitsiMeetGlobalNS, loadScript } from '../base/util';
8 8
 
9
+import { AmplitudeHandler } from './handlers';
10
+
9 11
 const logger = require('jitsi-meet-logger').getLogger(__filename);
10 12
 
11 13
 /**
@@ -23,6 +25,16 @@ export function sendAnalytics(event: Object) {
23 25
     }
24 26
 }
25 27
 
28
+/**
29
+ * Resets the analytics adapter to its initial state - removes handlers, cache,
30
+ * disabled state, etc.
31
+ *
32
+ * @returns {void}
33
+ */
34
+export function resetAnalytics() {
35
+    analytics.reset();
36
+}
37
+
26 38
 /**
27 39
  * Loads the analytics scripts and inits JitsiMeetJS.analytics by setting
28 40
  * permanent properties and setting the handlers from the loaded scripts.
@@ -43,6 +55,9 @@ export function initAnalytics({ getState }: { getState: Function }) {
43 55
 
44 56
     const state = getState();
45 57
     const config = state['features/base/config'];
58
+    const { locationURL } = state['features/base/connection'];
59
+    const host = locationURL ? locationURL.host : '';
60
+
46 61
     const {
47 62
         analytics: analyticsConfig = {},
48 63
         deploymentInfo
@@ -58,6 +73,7 @@ export function initAnalytics({ getState }: { getState: Function }) {
58 73
         envType: (deploymentInfo && deploymentInfo.envType) || 'dev',
59 74
         googleAnalyticsTrackingId,
60 75
         group,
76
+        host,
61 77
         product: deploymentInfo && deploymentInfo.product,
62 78
         subproduct: deploymentInfo && deploymentInfo.environment,
63 79
         user: user && user.id,
@@ -109,7 +125,7 @@ export function initAnalytics({ getState }: { getState: Function }) {
109 125
  * successfully loaded and rejects if there are no handlers loaded or the
110 126
  * analytics is disabled.
111 127
  */
112
-function _loadHandlers(scriptURLs, handlerConstructorOptions) {
128
+function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
113 129
     const promises = [];
114 130
 
115 131
     for (const url of scriptURLs) {
@@ -139,12 +155,12 @@ function _loadHandlers(scriptURLs, handlerConstructorOptions) {
139 155
         // check the old location to provide legacy support
140 156
         const analyticsHandlers = [
141 157
             ...getJitsiMeetGlobalNS().analyticsHandlers,
142
-            ...window.analyticsHandlers
143
-        ];
158
+            ...window.analyticsHandlers,
144 159
 
145
-        if (analyticsHandlers.length === 0) {
146
-            throw new Error('No analytics handlers available');
147
-        }
160
+            // NOTE: when we add second handler it will be good to put all
161
+            // build-in handlers in an array and destruct it here.
162
+            AmplitudeHandler
163
+        ];
148 164
 
149 165
         const handlers = [];
150 166
 

+ 12
- 15
react/features/analytics/handlers/AmplitudeHandler.js View File

@@ -1,15 +1,12 @@
1
-import amplitude from 'amplitude-js';
2
-
3
-import { getJitsiMeetGlobalNS } from '../../base/util';
4
-
5 1
 import AbstractHandler from './AbstractHandler';
2
+import { amplitude } from './amplitude';
6 3
 
7 4
 const logger = require('jitsi-meet-logger').getLogger(__filename);
8 5
 
9 6
 /**
10 7
  * Analytics handler for Amplitude.
11 8
  */
12
-class AmplitudeHandler extends AbstractHandler {
9
+export default class AmplitudeHandler extends AbstractHandler {
13 10
     /**
14 11
      * Creates new instance of the Amplitude analytics handler.
15 12
      *
@@ -20,18 +17,22 @@ class AmplitudeHandler extends AbstractHandler {
20 17
     constructor(options) {
21 18
         super();
22 19
 
23
-        const { amplitudeAPPKey } = options;
20
+        const { amplitudeAPPKey, host } = options;
24 21
 
25 22
         if (!amplitudeAPPKey) {
26 23
             logger.warn(
27
-                'Failed to initialize Amplitude handler, no tracking ID');
24
+                'Failed to initialize Amplitude handler, no APP key');
28 25
 
29 26
             return;
30 27
         }
31 28
 
32 29
         this._enabled = true;
33 30
 
34
-        amplitude.getInstance().init(amplitudeAPPKey);
31
+        this._amplitudeOptions = {
32
+            host
33
+        };
34
+
35
+        amplitude.getInstance(this._amplitudeOptions).init(amplitudeAPPKey);
35 36
     }
36 37
 
37 38
     /**
@@ -42,7 +43,8 @@ class AmplitudeHandler extends AbstractHandler {
42 43
      */
43 44
     setUserProperties(userProps) {
44 45
         if (this._enabled) {
45
-            amplitude.getInstance().setUserProperties(userProps);
46
+            amplitude.getInstance(this._amplitudeOptions)
47
+                .setUserProperties(userProps);
46 48
         }
47 49
     }
48 50
 
@@ -59,13 +61,8 @@ class AmplitudeHandler extends AbstractHandler {
59 61
             return;
60 62
         }
61 63
 
62
-        amplitude.getInstance().logEvent(
64
+        amplitude.getInstance(this._amplitudeOptions).logEvent(
63 65
             this._extractName(event),
64 66
             event);
65 67
     }
66 68
 }
67
-
68
-const globalNS = getJitsiMeetGlobalNS();
69
-
70
-globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
71
-globalNS.analyticsHandlers.push(AmplitudeHandler);

+ 97
- 0
react/features/analytics/handlers/amplitude/Amplitude.native.js View File

@@ -0,0 +1,97 @@
1
+import { NativeModules } from 'react-native';
2
+
3
+const { Amplitude: AmplitudeNative } = NativeModules;
4
+
5
+/**
6
+ * Wrapper for the Amplitude native module.
7
+ */
8
+class Amplitude {
9
+    /**
10
+     * Create new Amplitude instance.
11
+     *
12
+     * @param {string} instanceName - The name of the Amplitude instance. Should
13
+     * be used only for multi-project logging.
14
+     */
15
+    constructor(instanceName) {
16
+        this._instanceName = instanceName;
17
+    }
18
+
19
+    /**
20
+     * Initializes the Amplitude SDK.
21
+     *
22
+     * @param {string} apiKey - The API_KEY of the Amplitude project.
23
+     * @returns {void}
24
+     */
25
+    init(apiKey) {
26
+        AmplitudeNative.init(this._instanceName, apiKey);
27
+    }
28
+
29
+    /**
30
+     * Sets user properties for the current user.
31
+     *
32
+     * @param {Object} userProperties - The user properties to be set.
33
+     * @returns {void}
34
+     */
35
+    setUserProperties(userProperties) {
36
+        AmplitudeNative.setUserProperties(this._instanceName, userProperties);
37
+    }
38
+
39
+    /**
40
+     * Log an event with eventType and eventProperties.
41
+     *
42
+     * @param {string} eventType - The type of the event.
43
+     * @param {Object} eventProperties - The properties of the event.
44
+     * @returns {void}
45
+     */
46
+    logEvent(eventType, eventProperties) {
47
+        // The event properties are converted to JSON string because of known
48
+        // performance issue when passing objects trough the RN bridge too
49
+        // often (a few times a second).
50
+        AmplitudeNative.logEvent(
51
+            this._instanceName, eventType, JSON.stringify(eventProperties));
52
+    }
53
+
54
+}
55
+
56
+/**
57
+ * Cache of <tt>Amplitude</tt> instances by instanceName.
58
+ */
59
+const instances = {};
60
+
61
+/**
62
+ * The default (with instanceName - undefined) <tt>Amplitude</tt> instance.
63
+ */
64
+let defaultInstance;
65
+
66
+export default {
67
+    /**
68
+     * Returns a <tt>Amplitude</tt> instance.
69
+     *
70
+     * @param {Object} options - Optional parameters.
71
+     * @param {string} options.host - The host property from the current URL.
72
+     * @param {string|undefined} options.instanceName - The name of the
73
+     * amplitude instance. Should be used only for multi-project logging.
74
+     * @returns {Amplitude}
75
+     */
76
+    getInstance(options = {}) {
77
+        let instance;
78
+
79
+        const { host = '', instanceName = '' } = options;
80
+
81
+        let internalInstanceName = host;
82
+
83
+        if (instanceName !== '') {
84
+            internalInstanceName += `-${instanceName}`;
85
+        }
86
+
87
+        if (internalInstanceName === '') {
88
+            instance = defaultInstance = defaultInstance || new Amplitude();
89
+        } else {
90
+            instance = instances[internalInstanceName]
91
+                = instances[internalInstanceName]
92
+                    || new Amplitude(internalInstanceName);
93
+        }
94
+
95
+        return instance;
96
+    }
97
+};

+ 7
- 0
react/features/analytics/handlers/amplitude/Amplitude.web.js View File

@@ -0,0 +1,7 @@
1
+import amplitude from 'amplitude-js';
2
+
3
+export default {
4
+    getInstance(options = {}) {
5
+        return amplitude.getInstance(options.instanceName);
6
+    }
7
+};

+ 1
- 0
react/features/analytics/handlers/amplitude/index.js View File

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

+ 1
- 0
react/features/analytics/handlers/index.js View File

@@ -0,0 +1 @@
1
+export { default as AmplitudeHandler } from './AmplitudeHandler';

+ 12
- 1
react/features/analytics/middleware.js View File

@@ -1,7 +1,8 @@
1 1
 import { SET_ROOM } from '../base/conference';
2
+import { SET_CONFIG } from '../base/config';
2 3
 import { MiddlewareRegistry } from '../base/redux';
3 4
 
4
-import { initAnalytics } from './functions';
5
+import { initAnalytics, resetAnalytics } from './functions';
5 6
 
6 7
 /**
7 8
  * Middleware which intercepts config actions to handle evaluating analytics
@@ -12,6 +13,16 @@ import { initAnalytics } from './functions';
12 13
  */
13 14
 MiddlewareRegistry.register(store => next => action => {
14 15
     switch (action.type) {
16
+    case SET_CONFIG: {
17
+        if (navigator.product === 'ReactNative') {
18
+            // Reseting the analytics is currently not needed for web because
19
+            // the user will be redirected to another page and new instance of
20
+            // Analytics will be created and initialized.
21
+            resetAnalytics();
22
+        }
23
+
24
+        break;
25
+    }
15 26
     case SET_ROOM: {
16 27
         const result = next(action);
17 28
 

+ 1
- 10
react/features/base/lib-jitsi-meet/functions.js View File

@@ -43,16 +43,7 @@ export function createLocalTrack(type: string, deviceId: string) {
43 43
  * otherwise.
44 44
  */
45 45
 export function isAnalyticsEnabled(stateful: Function | Object) {
46
-    const {
47
-        analytics = {},
48
-        disableThirdPartyRequests
49
-    } = toState(stateful)['features/base/config'];
50
-    const { scriptURLs } = analytics;
51
-
52
-    return (
53
-        !disableThirdPartyRequests
54
-            && Array.isArray(scriptURLs)
55
-            && Boolean(scriptURLs.length));
46
+    return !toState(stateful)['features/base/config'].disableThirdPartyRequests;
56 47
 }
57 48
 
58 49
 /**

+ 1
- 3
webpack.config.js View File

@@ -135,9 +135,7 @@ module.exports = [
135 135
                 './react/features/local-recording/'
136 136
                     + 'recording/flac/flacEncodeWorker.js',
137 137
             'analytics-ga':
138
-                './react/features/analytics/handlers/GoogleAnalyticsHandler.js',
139
-            'analytics-amplitude':
140
-                './react/features/analytics/handlers/AmplitudeHandler.js'
138
+                './react/features/analytics/handlers/GoogleAnalyticsHandler.js'
141 139
         }
142 140
     }),
143 141
 

Loading…
Cancel
Save