From 370edf713d9c594627f4b8f5635fe5c9fa6a4ebc Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Mon, 14 Feb 2022 17:33:30 -0800 Subject: [PATCH 1/8] feat: introduce integrated amplitude SDKs --- android/build.gradle | 4 ++-- experiment-react-native-client.podspec | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 5bc396c..ae0caed 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -56,6 +56,6 @@ repositories { dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules - implementation 'com.amplitude:experiment-android-client:1.4.0' - implementation 'com.amplitude:android-sdk:2.26.1' + implementation 'com.amplitude:experiment-android-client:1.5.1' + implementation 'com.amplitude:android-sdk:2.36.1' } diff --git a/experiment-react-native-client.podspec b/experiment-react-native-client.podspec index 29b2590..26cc63f 100644 --- a/experiment-react-native-client.podspec +++ b/experiment-react-native-client.podspec @@ -16,6 +16,6 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency "Amplitude" - s.dependency "AmplitudeExperiment", "1.5.0" + s.dependency "Amplitude", "8.8.0" + s.dependency "AmplitudeExperiment", "1.6.0" end From b6d9d822dca5eef11bf6feaaadb2d398a7c302b4 Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Wed, 16 Feb 2022 15:41:33 -0800 Subject: [PATCH 2/8] feat: update rn api --- .../ExperimentReactNativeClientModule.java | 54 +++++++- example/ios/Podfile.lock | 25 ++-- ios/ExperimentReactNativeClient.swift | 126 ++++++++++++------ src/index.ts | 11 ++ src/types.ts | 39 +++++- 5 files changed, 192 insertions(+), 63 deletions(-) diff --git a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java index e9d059e..d51e6bd 100644 --- a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java +++ b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java @@ -65,7 +65,7 @@ public String getName() { @ReactMethod public void initialize(String apiKey, ReadableMap config, Promise promise) { try { - ExperimentConfig convertedConfig = convertConfig(config); + ExperimentConfig convertedConfig = convertConfig(config, false); experimentClient = Experiment.initialize( (Application) this.reactContext.getApplicationContext(), apiKey, @@ -78,6 +78,22 @@ public void initialize(String apiKey, ReadableMap config, Promise promise) { } } + @ReactMethod + public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, Promise promise) { + try { + ExperimentConfig convertedConfig = convertConfig(config, true); + experimentClient = Experiment.initializeWithAmplitudeAnalytics( + (Application) this.reactContext.getApplicationContext(), + apiKey, + convertedConfig + ); + promise.resolve(true); + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + promise.reject(e); + } + } + @ReactMethod public void fetch(ReadableMap user, Promise promise) { try { @@ -119,6 +135,17 @@ public void variant(String key, Promise promise) { } } + @ReactMethod + public void exposure(String flagKey, Promise promise) { + try { + experimentClient.exposure(flagKey); + promise.resolve(true); + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + promise.reject(e); + } + } + @ReactMethod public void variantWithFallback(String flagKey, ReadableMap fallback, Promise promise) { @@ -166,7 +193,7 @@ public void setAmplitudeUserProvider(String amplitudeInstanceName, Promise promi } // Conversion methods - private ExperimentConfig convertConfig(ReadableMap config) { + private ExperimentConfig convertConfig(ReadableMap config, boolean integrated) { ExperimentConfig.Builder builder = ExperimentConfig.builder(); if (config == null) { return builder.build(); @@ -174,6 +201,9 @@ private ExperimentConfig convertConfig(ReadableMap config) { if (config.hasKey("debug")) { builder.debug(config.getBoolean("debug")); } + if (config.hasKey("instanceName")) { + builder.instanceName(config.getString("instanceName")); + } if (config.hasKey("fallbackVariant")) { ReadableMap map = config.getMap("fallbackVariant"); Variant fallbackVariant = new Variant( @@ -204,19 +234,29 @@ private ExperimentConfig convertConfig(ReadableMap config) { if (config.hasKey("retryFetchOnFailure")) { builder.retryFetchOnFailure(config.getBoolean("retryFetchOnFailure")); } - if (config.hasKey("amplitudeUserProviderInstanceName")) { + if (config.hasKey("automaticExposureTracking")) { + builder.automaticExposureTracking(config.getBoolean("automaticExposureTracking")); + } + if (config.hasKey("automaticFetchOnAmplitudeIdentityChange")) { + builder.automaticFetchOnAmplitudeIdentityChange(config.getBoolean("automaticFetchOnAmplitudeIdentityChange")); + } + + if (!integrated) { + // Deprecated + if (config.hasKey("amplitudeUserProviderInstanceName")) { String instanceName = config.getString("amplitudeUserProviderInstanceName"); AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); if (amplitudeInstance != null) { - builder.userProvider(new AmplitudeUserProvider(amplitudeInstance)); + builder.userProvider(new AmplitudeUserProvider(amplitudeInstance)); } - } - if (config.hasKey("amplitudeAnalyticsProviderInstanceName")) { + } + if (config.hasKey("amplitudeAnalyticsProviderInstanceName")) { String instanceName = config.getString("amplitudeAnalyticsProviderInstanceName"); AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); if (amplitudeInstance != null) { - builder.analyticsProvider(new AmplitudeAnalyticsProvider(amplitudeInstance)); + builder.analyticsProvider(new AmplitudeAnalyticsProvider(amplitudeInstance)); } + } } return builder.build(); } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f042635..3ae3678 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,15 +1,18 @@ PODS: - - Amplitude (8.5.0) + - Amplitude (8.8.0): + - AnalyticsConnector (~> 1.0.0) - amplitude-react-native (2.6.0): - - Amplitude (= 8.5.0) + - Amplitude (= 8.8.0) - React-Core - - AmplitudeExperiment (1.5.0) + - AmplitudeExperiment (1.6.0): + - AnalyticsConnector (~> 1.0.0) + - AnalyticsConnector (1.0.0) - boost-for-react-native (1.63.0) - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - - experiment-react-native-client (0.5.1): - - Amplitude - - AmplitudeExperiment (= 1.5.0) + - experiment-react-native-client (0.5.2): + - Amplitude (= 8.8.0) + - AmplitudeExperiment (= 1.6.0) - React-Core - FBLazyVector (0.63.3) - FBReactNativeSpec (0.63.3): @@ -373,6 +376,7 @@ SPEC REPOS: trunk: - Amplitude - AmplitudeExperiment + - AnalyticsConnector - boost-for-react-native - CocoaAsyncSocket - Flipper @@ -445,13 +449,14 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Amplitude: ef9ed339ddd33c9183edf63fa4bbaa86cf873321 - amplitude-react-native: fa5e830e59fd8ed440a74d58fd72ad4b37e7c946 - AmplitudeExperiment: 56180276d6dfc277659acac6495764de3e848d80 + Amplitude: 710116f3539c225e86fb70a8abdcd20015683132 + amplitude-react-native: cb93e8a7d8ac80e359b40185976a27f1dcab65e9 + AmplitudeExperiment: 2ae761f52e7d7d15f9516bcf796a06d0c57e97b8 + AnalyticsConnector: 4c386d5972ac9da86e22d668564dbbac97558754 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: cde416483dac037923206447da6e1454df403714 - experiment-react-native-client: 2691b4bd4d9b58e35e5ed79ba5c18f162e3f2180 + experiment-react-native-client: 9c14d0087aa28140fe038ded1406c47a49a958af FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f Flipper: 1bd2db48dcc31e4b167b9a33ec1df01c2ded4893 diff --git a/ios/ExperimentReactNativeClient.swift b/ios/ExperimentReactNativeClient.swift index 820df6d..f49eae9 100644 --- a/ios/ExperimentReactNativeClient.swift +++ b/ios/ExperimentReactNativeClient.swift @@ -18,51 +18,20 @@ class ExperimentReactNativeClient: NSObject { resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) -> Void { - let builder = ExperimentConfig.Builder() - if let val = config?["debug"] as! Bool? { - let _ = builder.debug(val) - } - if let val = config?["fallbackVariant"] as! [String: Any]? { - let _ = builder.fallbackVariant(Variant.init(val["value"] as! String?, payload: val["payload"])) - } - if let val = config?["initialVariants"] as! [String: [String: Any]]? { - let initialVariants = val.mapValues { value in - return Variant.init(value["value"] as! String?, payload: value["payload"]) - } - let _ = builder.initialVariants(initialVariants) - } - if let val = config?["serverUrl"] as! String? { - let _ = builder.serverUrl(val) - } - if let val = config?["source"] as! String? { - var source: Source? = nil - if (val == "LOCAL_STORAGE") { - source = Source.LocalStorage - } else if (val == "INITIAL_VARIANTS") { - source = Source.InitialVariants - } + let convertedConfig = convertConfig(config: config, integrated: false) + experimentClient = Experiment.initialize(apiKey: apiKey, config: convertedConfig) + resolve(true) + } - if let source = source { - let _ = builder.source(source) - } - } - if let val = config?["fetchTimeoutMillis"] as! Int? { - let _ = builder.fetchTimeoutMillis(val) - } - if let val = config?["retryFetchOnFailure"] as! Bool? { - let _ = builder.fetchRetryOnFailure(val) - } - if let val = config?["amplitudeUserProviderInstanceName"] as! String? { - let amplitudeInstance = Amplitude.instance(withName: val) - let userProvider = AmplitudeUserProvider(amplitudeInstance) - let _ = builder.userProvider(userProvider) - } - if let val = config?["amplitudeAnalyticsProviderInstanceName"] as! String? { - let amplitudeInstance = Amplitude.instance(withName: val) - let analyticsProvider = AmplitudeAnalyticsProvider(amplitudeInstance) - let _ = builder.analyticsProvider(analyticsProvider) - } - experimentClient = Experiment.initialize(apiKey: apiKey, config: builder.build()) + @objc + func initializeWithAmplitudeAnalytics( + _ apiKey: String, + config: [String:Any]?, + resolver resolve: RCTPromiseResolveBlock, + rejecter reject: RCTPromiseRejectBlock + ) -> Void { + let convertedConfig = convertConfig(config: config, integrated: true) + experimentClient = Experiment.initializeWithAmplitudeAnalytics(apiKey: apiKey, config: convertedConfig) resolve(true) } @@ -143,6 +112,65 @@ class ExperimentReactNativeClient: NSObject { return builder.build() } + @objc + func convertConfig(config: [String:Any]?, integrated: Bool) -> ExperimentConfig { + let builder = ExperimentConfig.Builder() + if let val = config?["debug"] as! Bool? { + let _ = builder.debug(val) + } + if let val = config?["instanceName"] as! String? { + let _ = builder.instanceName(val) + } + if let val = config?["fallbackVariant"] as! [String: Any]? { + let _ = builder.fallbackVariant(Variant.init(val["value"] as! String?, payload: val["payload"])) + } + if let val = config?["initialVariants"] as! [String: [String: Any]]? { + let initialVariants = val.mapValues { value in + return Variant.init(value["value"] as! String?, payload: value["payload"]) + } + let _ = builder.initialVariants(initialVariants) + } + if let val = config?["serverUrl"] as! String? { + let _ = builder.serverUrl(val) + } + if let val = config?["source"] as! String? { + var source: Source? = nil + if (val == "LOCAL_STORAGE") { + source = Source.LocalStorage + } else if (val == "INITIAL_VARIANTS") { + source = Source.InitialVariants + } + if let source = source { + let _ = builder.source(source) + } + } + if let val = config?["fetchTimeoutMillis"] as! Int? { + let _ = builder.fetchTimeoutMillis(val) + } + if let val = config?["retryFetchOnFailure"] as! Bool? { + let _ = builder.fetchRetryOnFailure(val) + } + if let val = config?["automaticExposureTracking"] as! Bool? { + let _ = builder.automaticExposureTracking(val) + } + if let val = config?["automaticFetchOnAmplitudeIdentityChange"] as! Bool? { + let _ = builder.automaticFetchOnAmplitudeIdentityChange(val) + } + + // Deprecated + if let val = config?["amplitudeUserProviderInstanceName"] as! String? { + let amplitudeInstance = Amplitude.instance(withName: val) + let userProvider = AmplitudeUserProvider(amplitudeInstance) + let _ = builder.userProvider(userProvider) + } + if let val = config?["amplitudeAnalyticsProviderInstanceName"] as! String? { + let amplitudeInstance = Amplitude.instance(withName: val) + let analyticsProvider = AmplitudeAnalyticsProvider(amplitudeInstance) + let _ = builder.analyticsProvider(analyticsProvider) + } + return builder.build() + } + @objc func variant( _ key: String, @@ -191,6 +219,16 @@ class ExperimentReactNativeClient: NSObject { } } + @objc + func exposure( + _ flagKey: String, + resolver resolve: RCTPromiseResolveBlock, + rejecter reject: RCTPromiseRejectBlock + ) -> Void { + experimentClient?.exposure(key: flagKey) + resolve(true) + } + @objc func setAmplitudeUserProvider( _ amplitudeInstanceName: String?, diff --git a/src/index.ts b/src/index.ts index ffb846c..f6d3296 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,13 @@ export const Experiment = { return ExperimentReactNativeClient.initialize(apiKey, config); }, + initializeWithAmplitudeAnalytics: async ( + apiKey: string, + config?: ExperimentConfig + ): Promise => { + return ExperimentReactNativeClient.initializeWithAmplitudeAnalytics(apiKey, config); + }, + fetch: async (user?: ExperimentUser): Promise => { if (!user?.library) { user = { @@ -53,6 +60,10 @@ export const Experiment = { return ExperimentReactNativeClient.all(); }, + exposure: async (): Promise => { + return ExperimentReactNativeClient.exposure() + }, + setAmplitudeUserProvider(amplitudeInstanceName?: string): Promise { return ExperimentReactNativeClient.setAmplitudeUserProvider( amplitudeInstanceName diff --git a/src/types.ts b/src/types.ts index b2e4286..be2b99f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -149,7 +149,14 @@ export interface ExperimentConfig { debug?: boolean; /** - * The default fallback variant for all {@link ExperimentClient.variant} + * The name of the instance being initialized. Used for initializing separate + * instances of experiment or linking the experiment SDK to a specific + * instance of the amplitude analytics SDK. + */ + instanceName?: string; + + /** + * The default fallback variant for all {@link variant} * calls. */ fallbackVariant?: Variant; @@ -183,26 +190,54 @@ export interface ExperimentConfig { */ retryFetchOnFailure?: boolean; + /** + * If true, automatically tracks exposure events though the + * `ExperimentAnalyticsProvider`. If no analytics provider is set, this + * option does nothing. + */ + automaticExposureTracking?: boolean; + + /** + * This config only matters if you are using the amplitude analytics SDK + * integration initialized by calling + * `Experiment.initializeWithAmplitudeAnalytics()`. + * + * If true, the client will automatically fetch variants when the + * user's identity changes. The user's identity includes user_id, device_id + * and any user properties which are `set`, `unset` or `clearAll`ed via a call + * to `identify()`. + * + * Note: Non-idempotent identify operations `setOnce`, `add`, `append`, and + * `prepend` are not counted towards the user identity changing. + */ + automaticFetchOnAmplitudeIdentityChange?: boolean; + /** * Name of the amplitude instance to provide user info. + * + * @deprecated Use {@link initializeWithAmplitudeAnalytics} initializer in tandem with the {@link instanceName} config */ amplitudeUserProviderInstanceName?: string; /** * Name of the amplitude instance to provide analytics tracking. + * + * @deprecated Use {@link initializeWithAmplitudeAnalytics} initializer in tandem with the {@link instanceName} config */ amplitudeAnalyticsProviderInstanceName?: string; } export interface ExperimentReactNativeClientModule { initialize(apiKey: string, config?: ExperimentConfig): Promise; + initializeWithAmplitudeAnalytics(apiKey: string, config?: ExperimentConfig): Promise; fetch(user?: ExperimentUser): Promise; setUser(user: ExperimentUser): Promise; variant(key: string): Promise; variantWithFallback(key: string, fallback: Variant): Promise; all(): Promise; + exposure(): Promise; /** - * @deprecated use config.amplitudeUserProviderInstanceName + * @deprecated use {@link initializeWithAmplitudeAnalytics} to integrate with the amplitude analytics sdk. */ setAmplitudeUserProvider(amplitudeInstanceName?: string): Promise; } From b0e7ea1cfdb3020f2df541d1aebead3546c0fe50 Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Wed, 16 Feb 2022 17:30:59 -0800 Subject: [PATCH 3/8] feat: integrated check on ios --- experiment-react-native-client.podspec | 4 ++-- ios/ExperimentReactNativeClient.swift | 21 ++++++++++++--------- src/index.ts | 11 +++++++---- src/types.ts | 5 ++++- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/experiment-react-native-client.podspec b/experiment-react-native-client.podspec index 26cc63f..bcbbdb0 100644 --- a/experiment-react-native-client.podspec +++ b/experiment-react-native-client.podspec @@ -16,6 +16,6 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency "Amplitude", "8.8.0" - s.dependency "AmplitudeExperiment", "1.6.0" + s.dependency "Amplitude", "~> 8.8.0" + s.dependency "AmplitudeExperiment", "~> 1.6.0" end diff --git a/ios/ExperimentReactNativeClient.swift b/ios/ExperimentReactNativeClient.swift index f49eae9..32bf227 100644 --- a/ios/ExperimentReactNativeClient.swift +++ b/ios/ExperimentReactNativeClient.swift @@ -158,16 +158,19 @@ class ExperimentReactNativeClient: NSObject { } // Deprecated - if let val = config?["amplitudeUserProviderInstanceName"] as! String? { - let amplitudeInstance = Amplitude.instance(withName: val) - let userProvider = AmplitudeUserProvider(amplitudeInstance) - let _ = builder.userProvider(userProvider) - } - if let val = config?["amplitudeAnalyticsProviderInstanceName"] as! String? { - let amplitudeInstance = Amplitude.instance(withName: val) - let analyticsProvider = AmplitudeAnalyticsProvider(amplitudeInstance) - let _ = builder.analyticsProvider(analyticsProvider) + if !integrated { + if let val = config?["amplitudeUserProviderInstanceName"] as! String? { + let amplitudeInstance = Amplitude.instance(withName: val) + let userProvider = AmplitudeUserProvider(amplitudeInstance) + let _ = builder.userProvider(userProvider) + } + if let val = config?["amplitudeAnalyticsProviderInstanceName"] as! String? { + let amplitudeInstance = Amplitude.instance(withName: val) + let analyticsProvider = AmplitudeAnalyticsProvider(amplitudeInstance) + let _ = builder.analyticsProvider(analyticsProvider) + } } + return builder.build() } diff --git a/src/index.ts b/src/index.ts index f6d3296..199f0be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,10 +28,13 @@ export const Experiment = { }, initializeWithAmplitudeAnalytics: async ( - apiKey: string, - config?: ExperimentConfig + apiKey: string, + config?: ExperimentConfig ): Promise => { - return ExperimentReactNativeClient.initializeWithAmplitudeAnalytics(apiKey, config); + return ExperimentReactNativeClient.initializeWithAmplitudeAnalytics( + apiKey, + config + ); }, fetch: async (user?: ExperimentUser): Promise => { @@ -61,7 +64,7 @@ export const Experiment = { }, exposure: async (): Promise => { - return ExperimentReactNativeClient.exposure() + return ExperimentReactNativeClient.exposure(); }, setAmplitudeUserProvider(amplitudeInstanceName?: string): Promise { diff --git a/src/types.ts b/src/types.ts index be2b99f..41933c8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -229,7 +229,10 @@ export interface ExperimentConfig { export interface ExperimentReactNativeClientModule { initialize(apiKey: string, config?: ExperimentConfig): Promise; - initializeWithAmplitudeAnalytics(apiKey: string, config?: ExperimentConfig): Promise; + initializeWithAmplitudeAnalytics( + apiKey: string, + config?: ExperimentConfig + ): Promise; fetch(user?: ExperimentUser): Promise; setUser(user: ExperimentUser): Promise; variant(key: string): Promise; From 379a37769918159fc0de7731e6334f380f6b8f5a Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Wed, 16 Feb 2022 19:31:43 -0800 Subject: [PATCH 4/8] chore: reformat --- .../ExperimentReactNativeClientModule.java | 116 +++++++----------- 1 file changed, 42 insertions(+), 74 deletions(-) diff --git a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java index d51e6bd..07652d9 100644 --- a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java +++ b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java @@ -40,8 +40,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; -@ReactModule(name = ExperimentReactNativeClientModule.NAME) -public class ExperimentReactNativeClientModule extends ReactContextBaseJavaModule { +@ReactModule(name = ExperimentReactNativeClientModule.NAME) public class ExperimentReactNativeClientModule + extends ReactContextBaseJavaModule { public static final String NAME = "ExperimentReactNativeClient"; private static final String TAG = "Experiment"; @@ -54,23 +54,17 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { this.reactContext = reactContext; } - @Override - @NonNull - public String getName() { + @Override @NonNull public String getName() { return NAME; } // Example method // See https://reactnative.dev/docs/native-modules-android - @ReactMethod - public void initialize(String apiKey, ReadableMap config, Promise promise) { + @ReactMethod public void initialize(String apiKey, ReadableMap config, Promise promise) { try { ExperimentConfig convertedConfig = convertConfig(config, false); - experimentClient = Experiment.initialize( - (Application) this.reactContext.getApplicationContext(), - apiKey, - convertedConfig - ); + experimentClient = Experiment.initialize((Application) this.reactContext.getApplicationContext(), apiKey, + convertedConfig); promise.resolve(true); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); @@ -78,15 +72,11 @@ public void initialize(String apiKey, ReadableMap config, Promise promise) { } } - @ReactMethod - public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, Promise promise) { + @ReactMethod public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, Promise promise) { try { ExperimentConfig convertedConfig = convertConfig(config, true); experimentClient = Experiment.initializeWithAmplitudeAnalytics( - (Application) this.reactContext.getApplicationContext(), - apiKey, - convertedConfig - ); + (Application) this.reactContext.getApplicationContext(), apiKey, convertedConfig); promise.resolve(true); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); @@ -94,8 +84,7 @@ public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, } } - @ReactMethod - public void fetch(ReadableMap user, Promise promise) { + @ReactMethod public void fetch(ReadableMap user, Promise promise) { try { ExperimentUser experimentUser = user != null ? convertUser(user) : null; Future future = experimentClient.fetch(experimentUser); @@ -113,8 +102,7 @@ public void fetch(ReadableMap user, Promise promise) { } } - @ReactMethod - public void setUser(ReadableMap user, Promise promise) { + @ReactMethod public void setUser(ReadableMap user, Promise promise) { try { experimentClient.setUser(convertUser(user)); promise.resolve(true); @@ -124,8 +112,7 @@ public void setUser(ReadableMap user, Promise promise) { } } - @ReactMethod - public void variant(String key, Promise promise) { + @ReactMethod public void variant(String key, Promise promise) { try { Variant variant = experimentClient.variant(key, null); promise.resolve(variantToMap(variant)); @@ -135,8 +122,7 @@ public void variant(String key, Promise promise) { } } - @ReactMethod - public void exposure(String flagKey, Promise promise) { + @ReactMethod public void exposure(String flagKey, Promise promise) { try { experimentClient.exposure(flagKey); promise.resolve(true); @@ -146,14 +132,11 @@ public void exposure(String flagKey, Promise promise) { } } - @ReactMethod - public void variantWithFallback(String flagKey, ReadableMap fallback, - Promise promise) { + @ReactMethod public void variantWithFallback(String flagKey, ReadableMap fallback, Promise promise) { try { Variant fallbackVariant = new Variant(null, null); if (fallback != null) { - fallbackVariant = new Variant(safeGetString(fallback, "value"), - safeGetObject(fallback, "payload")); + fallbackVariant = new Variant(safeGetString(fallback, "value"), safeGetObject(fallback, "payload")); } Variant variant = experimentClient.variant(flagKey, fallbackVariant); promise.resolve(variantToMap(variant)); @@ -163,8 +146,7 @@ public void variantWithFallback(String flagKey, ReadableMap fallback, } } - @ReactMethod - public void all(Promise promise) { + @ReactMethod public void all(Promise promise) { try { WritableMap map = new WritableNativeMap(); Map variants = experimentClient.all(); @@ -178,8 +160,7 @@ public void all(Promise promise) { } } - @ReactMethod - public void setAmplitudeUserProvider(String amplitudeInstanceName, Promise promise) { + @ReactMethod public void setAmplitudeUserProvider(String amplitudeInstanceName, Promise promise) { try { AmplitudeClient amplitudeInstance = Amplitude.getInstance(amplitudeInstanceName); if (amplitudeInstance != null) { @@ -206,10 +187,7 @@ private ExperimentConfig convertConfig(ReadableMap config, boolean integrated) { } if (config.hasKey("fallbackVariant")) { ReadableMap map = config.getMap("fallbackVariant"); - Variant fallbackVariant = new Variant( - safeGetString(map, "value"), - safeGetObject(map, "payload") - ); + Variant fallbackVariant = new Variant(safeGetString(map, "value"), safeGetObject(map, "payload")); builder.fallbackVariant(fallbackVariant); } if (config.hasKey("initialVariants")) { @@ -238,47 +216,45 @@ private ExperimentConfig convertConfig(ReadableMap config, boolean integrated) { builder.automaticExposureTracking(config.getBoolean("automaticExposureTracking")); } if (config.hasKey("automaticFetchOnAmplitudeIdentityChange")) { - builder.automaticFetchOnAmplitudeIdentityChange(config.getBoolean("automaticFetchOnAmplitudeIdentityChange")); + builder.automaticFetchOnAmplitudeIdentityChange( + config.getBoolean("automaticFetchOnAmplitudeIdentityChange")); } if (!integrated) { - // Deprecated - if (config.hasKey("amplitudeUserProviderInstanceName")) { - String instanceName = config.getString("amplitudeUserProviderInstanceName"); - AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); - if (amplitudeInstance != null) { - builder.userProvider(new AmplitudeUserProvider(amplitudeInstance)); + // Deprecated + if (config.hasKey("amplitudeUserProviderInstanceName")) { + String instanceName = config.getString("amplitudeUserProviderInstanceName"); + AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); + if (amplitudeInstance != null) { + builder.userProvider(new AmplitudeUserProvider(amplitudeInstance)); + } } - } - if (config.hasKey("amplitudeAnalyticsProviderInstanceName")) { - String instanceName = config.getString("amplitudeAnalyticsProviderInstanceName"); - AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); - if (amplitudeInstance != null) { - builder.analyticsProvider(new AmplitudeAnalyticsProvider(amplitudeInstance)); + if (config.hasKey("amplitudeAnalyticsProviderInstanceName")) { + String instanceName = config.getString("amplitudeAnalyticsProviderInstanceName"); + AmplitudeClient amplitudeInstance = Amplitude.getInstance(instanceName); + if (amplitudeInstance != null) { + builder.analyticsProvider(new AmplitudeAnalyticsProvider(amplitudeInstance)); + } } - } } return builder.build(); } - @Nullable - private String safeGetString(ReadableMap map, String key) { + @Nullable private String safeGetString(ReadableMap map, String key) { if (map.hasKey(key)) { return map.getString(key); } return null; } - @Nullable - private Map safeGetMap(ReadableMap map, String key) { + @Nullable private Map safeGetMap(ReadableMap map, String key) { if (map.hasKey(key)) { return map.getMap(key).toHashMap(); } return null; } - @Nullable - private Object safeGetObject(ReadableMap map, String key) { + @Nullable private Object safeGetObject(ReadableMap map, String key) { if (map.hasKey(key)) { return ReactNativeHelper.toMap(map).get(key); } @@ -322,22 +298,14 @@ private ExperimentUser convertUser(ReadableMap user) { return null; } ExperimentUser.Builder builder = ExperimentUser.builder(); - builder.deviceId(safeGetString(user, "device_id")) - .userId(safeGetString(user, "user_id")) - .version(safeGetString(user, "version")) - .country(safeGetString(user, "country")) - .region(safeGetString(user, "region")) - .dma(safeGetString(user, "dma")) - .city(safeGetString(user, "city")) - .language(safeGetString(user, "language")) - .platform(safeGetString(user, "platform")) - .os(safeGetString(user, "os")) - .deviceBrand(safeGetString(user, "device_brand")) + builder.deviceId(safeGetString(user, "device_id")).userId(safeGetString(user, "user_id")) + .version(safeGetString(user, "version")).country(safeGetString(user, "country")) + .region(safeGetString(user, "region")).dma(safeGetString(user, "dma")).city(safeGetString(user, "city")) + .language(safeGetString(user, "language")).platform(safeGetString(user, "platform")) + .os(safeGetString(user, "os")).deviceBrand(safeGetString(user, "device_brand")) .deviceManufacturer(safeGetString(user, "device_manufacturer")) - .deviceModel(safeGetString(user, "device_model")) - .carrier(safeGetString(user, "carrier")) - .library(safeGetString(user, "library")) - .userProperties(safeGetMap(user, "user_properties")); + .deviceModel(safeGetString(user, "device_model")).carrier(safeGetString(user, "carrier")) + .library(safeGetString(user, "library")).userProperties(safeGetMap(user, "user_properties")); return builder.build(); } } From 0144aac55dfe33bc61c9979207b70e5efaa3ee6b Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Sat, 19 Feb 2022 09:07:48 -0800 Subject: [PATCH 5/8] fix: update example, fix ios init --- example/ios/Podfile.lock | 10 +++++----- example/package.json | 2 +- example/src/App.tsx | 19 ++++++------------- example/yarn.lock | 8 ++++---- ios/ExperimentReactNativeClient.m | 2 ++ 5 files changed, 18 insertions(+), 23 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 3ae3678..8ac1224 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,7 +1,7 @@ PODS: - Amplitude (8.8.0): - AnalyticsConnector (~> 1.0.0) - - amplitude-react-native (2.6.0): + - amplitude-react-native (2.8.0): - Amplitude (= 8.8.0) - React-Core - AmplitudeExperiment (1.6.0): @@ -11,8 +11,8 @@ PODS: - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - experiment-react-native-client (0.5.2): - - Amplitude (= 8.8.0) - - AmplitudeExperiment (= 1.6.0) + - Amplitude (~> 8.8.0) + - AmplitudeExperiment (~> 1.6.0) - React-Core - FBLazyVector (0.63.3) - FBReactNativeSpec (0.63.3): @@ -450,13 +450,13 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Amplitude: 710116f3539c225e86fb70a8abdcd20015683132 - amplitude-react-native: cb93e8a7d8ac80e359b40185976a27f1dcab65e9 + amplitude-react-native: acb8a0659b3f713185457f18642a8feb77652b4c AmplitudeExperiment: 2ae761f52e7d7d15f9516bcf796a06d0c57e97b8 AnalyticsConnector: 4c386d5972ac9da86e22d668564dbbac97558754 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: cde416483dac037923206447da6e1454df403714 - experiment-react-native-client: 9c14d0087aa28140fe038ded1406c47a49a958af + experiment-react-native-client: aa18cd70fa8b71d174733e2d091a4dfd5eba9f23 FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f Flipper: 1bd2db48dcc31e4b167b9a33ec1df01c2ded4893 diff --git a/example/package.json b/example/package.json index 574c16a..662f98a 100644 --- a/example/package.json +++ b/example/package.json @@ -9,7 +9,7 @@ "start": "react-native start" }, "dependencies": { - "@amplitude/react-native": "^2.1.2", + "@amplitude/react-native": "2.8.0", "react": "16.13.1", "react-native": "0.63.3" }, diff --git a/example/src/App.tsx b/example/src/App.tsx index 0ef7d6a..9eef6ab 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { StyleSheet, View, Text } from 'react-native'; -import { Amplitude } from '@amplitude/react-native'; +import { Amplitude, Identify } from '@amplitude/react-native'; import { Experiment, Variant, @@ -22,27 +22,20 @@ export default function App() { const [allVariants, setAllVariants] = React.useState(); React.useEffect(() => { (async () => { - let amplitudeInstanceName; if (Amplitude) { - const amplitude = Amplitude.getInstance(); - amplitude.init('a6dd847b9d2f03c816d4f3f8458cdc1d'); - amplitudeInstanceName = amplitude.instanceName; + await Amplitude.getInstance().init('a6dd847b9d2f03c816d4f3f8458cdc1d'); + await Amplitude.getInstance().setUserId("brian.giori@amplitude.com") } if (Experiment) { - await Experiment.initialize('client-IAxMYws9vVQESrrK88aTcToyqMxiiJoR', { + await Experiment.initializeWithAmplitudeAnalytics('client-IAxMYws9vVQESrrK88aTcToyqMxiiJoR', { debug: true, fallbackVariant: { value: 'defaultFallback' }, - initialVariants: { - 'flag-does-not-exist': { - value: 'asdf', - }, - }, - amplitudeUserProviderInstanceName: amplitudeInstanceName, - amplitudeAnalyticsProviderInstanceName: amplitudeInstanceName, + automaticExposureTracking: true, }); await Experiment.fetch({ user_properties: { test: 'true', test2: 4.3 }, }); + setVariant(await Experiment.variant('react-native')); setFallbackResult(await Experiment.variant('flag-does-not-exist')); setVariantFallbackResult( diff --git a/example/yarn.lock b/example/yarn.lock index 2b65669..cc26eac 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@amplitude/react-native@^2.1.2": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@amplitude/react-native/-/react-native-2.6.0.tgz#9bde1e4a7e684f949c5cd8e1067ea4006e654c29" - integrity sha512-AIEN8zfgmjvG9IaWgQFQE2XkijtvLRxns9jFQrO5GKA7DLw3z+PvCnY2g4TcAMOftH2+Sp6zpItE2RS38y/4bQ== +"@amplitude/react-native@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@amplitude/react-native/-/react-native-2.8.0.tgz#f4d08f84c9662761f2f3af8dc35080240229a1b7" + integrity sha512-Stw61MwcX7BoFwJisfqEauaNCk0kxS/Co0V3MkD6QLXkKjqwESaLmJiKP+ZqcvBDbb/3uU4h1HxF1HuTn0+/WQ== "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0": version "7.16.0" diff --git a/ios/ExperimentReactNativeClient.m b/ios/ExperimentReactNativeClient.m index dab392c..c17c642 100644 --- a/ios/ExperimentReactNativeClient.m +++ b/ios/ExperimentReactNativeClient.m @@ -4,6 +4,8 @@ @interface RCT_EXTERN_MODULE(ExperimentReactNativeClient, NSObject) RCT_EXTERN_METHOD(initialize:(NSString *)apiKey config:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(initializeWithAmplitudeAnalytics:(NSString *)apiKey config:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(fetch:(NSDictionary *)user resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(setUser:(NSDictionary *)user resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) From 48c0fb6f7c6df900a64814b57d3bda11f97736b9 Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Sat, 19 Feb 2022 09:08:11 -0800 Subject: [PATCH 6/8] fix: style --- example/src/App.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index 9eef6ab..976f4a3 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { StyleSheet, View, Text } from 'react-native'; -import { Amplitude, Identify } from '@amplitude/react-native'; +import { Amplitude } from '@amplitude/react-native'; import { Experiment, Variant, @@ -24,14 +24,17 @@ export default function App() { (async () => { if (Amplitude) { await Amplitude.getInstance().init('a6dd847b9d2f03c816d4f3f8458cdc1d'); - await Amplitude.getInstance().setUserId("brian.giori@amplitude.com") + await Amplitude.getInstance().setUserId('brian.giori@amplitude.com'); } if (Experiment) { - await Experiment.initializeWithAmplitudeAnalytics('client-IAxMYws9vVQESrrK88aTcToyqMxiiJoR', { - debug: true, - fallbackVariant: { value: 'defaultFallback' }, - automaticExposureTracking: true, - }); + await Experiment.initializeWithAmplitudeAnalytics( + 'client-IAxMYws9vVQESrrK88aTcToyqMxiiJoR', + { + debug: true, + fallbackVariant: { value: 'defaultFallback' }, + automaticExposureTracking: true, + } + ); await Experiment.fetch({ user_properties: { test: 'true', test2: 4.3 }, }); From c24916dc31f84709fe5a4b03dee457cbee6be61a Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Sat, 19 Feb 2022 09:23:28 -0800 Subject: [PATCH 7/8] fix: explicit exposure --- .../reactnative/ExperimentReactNativeClientModule.java | 4 ++-- example/src/App.tsx | 2 -- ios/ExperimentReactNativeClient.m | 2 ++ ios/ExperimentReactNativeClient.swift | 4 ++-- src/index.ts | 4 ++-- src/types.ts | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java index 07652d9..de63464 100644 --- a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java +++ b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java @@ -122,9 +122,9 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void exposure(String flagKey, Promise promise) { + @ReactMethod public void exposure(String key, Promise promise) { try { - experimentClient.exposure(flagKey); + experimentClient.exposure(key); promise.resolve(true); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); diff --git a/example/src/App.tsx b/example/src/App.tsx index 976f4a3..7c67db2 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -32,13 +32,11 @@ export default function App() { { debug: true, fallbackVariant: { value: 'defaultFallback' }, - automaticExposureTracking: true, } ); await Experiment.fetch({ user_properties: { test: 'true', test2: 4.3 }, }); - setVariant(await Experiment.variant('react-native')); setFallbackResult(await Experiment.variant('flag-does-not-exist')); setVariantFallbackResult( diff --git a/ios/ExperimentReactNativeClient.m b/ios/ExperimentReactNativeClient.m index c17c642..203e8a7 100644 --- a/ios/ExperimentReactNativeClient.m +++ b/ios/ExperimentReactNativeClient.m @@ -12,6 +12,8 @@ @interface RCT_EXTERN_MODULE(ExperimentReactNativeClient, NSObject) RCT_EXTERN_METHOD(variant:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(exposure:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(variantWithFallback:(NSString *)key fallback:(NSDictionary *)fallback resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(all: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) diff --git a/ios/ExperimentReactNativeClient.swift b/ios/ExperimentReactNativeClient.swift index 32bf227..f64abaf 100644 --- a/ios/ExperimentReactNativeClient.swift +++ b/ios/ExperimentReactNativeClient.swift @@ -224,11 +224,11 @@ class ExperimentReactNativeClient: NSObject { @objc func exposure( - _ flagKey: String, + _ key: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) -> Void { - experimentClient?.exposure(key: flagKey) + experimentClient?.exposure(key: key) resolve(true) } diff --git a/src/index.ts b/src/index.ts index 199f0be..65c5bb1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,8 +63,8 @@ export const Experiment = { return ExperimentReactNativeClient.all(); }, - exposure: async (): Promise => { - return ExperimentReactNativeClient.exposure(); + exposure: async (key: string): Promise => { + return ExperimentReactNativeClient.exposure(key); }, setAmplitudeUserProvider(amplitudeInstanceName?: string): Promise { diff --git a/src/types.ts b/src/types.ts index 41933c8..c1d031e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -238,7 +238,7 @@ export interface ExperimentReactNativeClientModule { variant(key: string): Promise; variantWithFallback(key: string, fallback: Variant): Promise; all(): Promise; - exposure(): Promise; + exposure(key: string): Promise; /** * @deprecated use {@link initializeWithAmplitudeAnalytics} to integrate with the amplitude analytics sdk. */ From f6d5672aaf711cb09bf4de0581b1629c2ba1689a Mon Sep 17 00:00:00 2001 From: Brian Giori Date: Sat, 19 Feb 2022 09:33:49 -0800 Subject: [PATCH 8/8] fix: revert format on java mod --- .../ExperimentReactNativeClientModule.java | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java index de63464..b5de6a6 100644 --- a/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java +++ b/android/src/main/java/com/amplitude/experiment/reactnative/ExperimentReactNativeClientModule.java @@ -40,8 +40,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; -@ReactModule(name = ExperimentReactNativeClientModule.NAME) public class ExperimentReactNativeClientModule - extends ReactContextBaseJavaModule { +@ReactModule(name = ExperimentReactNativeClientModule.NAME) +public class ExperimentReactNativeClientModule extends ReactContextBaseJavaModule { public static final String NAME = "ExperimentReactNativeClient"; private static final String TAG = "Experiment"; @@ -54,13 +54,16 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { this.reactContext = reactContext; } - @Override @NonNull public String getName() { + @Override + @NonNull + public String getName() { return NAME; } // Example method // See https://reactnative.dev/docs/native-modules-android - @ReactMethod public void initialize(String apiKey, ReadableMap config, Promise promise) { + @ReactMethod + public void initialize(String apiKey, ReadableMap config, Promise promise) { try { ExperimentConfig convertedConfig = convertConfig(config, false); experimentClient = Experiment.initialize((Application) this.reactContext.getApplicationContext(), apiKey, @@ -72,7 +75,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, Promise promise) { + @ReactMethod + public void initializeWithAmplitudeAnalytics(String apiKey, ReadableMap config, Promise promise) { try { ExperimentConfig convertedConfig = convertConfig(config, true); experimentClient = Experiment.initializeWithAmplitudeAnalytics( @@ -84,7 +88,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void fetch(ReadableMap user, Promise promise) { + @ReactMethod + public void fetch(ReadableMap user, Promise promise) { try { ExperimentUser experimentUser = user != null ? convertUser(user) : null; Future future = experimentClient.fetch(experimentUser); @@ -102,7 +107,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void setUser(ReadableMap user, Promise promise) { + @ReactMethod + public void setUser(ReadableMap user, Promise promise) { try { experimentClient.setUser(convertUser(user)); promise.resolve(true); @@ -112,7 +118,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void variant(String key, Promise promise) { + @ReactMethod + public void variant(String key, Promise promise) { try { Variant variant = experimentClient.variant(key, null); promise.resolve(variantToMap(variant)); @@ -122,7 +129,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void exposure(String key, Promise promise) { + @ReactMethod + public void exposure(String key, Promise promise) { try { experimentClient.exposure(key); promise.resolve(true); @@ -132,7 +140,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void variantWithFallback(String flagKey, ReadableMap fallback, Promise promise) { + @ReactMethod + public void variantWithFallback(String flagKey, ReadableMap fallback, Promise promise) { try { Variant fallbackVariant = new Variant(null, null); if (fallback != null) { @@ -146,7 +155,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void all(Promise promise) { + @ReactMethod + public void all(Promise promise) { try { WritableMap map = new WritableNativeMap(); Map variants = experimentClient.all(); @@ -160,7 +170,8 @@ public ExperimentReactNativeClientModule(ReactApplicationContext reactContext) { } } - @ReactMethod public void setAmplitudeUserProvider(String amplitudeInstanceName, Promise promise) { + @ReactMethod + public void setAmplitudeUserProvider(String amplitudeInstanceName, Promise promise) { try { AmplitudeClient amplitudeInstance = Amplitude.getInstance(amplitudeInstanceName); if (amplitudeInstance != null) { @@ -240,21 +251,24 @@ private ExperimentConfig convertConfig(ReadableMap config, boolean integrated) { return builder.build(); } - @Nullable private String safeGetString(ReadableMap map, String key) { + @Nullable + private String safeGetString(ReadableMap map, String key) { if (map.hasKey(key)) { return map.getString(key); } return null; } - @Nullable private Map safeGetMap(ReadableMap map, String key) { + @Nullable + private Map safeGetMap(ReadableMap map, String key) { if (map.hasKey(key)) { return map.getMap(key).toHashMap(); } return null; } - @Nullable private Object safeGetObject(ReadableMap map, String key) { + @Nullable + private Object safeGetObject(ReadableMap map, String key) { if (map.hasKey(key)) { return ReactNativeHelper.toMap(map).get(key); }