Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Commit

Permalink
prepare 6.1.0 release (#119)
Browse files Browse the repository at this point in the history
### Added:
- Added `privateAttributeNames` configuration option for `LDConfig` allowing the configuration of private attributes for all users. ([#102](#102))

### Fixed:
- Android: Updated Android SDK dependency to [3.1.3](https://github.com/launchdarkly/android-client-sdk/releases/tag/3.1.3).
- Android: Added missing native module API stubs to prevent warning on `NativeEventEmitter`. ([#116](#116))
- iOS: Fixed ownership handling of native callbacks to avoid garbage collection of all flags and connection mode listeners that are still in use. ([#106](#106))
  • Loading branch information
LaunchDarklyReleaseBot authored Feb 26, 2022
1 parent ecc0cfe commit 171192e
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ workflows:
name: rn<<matrix.rn-version>>-xc<<matrix.xcode-version>>-build-apps-using-template
matrix:
parameters:
rn-version: ["0.64.3", "0.65.2", "0.66.4", "0.67.2"]
rn-version: ["0.64.3", "0.65.2", "0.66.4", "0.67.3"]
xcode-version: ["12.2.0", "12.5.1", "13.2.1"]
requires:
- test-javascript
2 changes: 1 addition & 1 deletion ManualTestApp/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
## Manual testing application

Add your mobile key in `App.js`, `npx pod-install`, `yarn run <android|ios>`.
Add your mobile key in `App.js`, `npx yarn install`, `npx pod-install`, `npx yarn run <android|ios>`.
2 changes: 1 addition & 1 deletion ManualTestApp/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3137,7 +3137,7 @@ kleur@^3.0.3:
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==

"launchdarkly-react-native-client-sdk@file:..":
version "5.1.1"
version "6.0.0"

leven@^3.1.0:
version "3.1.0"
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ allprojects {

dependencies {
implementation("com.facebook.react:react-native:+")
implementation("com.launchdarkly:launchdarkly-android-client-sdk:3.1.2")
implementation("com.launchdarkly:launchdarkly-android-client-sdk:3.1.3")
implementation("com.jakewharton.timber:timber:5.0.1")
implementation("com.google.code.gson:gson:2.8.9")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ public Map<String, Object> getConstants() {
return constants;
}

@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
}

@ReactMethod
public void removeListeners(Integer count) {
// Keep: Required for RN built in Event Emitter Calls.
}

@ReactMethod
public void configure(ReadableMap config, ReadableMap user, final Promise promise) {
internalConfigure(config, user, null, promise);
Expand Down
8 changes: 8 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ declare module 'launchdarkly-react-native-client-sdk' {
* that provides the full details for the user.
*/
inlineUsersInEvents?: boolean;

/**
* The names of user attributes that should be marked as private, and not sent to
* LaunchDarkly in analytics events.
*
* You can also specify this on a per-user basis with [[LDUser.privateAttributeNames]].
*/
privateAttributeNames?: string[]
};

/**
Expand Down
54 changes: 31 additions & 23 deletions ios/LaunchdarklyReactNativeClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import LaunchDarkly

@objc(LaunchdarklyReactNativeClient)
class LaunchdarklyReactNativeClient: RCTEventEmitter {
private var listenerKeys: [String:LDObserverOwner] = [:]

private let FLAG_PREFIX = "LaunchDarkly-Flag-"
private let ALL_FLAGS_PREFIX = "LaunchDarkly-All-Flags-"
private let CONNECTION_MODE_PREFIX = "LaunchDarkly-Connection-Mode-"
private let ERROR_INIT = "E_INITIALIZE"
private let ERROR_IDENTIFY = "E_IDENTIFY"
private let ERROR_UNKNOWN = "E_UNKNOWN"


private var flagListenerOwners: [String: ObserverOwner] = [:]
private var allFlagsListenerOwners: [String: ObserverOwner] = [:]
private var connectionModeListenerOwners: [String: ObserverOwner] = [:]

override func supportedEvents() -> [String]! {
return [FLAG_PREFIX, ALL_FLAGS_PREFIX, CONNECTION_MODE_PREFIX]
}
Expand Down Expand Up @@ -89,6 +91,7 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter {
configField(&ldConfig.allUserAttributesPrivate, config["allUserAttributesPrivate"], id)
configField(&ldConfig.autoAliasingOptOut, config["autoAliasingOptOut"], id)
configField(&ldConfig.inlineUserInEvents, config["inlineUsersInEvents"], id)
configField(&ldConfig.privateUserAttributes, config["privateAttributeNames"], id)

if let val = config["secondaryMobileKeys"] as? [String: String] {
try! ldConfig.setSecondaryMobileKeys(val)
Expand Down Expand Up @@ -382,53 +385,56 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter {

@objc func registerFeatureFlagListener(_ flagKey: String, environment: String) -> Void {
let multiListenerId = envConcat(environment: environment, identifier: flagKey)
let flagChangeOwner = multiListenerId as LDObserverOwner
listenerKeys[multiListenerId] = flagChangeOwner
LDClient.get(environment: environment)!.observe(key: flagKey, owner: flagChangeOwner, handler: { changedFlag in
let owner = ObserverOwner()
flagListenerOwners[multiListenerId] = owner
LDClient.get(environment: environment)!.observe(key: flagKey, owner: owner) { changedFlag in
if self.bridge != nil {
self.sendEvent(withName: self.FLAG_PREFIX, body: ["flagKey": changedFlag.key, "listenerId": multiListenerId])
}
})
}

private func unregisterListener(_ key: String, _ environment: String) -> Void {
let multiListenerId = envConcat(environment: environment, identifier: key)
let owner = multiListenerId as LDObserverOwner
if listenerKeys.removeValue(forKey: multiListenerId) != nil {
LDClient.get(environment: environment)!.stopObserving(owner: owner)
}
}

@objc func unregisterFeatureFlagListener(_ flagKey: String, environment: String) -> Void {
unregisterListener(flagKey, environment)
let multiListenerId = envConcat(environment: environment, identifier: flagKey)
if let owner = flagListenerOwners.removeValue(forKey: multiListenerId) {
LDClient.get(environment: environment)!.stopObserving(owner: owner)
}
}

@objc func registerCurrentConnectionModeListener(_ listenerId: String, environment: String) -> Void {
let multiListenerId = envConcat(environment: environment, identifier: listenerId)
let currentConnectionModeOwner = multiListenerId as LDObserverOwner
LDClient.get(environment: environment)!.observeCurrentConnectionMode(owner: currentConnectionModeOwner, handler: { connectionMode in
let owner = ObserverOwner()
connectionModeListenerOwners[multiListenerId] = owner
LDClient.get(environment: environment)!.observeCurrentConnectionMode(owner: owner) { connectionMode in
if self.bridge != nil {
self.sendEvent(withName: self.CONNECTION_MODE_PREFIX, body: ["connectionMode": connectionMode, "listenerId": multiListenerId])
}
})
}
}

@objc func unregisterCurrentConnectionModeListener(_ listenerId: String, environment: String) -> Void {
unregisterListener(listenerId, environment)
let multiListenerId = envConcat(environment: environment, identifier: listenerId)
if let owner = connectionModeListenerOwners.removeValue(forKey: multiListenerId) {
LDClient.get(environment: environment)!.stopObserving(owner: owner)
}
}

@objc func registerAllFlagsListener(_ listenerId: String, environment: String) -> Void {
let multiListenerId = envConcat(environment: environment, identifier: listenerId)
let flagChangeOwner = multiListenerId as LDObserverOwner
LDClient.get(environment: environment)!.observeAll(owner: flagChangeOwner, handler: { changedFlags in
let owner = ObserverOwner()
allFlagsListenerOwners[multiListenerId] = owner
LDClient.get(environment: environment)!.observeAll(owner: owner) { changedFlags in
if self.bridge != nil {
self.sendEvent(withName: self.ALL_FLAGS_PREFIX, body: ["flagKeys": Array(changedFlags.keys), "listenerId": multiListenerId])
}
})
}
}

@objc func unregisterAllFlagsListener(_ listenerId: String, environment: String) -> Void {
unregisterListener(listenerId, environment)
let multiListenerId = envConcat(environment: environment, identifier: listenerId)
if let owner = allFlagsListenerOwners.removeValue(forKey: multiListenerId) {
LDClient.get(environment: environment)!.stopObserving(owner: owner)
}
}

@objc func isInitialized(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
Expand All @@ -442,6 +448,8 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter {
}
}

class ObserverOwner{}

extension NSDictionary {
@objc var swiftDictionary: Dictionary<String, Any> {
var swiftDictionary = Dictionary<String, Any>()
Expand Down
1 change: 1 addition & 0 deletions test-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ async function tests() {
allUserAttributesPrivate: true,
autoAliasingOptOut: true,
inlineUsersInEvents: true,
privateAttributeNames: ['abc', 'def'],
};
const userEmpty: LDUser = {};
const userWithKeyOnly: LDUser = { key: 'user' };
Expand Down

0 comments on commit 171192e

Please sign in to comment.