diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle index 4a29b51f36..64c13c1784 100644 --- a/android/sdk/build.gradle +++ b/android/sdk/build.gradle @@ -25,10 +25,6 @@ android { sourceSets { main { java { - if (rootProject.ext.libreBuild) { - srcDir "src" - exclude "**/AmplitudeModule.java" - } exclude "test/" } } @@ -52,18 +48,18 @@ dependencies { implementation 'com.squareup.duktape:duktape-android:1.3.0' if (!rootProject.ext.libreBuild) { - implementation 'com.amplitude:android-sdk:2.14.1' implementation(project(":react-native-google-signin")) { exclude group: 'com.google.android.gms' exclude group: 'androidx' } } + implementation project(':react-native-async-storage') implementation project(':react-native-background-timer') implementation project(':react-native-calendar-events') - implementation project(':react-native-community-async-storage') implementation project(':react-native-community_netinfo') implementation project(':react-native-default-preference') + implementation project(':react-native-device-info') implementation project(':react-native-immersive') implementation project(':react-native-keep-awake') implementation project(':react-native-linear-gradient') diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java deleted file mode 100644 index 41b74b9f03..0000000000 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/AmplitudeModule.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright @ 2019-present 8x8, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jitsi.meet.sdk; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.provider.Settings; -import android.text.TextUtils; - -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableMap; - -import com.amplitude.api.Amplitude; -import com.facebook.react.module.annotations.ReactModule; - -import org.jitsi.meet.sdk.log.JitsiMeetLogger; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Implements the react-native module for the Amplitude integration. - */ -@ReactModule(name = AmplitudeModule.NAME) -class AmplitudeModule - extends ReactContextBaseJavaModule { - - public static final String NAME = "Amplitude"; - public static final String JITSI_PREFERENCES = "jitsi-preferences"; - public static final String AMPLITUDE_DEVICE_ID_KEY = "amplitudeDeviceId"; - - public AmplitudeModule(ReactApplicationContext reactContext) { - super(reactContext); - } - - /** - * Initializes the Amplitude SDK. - * - * @param instanceName The name of the Amplitude instance. Should - * be used only for multi-project logging. - * @param apiKey The API_KEY of the Amplitude project. - */ - @ReactMethod - @SuppressLint("HardwareIds") - public void init(String instanceName, String apiKey) { - Amplitude.getInstance(instanceName).initialize(getCurrentActivity(), apiKey); - - // Set the device ID to something consistent. - SharedPreferences sharedPreferences = getReactApplicationContext().getSharedPreferences(JITSI_PREFERENCES, Context.MODE_PRIVATE); - String android_id = sharedPreferences.getString(AMPLITUDE_DEVICE_ID_KEY, ""); - if (!TextUtils.isEmpty(android_id)) { - Amplitude.getInstance(instanceName).setDeviceId(android_id); - } else { - String amplitudeId = Amplitude.getInstance(instanceName).getDeviceId(); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(JITSI_PREFERENCES, amplitudeId).apply(); - } - } - - /** - * Sets the user ID for an Amplitude instance. - * - * @param instanceName The name of the Amplitude instance. - * @param userId The new value for the user ID. - */ - @ReactMethod - public void setUserId(String instanceName, String userId) { - Amplitude.getInstance(instanceName).setUserId(userId); - } - - /** - * Sets the user properties for an Amplitude instance. - * - * @param instanceName The name of the Amplitude instance. - * @param userProps JSON string with user properties to be set. - */ - @ReactMethod - public void setUserProperties(String instanceName, ReadableMap userProps) { - if (userProps != null) { - Amplitude.getInstance(instanceName).setUserProperties( - new JSONObject(userProps.toHashMap())); - } - } - - /** - * Log an analytics event. - * - * @param instanceName The name of the Amplitude instance. - * @param eventType The event type. - * @param eventPropsString JSON string with the event properties. - */ - @ReactMethod - public void logEvent(String instanceName, String eventType, String eventPropsString) { - try { - JSONObject eventProps = new JSONObject(eventPropsString); - Amplitude.getInstance(instanceName).logEvent(eventType, eventProps); - } catch (JSONException e) { - JitsiMeetLogger.e(e, "Error logging event"); - } - } - - @Override - public String getName() { - return NAME; - } -} diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java index 0c254b8707..50db109f5c 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java @@ -91,14 +91,6 @@ class ReactInstanceManagerHolder { nativeModules.add(new WebRTCModule(reactContext, options)); - try { - Class amplitudeModuleClass = Class.forName("org.jitsi.meet.sdk.AmplitudeModule"); - Constructor constructor = amplitudeModuleClass.getConstructor(ReactApplicationContext.class); - nativeModules.add((NativeModule)constructor.newInstance(reactContext)); - } catch (Exception e) { - // Ignore any error, the module is not compiled when LIBRE_BUILD is enabled. - } - return nativeModules; } @@ -192,6 +184,7 @@ class ReactInstanceManagerHolder { new com.facebook.react.shell.MainReactPackage(), new com.horcrux.svg.SvgPackage(), new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(), + new com.learnium.RNDeviceInfo.RNDeviceInfo(), new com.ocetnik.timer.BackgroundTimerPackage(), new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(), new com.reactnativecommunity.netinfo.NetInfoPackage(), diff --git a/android/settings.gradle b/android/settings.gradle index 5066c24263..919bdb9e54 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,16 +1,18 @@ rootProject.name = 'jitsi-meet' include ':app', ':sdk' +include ':react-native-async-storage' +project(':react-native-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-async-storage/async-storage/android') include ':react-native-background-timer' project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android') include ':react-native-calendar-events' project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android') -include ':react-native-community-async-storage' -project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android') include ':react-native-community_netinfo' project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android') include ':react-native-default-preference' project(':react-native-default-preference').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-default-preference/android') +include ':react-native-device-info' +project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android') include ':react-native-google-signin' project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android') include ':react-native-immersive' diff --git a/ios/Podfile b/ios/Podfile index 9b69a15135..15a29bb4af 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -58,21 +58,21 @@ target 'JitsiMeetSDK' do pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events' pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake' pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo' + pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen' pod 'react-native-webview', :path => '../node_modules/react-native-webview' pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc' pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient' - pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage' + pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-async-storage/async-storage' + pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info' pod 'RNGoogleSignin', :path => '../node_modules/@react-native-community/google-signin' pod 'RNSound', :path => '../node_modules/react-native-sound' pod 'RNSVG', :path => '../node_modules/react-native-svg' pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity' pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference' - pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen' # Native pod dependencies # - pod 'Amplitude-iOS', '~> 4.0.4' pod 'CocoaLumberjack', '~>3.5.3' pod 'ObjectiveDropboxOfficial', '~> 3.9.4' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a578a159b5..a5dfb3af4f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,5 +1,4 @@ PODS: - - Amplitude-iOS (4.0.4) - AppAuth (1.2.0): - AppAuth/Core (= 1.2.0) - AppAuth/ExternalUserAgent (= 1.2.0) @@ -351,10 +350,12 @@ PODS: - React-jsi (= 0.61.5-jitsi.2) - ReactCommon/jscallinvoker (= 0.61.5-jitsi.2) - ReactCommon/turbomodule/core (= 0.61.5-jitsi.2) - - RNCAsyncStorage (1.3.4): + - RNCAsyncStorage (1.13.2): - React - RNDefaultPreference (1.4.2): - React + - RNDeviceInfo (7.3.1): + - React-Core - RNGoogleSignin (3.0.1): - GoogleSignIn (~> 5.0.0) - React @@ -370,7 +371,6 @@ PODS: - Yoga (1.14.0) DEPENDENCIES: - - Amplitude-iOS (~> 4.0.4) - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) - CocoaLumberjack (~> 3.5.3) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) @@ -410,8 +410,9 @@ DEPENDENCIES: - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`) - - "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)" + - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - RNDefaultPreference (from `../node_modules/react-native-default-preference`) + - RNDeviceInfo (from `../node_modules/react-native-device-info`) - "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)" - RNSound (from `../node_modules/react-native-sound`) - RNSVG (from `../node_modules/react-native-svg`) @@ -420,7 +421,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - - Amplitude-iOS - AppAuth - boost-for-react-native - CocoaLumberjack @@ -507,9 +507,11 @@ EXTERNAL SOURCES: ReactCommon: :path: "../node_modules/react-native/ReactCommon" RNCAsyncStorage: - :path: "../node_modules/@react-native-community/async-storage" + :path: "../node_modules/@react-native-async-storage/async-storage" RNDefaultPreference: :path: "../node_modules/react-native-default-preference" + RNDeviceInfo: + :path: "../node_modules/react-native-device-info" RNGoogleSignin: :path: "../node_modules/@react-native-community/google-signin" RNSound: @@ -522,7 +524,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7 AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 @@ -574,14 +575,15 @@ SPEC CHECKSUMS: React-RCTText: 4f1b99f228278d2a5e9008eced8dc9c974c4a270 React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676 ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6 - RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323 + RNCAsyncStorage: bc2f81cc1df90c267ce9ed30bb2dbc93b945a8ee RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1 + RNDeviceInfo: 57bb2806fb7bd982a1434e9f0b4e6a6ab1f6702e RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20 RNSVG: 069864be08c9fe065a2cf7e63656a34c78653c99 RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3 Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c -PODFILE CHECKSUM: e77f7134cda53f089046f29cb1f32b08c00c8a2e +PODFILE CHECKSUM: 5be5132e41831a98362eeed760558227a4df89ae COCOAPODS: 1.10.0 diff --git a/ios/sdk/sdk.xcodeproj/project.pbxproj b/ios/sdk/sdk.xcodeproj/project.pbxproj index 0bd4d2735d..03dd4e2b24 100644 --- a/ios/sdk/sdk.xcodeproj/project.pbxproj +++ b/ios/sdk/sdk.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 75635B0B20751D6D00F29C9F /* left.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0920751D6D00F29C9F /* left.wav */; }; 87FE6F3321E52437004A5DC7 /* incomingMessage.wav in Resources */ = {isa = PBXBuildFile; fileRef = 87FE6F3221E52437004A5DC7 /* incomingMessage.wav */; }; A4414AE020B37F1A003546E6 /* rejected.wav in Resources */ = {isa = PBXBuildFile; fileRef = A4414ADF20B37F1A003546E6 /* rejected.wav */; }; - A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = A480429B21EE335600289B73 /* AmplitudeModule.m */; }; A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; }; C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */; }; C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */; }; @@ -94,7 +93,6 @@ 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 = ""; }; 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 = ""; }; A4414ADF20B37F1A003546E6 /* rejected.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = rejected.wav; path = ../../sounds/rejected.wav; sourceTree = ""; }; - A480429B21EE335600289B73 /* AmplitudeModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AmplitudeModule.m; path = src/analytics/AmplitudeModule.m; sourceTree = SOURCE_ROOT; }; A4A934E8212F3ADB001E9388 /* Dropbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Dropbox.m; sourceTree = ""; }; A4A934EB21349A06001E9388 /* Dropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dropbox.h; sourceTree = ""; }; C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOff.mp3; path = ../../sounds/liveStreamingOff.mp3; sourceTree = ""; }; @@ -190,7 +188,6 @@ 0BD906E71EC0C00300C8C18E /* src */ = { isa = PBXGroup; children = ( - A480429821ECE2D800289B73 /* analytics */, 0BB9AD7C1F60356D001C08DB /* AppInfo.m */, 0BCA495C1EC4B6C600B793EE /* AudioMode.m */, C69EFA02209A0EFD0027712B /* callkit */, @@ -246,15 +243,6 @@ name = Frameworks; sourceTree = ""; }; - A480429821ECE2D800289B73 /* analytics */ = { - isa = PBXGroup; - children = ( - A480429B21EE335600289B73 /* AmplitudeModule.m */, - ); - name = analytics; - path = "New Group"; - sourceTree = ""; - }; A4A934E7212F3AB8001E9388 /* dropbox */ = { isa = PBXGroup; children = ( @@ -438,18 +426,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources.sh", - "${PODS_ROOT}/Amplitude-iOS/Amplitude/api.amplitude.com.der", - "${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoCaLimitedRsaCertificationAuthority.der", - "${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoRsaCA.der", - "${PODS_ROOT}/Amplitude-iOS/Amplitude/ComodoRsaDomainValidationCA.der", "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/api.amplitude.com.der", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoCaLimitedRsaCertificationAuthority.der", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaCA.der", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaDomainValidationCA.der", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", ); runOnlyForDeploymentPostprocessing = 0; @@ -479,7 +459,6 @@ DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */, 0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */, 0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */, - A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */, C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */, DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */, C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */, diff --git a/ios/sdk/src/analytics/AmplitudeModule.m b/ios/sdk/src/analytics/AmplitudeModule.m deleted file mode 100644 index 5942457c5f..0000000000 --- a/ios/sdk/src/analytics/AmplitudeModule.m +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright @ 2018-present 8x8, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import - -#import "Amplitude.h" -#import "LogUtils.h" - - -@interface AmplitudeModule : NSObject -@end - -@implementation AmplitudeModule - -RCT_EXPORT_MODULE(Amplitude) - -+ (BOOL)requiresMainQueueSetup { - return NO; -} - -RCT_EXPORT_METHOD(init:(NSString*)instanceName API_KEY:(NSString*)apiKey) { - [[Amplitude instanceWithName:instanceName] initializeApiKey:apiKey]; -} - -RCT_EXPORT_METHOD(setUserId:(NSString*)instanceName userId: (NSString *) userId) { - [[Amplitude instanceWithName:instanceName] setUserId:userId]; -} - -RCT_EXPORT_METHOD(setUserProperties:(NSString*)instanceName userPropsString:(NSDictionary*)userProps) { - if (userProps != nil) { - [[Amplitude instanceWithName:instanceName] setUserProperties:userProps]; - } -} - -RCT_EXPORT_METHOD(logEvent:(NSString*)instanceName eventType:(NSString*)eventType eventPropsString:(NSString*)eventPropsString) { - NSError *error; - NSData *eventPropsData = [eventPropsString dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *eventProperties = [NSJSONSerialization JSONObjectWithData:eventPropsData - options:NSJSONReadingMutableContainers - error:&error]; - if (eventProperties == nil) { - DDLogError(@"[Amplitude] Error parsing event properties: %@", error); - } else { - [[Amplitude instanceWithName:instanceName] logEvent:eventType withEventProperties:eventProperties]; - } -} - -@end diff --git a/package-lock.json b/package-lock.json index 26d0e440a9..707c3b58f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,11 +4,34 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@amplitude/eslint-config-typescript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@amplitude/eslint-config-typescript/-/eslint-config-typescript-1.1.0.tgz", + "integrity": "sha512-N8sKkwtFakPD2/cSOrBnM5Wudjp4qeDD69U1cG7dZ6DDczxBhUEqnJDJ0wiYmKMPXqr+bmFOsDdbCcOmb/CLYA==" + }, + "@amplitude/types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.1.0.tgz", + "integrity": "sha512-aJebJlI1hfRrzsbcRzW1heTDEClhElwEJ4ODyYZbBacKzH29q3OKZCkgNfaEYdxfgLpoDSh/ffHYpl7fWm3SQA==", + "requires": { + "@amplitude/eslint-config-typescript": "^1.1.0" + } + }, "@amplitude/ua-parser-js": { "version": "0.7.24", "resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.24.tgz", "integrity": "sha512-VbQuJymJ20WEw0HtI2np7EdC3NJGUWi8+Xdbc7uk8WfMIF308T0howpzkQ3JFMN7ejnrcSM/OyNGveeE3TP3TA==" }, + "@amplitude/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-TbKgBZNSRFu5RfYTKpprn/DFlZqr8jnmjXASZyQ/m8XDdbD2VoRqHDmKUwFiruX9OhAb2m9BhjLuaiwRYHCcqQ==", + "requires": { + "@amplitude/eslint-config-typescript": "^1.1.0", + "@amplitude/types": "^1.1.0", + "tslib": "^1.9.3" + } + }, "@atlaskit/analytics-next": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@atlaskit/analytics-next/-/analytics-next-3.2.1.tgz", @@ -3343,10 +3366,13 @@ "isomorphic-fetch": "^2.2.1" } }, - "@react-native-community/async-storage": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.3.4.tgz", - "integrity": "sha512-fJmzL27x0BEjhmMXPnDPnUNCZK7bph+NBVCfAz9fzHzAamaiOkdUwuL3PvE4Oj4Kw4knP8ocw5VRDGorAidZ2g==" + "@react-native-async-storage/async-storage": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.13.2.tgz", + "integrity": "sha512-isTDvUApRJPVWFxV15yrQSOGqarX7cIedq/y4N5yWSnotf68D9qvDEv1I7rCXhkBDi0u4OJt6GA9dksUT0D3wg==", + "requires": { + "deep-assign": "^3.0.0" + } }, "@react-native-community/cli-debugger-ui": { "version": "3.0.0", @@ -4922,11 +4948,12 @@ "dev": true }, "amplitude-js": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-7.3.1.tgz", - "integrity": "sha512-dsJU9MdtDDAOtKnbHrJuVBgsL5UGxD1P2B7doGdAQ1hxxT/5mFrmJTFzi1tKe+2ir3QtcRa9B0qvH8TMsGw22A==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-7.3.3.tgz", + "integrity": "sha512-krSXUXeHqbQk15ozx0kC3h0K3i7wQ1ycSG08OfZBga2Vfbi3Y30CP6UXLdtJX4AiBB8EkjMePdMgU6kyuIpi/A==", "requires": { "@amplitude/ua-parser-js": "0.7.24", + "@amplitude/utils": "^1.0.5", "blueimp-md5": "^2.10.0", "query-string": "5" } @@ -7246,6 +7273,14 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "deep-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-3.0.0.tgz", + "integrity": "sha512-YX2i9XjJ7h5q/aQ/IM9PEwEnDqETAIYbggmdDB3HLTlSgo1CxPsj6pvhPG68rq6SVE0+p+6Ywsm5fTYNrYtBWw==", + "requires": { + "is-obj": "^1.0.0" + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -10245,6 +10280,11 @@ "kind-of": "^3.0.2" } }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -14158,6 +14198,11 @@ "resolved": "https://registry.npmjs.org/react-native-default-preference/-/react-native-default-preference-1.4.2.tgz", "integrity": "sha512-kNhBLv8s6kO2gJJFEKM7qew7oRvJnygjgG1CU2ZEY6SlG5qsRX8z1Ms7z1Oo/XB7fVfyXrAoZDGhIvy+uiByrg==" }, + "react-native-device-info": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-7.3.1.tgz", + "integrity": "sha512-RQP3etbmXsOlcaxHeHNug68nRli02S9iGC7TbaXpkvyyevIuRogfnrI71sWtqmlT91kdpYAOYKmNfRL9LOSKVw==" + }, "react-native-immersive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz", diff --git a/package.json b/package.json index abc2ba5c24..1b6b92360e 100644 --- a/package.json +++ b/package.json @@ -34,13 +34,13 @@ "@atlaskit/tooltip": "12.1.13", "@jitsi/js-utils": "1.0.3", "@microsoft/microsoft-graph-client": "1.1.0", - "@react-native-community/async-storage": "1.3.4", + "@react-native-async-storage/async-storage": "1.13.2", "@react-native-community/google-signin": "3.0.1", "@react-native-community/netinfo": "4.1.5", "@svgr/webpack": "4.3.2", "@tensorflow-models/body-pix": "2.0.4", "@tensorflow/tfjs": "1.5.1", - "amplitude-js": "7.3.1", + "amplitude-js": "7.3.3", "base64-js": "1.3.1", "bc-css-flags": "3.0.0", "dropbox": "4.0.9", @@ -75,6 +75,7 @@ "react-native-callstats": "3.61.0", "react-native-collapsible": "1.5.1", "react-native-default-preference": "1.4.2", + "react-native-device-info": "7.3.1", "react-native-immersive": "2.0.0", "react-native-keep-awake": "4.0.0", "react-native-linear-gradient": "2.5.6", diff --git a/react/features/analytics/handlers/AmplitudeHandler.js b/react/features/analytics/handlers/AmplitudeHandler.js index 0535c10b16..f36d56d11b 100644 --- a/react/features/analytics/handlers/AmplitudeHandler.js +++ b/react/features/analytics/handlers/AmplitudeHandler.js @@ -1,5 +1,9 @@ +import amplitude from 'amplitude-js'; + +import logger from '../logger'; + import AbstractHandler from './AbstractHandler'; -import { amplitude, fixDeviceID } from './amplitude'; +import { fixDeviceID } from './amplitude'; /** * Analytics handler for Amplitude. @@ -17,24 +21,39 @@ export default class AmplitudeHandler extends AbstractHandler { const { amplitudeAPPKey, host, user } = options; - if (!amplitudeAPPKey) { - throw new Error('Failed to initialize Amplitude handler, no APP key'); - } - this._enabled = true; + this._host = host; // Only used on React Native. - this._amplitudeOptions = { - host + const onError = e => { + logger.error('Error initializing Amplitude', e); + this._enabled = false; }; - amplitude.getInstance(this._amplitudeOptions).init(amplitudeAPPKey, undefined, { includeReferrer: true }); - fixDeviceID(amplitude.getInstance(this._amplitudeOptions)); + const amplitudeOptions = { + domain: navigator.product === 'ReactNative' ? host : undefined, + includeReferrer: true, + onError + }; + + this._getInstance().init(amplitudeAPPKey, undefined, amplitudeOptions); + fixDeviceID(this._getInstance()); if (user) { - amplitude.getInstance(this._amplitudeOptions).setUserId(user); + this._getInstance().setUserId(user); } } + /** + * Returns the AmplitudeClient instance. + * + * @returns {AmplitudeClient} + */ + _getInstance() { + const name = navigator.product === 'ReactNative' ? this._host : undefined; + + return amplitude.getInstance(name); + } + /** * Sets the Amplitude user properties. * @@ -43,8 +62,7 @@ export default class AmplitudeHandler extends AbstractHandler { */ setUserProperties(userProps) { if (this._enabled) { - amplitude.getInstance(this._amplitudeOptions) - .setUserProperties(userProps); + this._getInstance().setUserProperties(userProps); } } @@ -61,9 +79,7 @@ export default class AmplitudeHandler extends AbstractHandler { return; } - amplitude.getInstance(this._amplitudeOptions).logEvent( - this._extractName(event), - event); + this._getInstance().logEvent(this._extractName(event), event); } /** @@ -72,15 +88,10 @@ export default class AmplitudeHandler extends AbstractHandler { * @returns {Object} */ getIdentityProps() { - // TODO: Remove when web and native Aplitude implementations are unified. - if (navigator.product === 'ReactNative') { - return {}; - } - return { - sessionId: amplitude.getInstance(this._amplitudeOptions).getSessionId(), - deviceId: amplitude.getInstance(this._amplitudeOptions).options.deviceId, - userId: amplitude.getInstance(this._amplitudeOptions).options.userId + sessionId: this._getInstance().getSessionId(), + deviceId: this._getInstance().options.deviceId, + userId: this._getInstance().options.userId }; } } diff --git a/react/features/analytics/handlers/amplitude/Amplitude.native.js b/react/features/analytics/handlers/amplitude/Amplitude.native.js deleted file mode 100644 index 56dbd2ced2..0000000000 --- a/react/features/analytics/handlers/amplitude/Amplitude.native.js +++ /dev/null @@ -1,115 +0,0 @@ -import { NativeModules } from 'react-native'; - -const { Amplitude: AmplitudeNative } = NativeModules; - -/** - * Wrapper for the Amplitude native module. - */ -class Amplitude { - /** - * Create new Amplitude instance. - * - * @param {string} instanceName - The name of the Amplitude instance. Should - * be used only for multi-project logging. - */ - constructor(instanceName) { - // It might not have been included in the build. - if (!AmplitudeNative) { - throw new Error('Amplitude analytics is not supported'); - } - - this._instanceName = instanceName; - } - - /** - * Initializes the Amplitude SDK. - * - * @param {string} apiKey - The API_KEY of the Amplitude project. - * @returns {void} - */ - init(apiKey) { - AmplitudeNative.init(this._instanceName, apiKey); - } - - /** - * Sets an identifier for the current user. - * - * @param {string} userId - The new user id. - * @param {string} opt_userId - Currently not used. - * @param {Object} opt_config - Currently not used. - * @param {Function} opt_callback - Currently not used. - * @returns {void} - */ - setUserId(userId, opt_userId, opt_config, opt_callback) { // eslint-disable-line camelcase, no-unused-vars - AmplitudeNative.setUserId(this._instanceName, userId); - } - - /** - * Sets user properties for the current user. - * - * @param {Object} userProperties - The user properties to be set. - * @returns {void} - */ - setUserProperties(userProperties) { - AmplitudeNative.setUserProperties(this._instanceName, userProperties); - } - - /** - * Log an event with eventType and eventProperties. - * - * @param {string} eventType - The type of the event. - * @param {Object} eventProperties - The properties of the event. - * @returns {void} - */ - logEvent(eventType, eventProperties) { - // The event properties are converted to JSON string because of known - // performance issue when passing objects trough the RN bridge too - // often (a few times a second). - AmplitudeNative.logEvent( - this._instanceName, eventType, JSON.stringify(eventProperties)); - } - -} - -/** - * Cache of Amplitude instances by instanceName. - */ -const instances = {}; - -/** - * The default (with instanceName - undefined) Amplitude instance. - */ -let defaultInstance; - -export default { - /** - * Returns a Amplitude instance. - * - * @param {Object} options - Optional parameters. - * @param {string} options.host - The host property from the current URL. - * @param {string|undefined} options.instanceName - The name of the - * amplitude instance. Should be used only for multi-project logging. - * @returns {Amplitude} - */ - getInstance(options = {}) { - let instance; - - const { host = '', instanceName = '' } = options; - - let internalInstanceName = host; - - if (instanceName !== '') { - internalInstanceName += `-${instanceName}`; - } - - if (internalInstanceName === '') { - instance = defaultInstance = defaultInstance || new Amplitude(); - } else { - instance = instances[internalInstanceName] - = instances[internalInstanceName] - || new Amplitude(internalInstanceName); - } - - return instance; - } -}; diff --git a/react/features/analytics/handlers/amplitude/Amplitude.web.js b/react/features/analytics/handlers/amplitude/Amplitude.web.js deleted file mode 100644 index 21c01c6f03..0000000000 --- a/react/features/analytics/handlers/amplitude/Amplitude.web.js +++ /dev/null @@ -1,14 +0,0 @@ -import amplitude from 'amplitude-js'; - -export default { - /** - * Returns the AmplitudeClient instance. - * - * @param {Object} options - Optional parameters. - * @property {string} options.instanceName - The name of the AmplitudeClient instance. - * @returns {AmplitudeClient} - */ - getInstance(options = {}) { - return amplitude.getInstance(options.instanceName); - } -}; diff --git a/react/features/analytics/handlers/amplitude/fixDeviceID.native.js b/react/features/analytics/handlers/amplitude/fixDeviceID.native.js index 04a46c9d4c..b28ab967c0 100644 --- a/react/features/analytics/handlers/amplitude/fixDeviceID.native.js +++ b/react/features/analytics/handlers/amplitude/fixDeviceID.native.js @@ -1,9 +1,23 @@ +import DefaultPreference from 'react-native-default-preference'; +import DeviceInfo from 'react-native-device-info'; + /** * Custom logic for setting the correct device id. * * @param {AmplitudeClient} amplitude - The amplitude instance. * @returns {void} */ -export function fixDeviceID(amplitude) { // eslint-disable-line no-unused-vars +export async function fixDeviceID(amplitude) { + await DefaultPreference.setName('jitsi-preferences'); + const current = await DefaultPreference.get('amplitudeDeviceId'); + + if (current) { + amplitude.setDeviceId(current); + } else { + const uid = DeviceInfo.getUniqueId(); + + amplitude.setDeviceId(uid); + DefaultPreference.set('amplitudeDeviceId', uid); + } } diff --git a/react/features/analytics/handlers/amplitude/index.js b/react/features/analytics/handlers/amplitude/index.js index 80d88bb7a5..00a09625e8 100644 --- a/react/features/analytics/handlers/amplitude/index.js +++ b/react/features/analytics/handlers/amplitude/index.js @@ -1,2 +1 @@ -export { default as amplitude } from './Amplitude'; export * from './fixDeviceID'; diff --git a/react/features/mobile/polyfills/Storage.js b/react/features/mobile/polyfills/Storage.js index 538573e8c3..5cb1417a9f 100644 --- a/react/features/mobile/polyfills/Storage.js +++ b/react/features/mobile/polyfills/Storage.js @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-community/async-storage'; +import AsyncStorage from '@react-native-async-storage/async-storage'; /** * A Web Sorage API implementation used for polyfilling