Skip to content

Commit

Permalink
TAP-5070: Minor bug fixed after project cleanup (#14)
Browse files Browse the repository at this point in the history
* Refactored SDK to be more modular

* Removed TaplyticsProvider imports

* Removed unused and undocumented native methods

* Added _newSessionCallback native method and exported it as part of `setTaplyticsNewSessionListener` method

* Changed newSyncObject to take in NSDictionary

* Added getVariables and registerVaraiblesChangedListener methods and removed lodash and only added lodash.clonedeep

* Add library to gitignore and prettierignore

* Added extra line on ignore files

* Added push method types and cleaned up the push methods

* Removed old index files and added push types to index

* Fixed typo in console.error

* Fixed a bug caused by the event listeners not being initialized before they are triggered

* Export getRunningExperimentsAndVariations

* Reformatted android module, and fixed crash for newSyncObject
  • Loading branch information
hamzahayat authored Mar 25, 2021
1 parent d29d280 commit d2f04d5
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 50 deletions.
27 changes: 11 additions & 16 deletions android/src/main/java/com/taplytics/react/TaplyticsReactModule.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

package com.taplytics.react;

import androidx.annotation.Nullable;

import android.util.Log;

import androidx.annotation.Nullable;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.Arguments;
Expand All @@ -21,16 +20,13 @@
import com.taplytics.sdk.CodeBlockListener;
import com.taplytics.sdk.SessionInfoRetrievedListener;
import com.taplytics.sdk.Taplytics;
import com.taplytics.sdk.TaplyticsExperimentsUpdatedListener;
import com.taplytics.sdk.TaplyticsNewSessionListener;
import com.taplytics.sdk.TaplyticsPushSubscriptionChangedListener;
import com.taplytics.sdk.TaplyticsPushTokenListener;
import com.taplytics.sdk.TaplyticsResetUserListener;
import com.taplytics.sdk.TaplyticsRunningExperimentsListener;
import com.taplytics.sdk.TaplyticsRunningFeatureFlagsListener;
import com.taplytics.sdk.TaplyticsSetUserAttributesListener;
import com.taplytics.sdk.TaplyticsVar;
import com.taplytics.sdk.TaplyticsVarListener;
import com.taplytics.sdk.TaplyticsSetUserAttributesListener;

import org.json.JSONException;
import org.json.JSONObject;
Expand All @@ -45,12 +41,12 @@

public class TaplyticsReactModule extends ReactContextBaseJavaModule implements ReactInstanceManager.ReactInstanceEventListener {

private final ReactApplicationContext reactContext;
private static TaplyticsReactModule instance;
private static final String LOG_TAG_NAME = "TaplyticsReact";
private static final String EVENT_VALUE_NAME = "value";
private static final String ASYNC_VARIABLE_EVENT_VALUE_ID = "id";
private static final String ASYNC_VARIABLE_EVENT_NAME = "asyncVariable";
private static TaplyticsReactModule instance;
private final ReactApplicationContext reactContext;

public TaplyticsReactModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand All @@ -59,6 +55,10 @@ public TaplyticsReactModule(ReactApplicationContext reactContext) {
setupReactListener(reactContext);
}

static TaplyticsReactModule getInstance() {
return TaplyticsReactModule.instance;
}

private void setupReactListener(ReactApplicationContext reactContext) {
try {
if (reactContext.getApplicationContext() instanceof ReactApplication) {
Expand All @@ -70,7 +70,6 @@ private void setupReactListener(ReactApplicationContext reactContext) {
}
}


@Override
public String getName() {
return "Taplytics";
Expand All @@ -80,10 +79,6 @@ void sendEvent(String eventName, @Nullable WritableMap params) {
this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
}

static TaplyticsReactModule getInstance() {
return TaplyticsReactModule.instance;
}

@ReactMethod
public void _newSyncString(String name, String defaultValue, Promise callback) {
TaplyticsVar var = new TaplyticsVar<>(name, defaultValue);
Expand All @@ -100,7 +95,7 @@ public void _newSyncBool(String name, Boolean defaultValue, Promise callback) {
public void _newSyncObject(String name, ReadableMap defaultValue, Promise callback) {
try {
TaplyticsVar var = new TaplyticsVar<>(name, convertMapToJson(defaultValue));
callback.resolve(var.get());
callback.resolve(convertJsonToMap((JSONObject) var.get()));
} catch (JSONException e) {
callback.reject(LOG_TAG_NAME, e.getMessage());
}
Expand Down Expand Up @@ -169,7 +164,7 @@ public void _newAsyncObject(final String name, ReadableMap defaultValue, final I
public void variableUpdated(Object o) {
WritableMap params = Arguments.createMap();
try {
params.putMap(EVENT_VALUE_NAME, convertJsonToMap((JSONObject) o));
params.putMap(EVENT_VALUE_NAME, convertJsonToMap((JSONObject) o));
} catch (JSONException e) {
Log.e(LOG_TAG_NAME, e.getMessage());
}
Expand Down
50 changes: 30 additions & 20 deletions src/experiments/experiments.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EventSubscription, NativeEventEmitter, NativeModules } from 'react-native'
import cloneDeep from 'lodash.clonedeep'

import { CodeBlockCallback, PropertiesLoadedCallback, TaplyticsFeatureFlags, TaplyticsExperiments, TaplyticsVariables } from './experiments.types'
import { CodeBlockCallback, PropertiesLoadedCallback, TaplyticsFeatureFlags, TaplyticsExperiments, TaplyticsVariableMap } from './experiments.types'

const { Taplytics } = NativeModules
const TaplyticsEventEmitter = new NativeEventEmitter(Taplytics)
Expand Down Expand Up @@ -80,14 +80,14 @@ export const getRunningExperimentsAndVariations = (): Promise<TaplyticsExperimen
* The method that gets invoked whenever a experiment variables' value is updated.
*
*/
let variablesChangedListener: (variables: TaplyticsVariables) => void | Promise<void>
let variablesChangedListener: (variables: TaplyticsVariableMap) => void | Promise<void>

/**
* Use this function to register a listener for whenever an experiments' variable value is changed.
*
* @param listener The method that is invoked whenever an experiments' variable is updated.
*/
export const registerVariablesChangedListener = (listener: (variables: TaplyticsVariables) => void | Promise<void>) => {
export const registerVariablesChangedListener = (listener: (variables: TaplyticsVariableMap) => void | Promise<void>) => {
variablesChangedListener = listener
}

Expand All @@ -96,7 +96,7 @@ export const registerVariablesChangedListener = (listener: (variables: Taplytics
* and `newAsyncVariable`. It is then utilized by the listener passed into `registerVariablesChangedListener`
* and by `getVariables`.
*/
const dynamicVariables: TaplyticsVariables = {}
const dynamicVariables: TaplyticsVariableMap = {}

/**
* This method updates the `dynamicVariable` object, as well as invokes the method passed into
Expand All @@ -112,7 +112,7 @@ const updateDynamicVariables = (name: string, value: string | boolean | object |
dynamicVariables[name] = value

// Trigger listener
variablesChangedListener && variablesChangedListener(cloneDeep<TaplyticsVariables>(dynamicVariables))
variablesChangedListener && variablesChangedListener(cloneDeep<TaplyticsVariableMap>(dynamicVariables))
}

/**
Expand All @@ -121,7 +121,7 @@ const updateDynamicVariables = (name: string, value: string | boolean | object |
*
* @returns An object that holds the key's and values of the experiment variables.
*/
export const getVariables = (): TaplyticsVariables => cloneDeep<TaplyticsVariables>(dynamicVariables)
export const getVariables = (): TaplyticsVariableMap => cloneDeep<TaplyticsVariableMap>(dynamicVariables)

/**
* A Map of callbacks used by the `newAsyncVariable` funciton to keep track of
Expand All @@ -132,7 +132,9 @@ export const getVariables = (): TaplyticsVariables => cloneDeep<TaplyticsVariabl
const asyncVariableCallbackMap = new Map<number, (variable: any) => void>()

/**
* A ID that is used as the key to the `asyncVariableCallbackMap` Map.
* A ID that is used to track each invokation of the `newAsyncVariable` method.
* This ID is passed to the native layer, and eventually passed back whenever the
* `asyncVariable` event is triggered.
*/
let asyncVariableCallbackID = 0

Expand All @@ -149,12 +151,29 @@ let asyncVariableCallbackID = 0
*
* @returns An event subscriber object is returned. Use the `remove` function to clean up the event listener.
*/
export const newAsyncVariable = <T>(name: string, defaultValue: T, callback: (variable: T) => void): EventSubscription => {
const nativeModuleArgs = [name, defaultValue, asyncVariableCallbackID]

asyncVariableCallbackMap.set(asyncVariableCallbackID, callback)
export const newAsyncVariable = <T>(name: string, defaultValue: T, callback: (variable: T) => void) => {
// Increment the ID
asyncVariableCallbackID++

/**
* Store a locally scoped reference to the ID that the listener
* utilizes to check against it's argument's ID. This is done to ensure
* that only the intended callback is triggered.
*/
const localScopeID = asyncVariableCallbackID

const subscriber = TaplyticsEventEmitter.addListener('asyncVariable', ({ id, value }) => {
if (localScopeID !== id) return

// Trigger the callback
callback(value)

// Update the dynamic variables used by `getVariables`
updateDynamicVariables(name, value)
})

const nativeModuleArgs = [name, defaultValue, asyncVariableCallbackID]

switch (typeof defaultValue) {
case 'boolean':
Taplytics._newAsyncBool(...nativeModuleArgs)
Expand All @@ -173,15 +192,6 @@ export const newAsyncVariable = <T>(name: string, defaultValue: T, callback: (va
break
}

const subscriber = TaplyticsEventEmitter.addListener('asyncVariable', ({ id, value }) => {
// Trigger the callback
const variableCallback = asyncVariableCallbackMap.get(id)
variableCallback && variableCallback(value)

// Update the dynamic variables used by `getVariables`
updateDynamicVariables(name, value)
})

return subscriber
}

Expand Down
6 changes: 4 additions & 2 deletions src/experiments/experiments.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export type TaplyticsFeatureFlags = {
[key: string]: string
}

export type TaplyticsVariables = {
[key: string]: boolean | string | object | number
export type TaplyticsVariable = boolean | string | object | number

export type TaplyticsVariableMap = {
[key: string]: TaplyticsVariable
}
14 changes: 12 additions & 2 deletions src/experiments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,33 @@ import {
getRunningFeatureFlags,
getVariables,
newAsyncVariable,
newSyncVariable,
propertiesLoadedCallback,
registerVariablesChangedListener,
runCodeBlock,
} from './experiments'
import { CodeBlockCallback, PropertiesLoadedCallback, TaplyticsExperiments, TaplyticsFeatureFlags, TaplyticsVariables } from './experiments.types'
import {
CodeBlockCallback,
PropertiesLoadedCallback,
TaplyticsExperiments,
TaplyticsFeatureFlags,
TaplyticsVariable,
TaplyticsVariableMap,
} from './experiments.types'

export {
CodeBlockCallback,
PropertiesLoadedCallback,
TaplyticsExperiments,
TaplyticsFeatureFlags,
TaplyticsVariables,
TaplyticsVariable,
TaplyticsVariableMap,
featureFlagEnabled,
getRunningExperimentsAndVariations,
getRunningFeatureFlags,
getVariables,
newAsyncVariable,
newSyncVariable,
propertiesLoadedCallback,
registerVariablesChangedListener,
runCodeBlock,
Expand Down
10 changes: 8 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import {
featureFlagEnabled,
getRunningExperimentsAndVariations,
getRunningFeatureFlags,
getVariables,
newAsyncVariable,
newSyncVariable,
propertiesLoadedCallback,
registerVariablesChangedListener,
runCodeBlock,
TaplyticsExperiments,
TaplyticsFeatureFlags,
TaplyticsVariables,
TaplyticsVariable,
TaplyticsVariableMap,
} from './experiments'
import { logEvent, resetAppUser, setTaplyticsNewSessionListener, setUserAttributes, startNewSession, TaplyticsUserAttributes } from './user'
import {
Expand All @@ -26,12 +29,15 @@ export {
TaplyticsFeatureFlags,
TaplyticsiOSNotification,
TaplyticsUserAttributes,
TaplyticsVariables,
TaplyticsVariable,
TaplyticsVariableMap,
featureFlagEnabled,
getRunningExperimentsAndVariations,
getRunningFeatureFlags,
getVariables,
logEvent,
newAsyncVariable,
newSyncVariable,
propertiesLoadedCallback,
registerPushDismissedListener,
registerPushNotifications,
Expand Down
16 changes: 8 additions & 8 deletions src/push/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ export const registerPushNotifications = () => {
* @returns An event subscriber object is returned. Use the `remove` function to clean up the event listener.
*/
export const registerPushReceivedListener = (listener: TaplyticsNotificationListener): EventSubscription => {
if (Platform.OS === 'ios') {
Taplytics._registerPushReceivedListener()
}

const subscriber = TaplyticsEventEmitter.addListener('pushReceived', (notification) => {
if (Platform.OS === 'android') {
listener(notification?.value as TaplyticsAndroidNotification)
Expand All @@ -38,6 +34,10 @@ export const registerPushReceivedListener = (listener: TaplyticsNotificationList
}
})

if (Platform.OS === 'ios') {
Taplytics._registerPushReceivedListener()
}

return subscriber
}

Expand All @@ -51,10 +51,6 @@ export const registerPushReceivedListener = (listener: TaplyticsNotificationList
* @returns An event subscriber object is returned. Use the `remove` function to clean up the event listener.
*/
export const registerPushOpenedListener = (listener: TaplyticsNotificationListener): EventSubscription => {
if (Platform.OS === 'ios') {
Taplytics._registerPushOpenedListener()
}

const subscriber = TaplyticsEventEmitter.addListener('pushOpened', (notification) => {
if (Platform.OS === 'android') {
listener(notification?.value as TaplyticsAndroidNotification)
Expand All @@ -65,6 +61,10 @@ export const registerPushOpenedListener = (listener: TaplyticsNotificationListen
}
})

if (Platform.OS === 'ios') {
Taplytics._registerPushOpenedListener()
}

return subscriber
}

Expand Down

0 comments on commit d2f04d5

Please sign in to comment.