Third party remote configuration provider integration is currently in private beta and will be available in the next major release of Appfigurate.
Using Appfigurate remote properties instead of Launch Darkly flag evaluation APIs directly allows for the following:
locally change Launch Darkly flags without affecting your entire customer base.
compile time type safety - Appfigurate remote properties are typed, Launch Darkly flags are not.
avoids hardcoding duplicated flag names throughout your app.
avoids hardcoding duplicated default values throughout your app.
deleting a flag from Launch Darkly Console won't affect existing apps, they'll continue to use the default value provided in the reset method.
We assume you already have Appfigurate Library and Launch Darkly integrated into your app with the following example remote properties created in the Launch Darkly console:
Add remote properties into your Configuration subclass
Update your configuration subclass to include your remote configuration properties. Provide default values for the properties in the overridden reset method. See also Supported property types.
Swift Configuration example
import Foundation
import AppfigurateLibrary
@objcMembers class MyConfiguration: APLConfiguration {
...
@RemoteBoolProperty(remoteKey: "alwaysDarkMode", description: "Force dark mode to be always set")
var alwaysDarkMode: Bool
@RemoteStringPropertyEdit(remoteKey: "appTitle", description: "Title of application")
var appTitle: String
@RemoteIntPropertyEdit(remoteKey: "bookingDuration", description: "Duration (days) for reservation bookings")
var bookingDuration: Int
@RemoteDoublePropertyEdit(remoteKey: "fontSize", description: "Size of font throughout app")
var fontSize: Double
...
override func reset() {
alwaysDarkMode = false
appTitle = "Holiday finder"
bookingDuration = 30
fontSize = 13.0
}
...
}
Notify Appfigurate Library when Launch Darkly has received flags
We need to tell Appfigurate Library that Launch Darkly has received flags, so that it can keep your Configuration subclasses remote properties in sync.
Add a call to APLFlushRemoteConfiguration in any existing Launch Darkly start(config, startWaitSeconds, completion) and observeAll(owner, handler) blocks.
Swift example
LDClient.start(config: config, startWaitSeconds: 5.0) { timedOut in
...
APLFlushRemoteConfiguration() // add this line
}
...
LDClient.get()?.observeAll(owner: self) { keys in
...
APLFlushRemoteConfiguration() // add this line
}
Add a call to APLFlushRemoteConfiguration in any existing Launch Darkly startWithConfiguration:startWaitSeconds:completion: and observeAllKeysWithOwner:handler: blocks.
Objective-C example
[LDClient startWithConfiguration:config startWaitSeconds:5.0 completion:^(bool timedOut) {
...
APLFlushRemoteConfiguration(); // add this line
}];
...
[[LDClient get] observeAllKeysWithOwner: self handler:^(NSDictionary<NSString *,LDChangedFlag *> *handler) {
...
APLFlushRemoteConfiguration(); // add this line
}];
The Android Launch Darkly SDK doesn't have functionality that notifies you of flags being received during the LDClient.init call. Instead we must programmatically check for a well known flag's evaluation detail, and then call Appfigurate.flushRemoteConfiguration as appropriate.
Add another call to Appfigurate.flushRemoteConfiguration in a Launch Darkly registerAllFlagsListener block.
Java example
LDClient.init(...)
...
// add this block of code
if (LDClient.get().boolVariationDetail("alwaysDarkMode", false).variationIndex > EvaluationDetail.NO_VARIATION) {
// Flags loaded by LDClient.init()
Appfigurate.flushRemoteConfiguration()
}
...
LDClient.get().registerAllFlagsListener {
...
Appfigurate.flushRemoteConfiguration() // add this line
}
The Android Launch Darkly SDK doesn't have functionality that notifies you of flags being received during the LDClient.init call. Instead we must programmatically check for a well known flag's evaluation detail, and then call Appfigurate.flushRemoteConfiguration as appropriate.
Add another call to Appfigurate.flushRemoteConfiguration in a Launch Darkly registerAllFlagsListener block.
Java example
LDClient.init(...)
...
// add this block of code
if (LDClient.get().boolVariationDetail("alwaysDarkMode", false).variationIndex > EvaluationDetail.NO_VARIATION) {
// Flags loaded by LDClient.init()
Appfigurate.flushRemoteConfiguration();
}
...
LDClient.get().registerAllFlagsListener(new LDAllFlagsListener() {
@Override
public void onChange(List<String> flagKey) {
...
Appfigurate.flushRemoteConfiguration(); // add this line
}
});
Best practice and usage
Replace all calls to Launch Darkly boolVariation(forKey:defaultValue:), intVariation(forKey:defaultValue:), doubleVariation(forKey:defaultValue), stringVariation(forKey:defaultValue:)
if (LDClient.get()!.boolVariation(forKey: "alwaysDarkMode", defaultValue: false)) {
...
with the following:
if ((APLConfiguration.shared() as! MyConfiguration).alwaysDarkMode) {
...
Replace all calls to Launch Darkly boolVariationForKey:defaultValue:, intVariationForKey:defaultValue:, doubleVariationForKey:defaultValue, stringVariationForKey:defaultValue:
if ([[LDClient get] boolVariationForKey: @"alwaysDarkMode" defaultValue: NO]) {
...
with the following:
if (((MyConfiguration*) [APLConfiguration sharedConfiguration]).alwaysDarkMode) {
...
Replace all calls to Launch Darkly boolVariation(), intVariation(), doubleVariation(), stringVariation()