All notable changes to the LaunchDarkly Android SDK will be documented in this file. This project adheres to Semantic Versioning.
identify results in flag value changes.LDConfig.Builder.applicationInfo(), for configuration of application metadata that may be used in LaunchDarkly analytics or other product features. This does not affect feature flag evaluations.LDConfig.Builder.applicationInfo(), for configuration of application metadata that may be used in LaunchDarkly analytics or other product features. This does not affect feature flag evaluations.StreamingDataSourceBuilder.streamEvenInBackground, an option for allowing the SDK to maintain a streaming data connection even when the application is in the background.StreamingDataSourceBuilder.streamEvenInBackground, an option for allowing the SDK to maintain a streaming data connection even when the application is in the background.This release is broken and should not be used. It was an accidental duplicate of 4.1.0.
The latest version of this SDK supports LaunchDarkly's new custom contexts feature. Contexts are an evolution of a previously-existing concept, "users." Contexts let you create targeting rules for feature flags based on a variety of different information, including attributes pertaining to users, organizations, devices, and more. You can even combine contexts to create "multi-contexts."
For detailed information about this version, please refer to the list below. For information on how to upgrade from the previous version, please read the migration guide.
com.launchDarkly.sdk, the types LDContext and ContextKind define the new context model.LDUser parameter, there is now an overload that takes an LDContext. The SDK still supports LDUser for now, but LDContext is the preferred model and LDUser may be removed in a future version.TestData class in com.launchdarkly.sdk.android.integrations is a new way to inject feature flag data programmatically into the SDK for testing—either with fixed values for each flag, or with targeting logic that can return different values for different contexts.secondary meta-attribute that affects percentage rollouts. If you set an attribute with that name in LDContext, it will simply be a custom attribute like any other.anonymous attribute in LDUser is now a simple boolean, with no distinction between a false state and a null state.AlarmManager API to schedule background polling of flag data. Instead, it uses a simple worker thread. AlarmManager notifications could wake up a sleeping device, which is not desirable just for getting flag data.device and os values to the user attributes. Applications that wish to use device/OS information in feature flag rules must explicitly add such information.secondary meta-attribute in LDUser and LDUser.Builder.alias method no longer exists because alias events are not needed in the new context model.autoAliasingOptOut and inlineUsersInEvents options no longer exist because they are not relevant in the new context model.The primary purpose of this release is to introduce newer APIs for SDK configuration, corresponding to how configuration will work in the upcoming 4.0 release. The corresponding older APIs are now deprecated; switching from them to the newer ones now will facilitate migrating to 4.0 in the future. This also brings the Android SDK's API closer in line with other current LaunchDarkly SDKs, such as the Java SDK and the .NET SDKs.
Previously, most configuration options were set by setter methods in LDConfig.Builder. These are being superseded by builders that are specific to one area of functionality: for instance, Components.streamingDataSource() and Components.pollingDataSource() provide builders/factories that have options specific to streaming or polling, and the SDK's many options related to analytics events are now in a builder returned by Components.sendEvents(). Using this newer API makes it clearer which options are for what, and makes it impossible to write contradictory configurations like .stream(true).pollingIntervalMillis(30000).
The new configuration builders also include some options for SDK behavior that could not previously be configured; see "Added".
Components, containing factory methods for the various configuration builders.com.launchdarkly.sdk.android.integrations: StreamingDataSourceBuilder, PollingDataSourceBuilder, EventProcessorBuilder, HttpConfigurationBuilder, ServiceEndpointsBuilder.LDConfig.Builder.events() to Components.noEvents().com.launchdarkly.sdk.android.subsystems.EventProcessor.StreamingDataSourceBuilder.initialReconnectDelayMillis().(all in LDConfig.Builder)
pollingIntervalMillis, stream: see PollingDataSourceBuilder.backgroundPollingIntervalMillis: see PollingDataSourceBuilder and StreamingDataSourceBuilder.allAttributesPrivate, diagnosticRecordingIntervalMillis, eventsCapacity, eventsFlushIntervalMillis, inlineUsersInEvents, privateAttributes: see EventProcessorBuilder.connectionTimeoutMillis, headerTransform, useReport, wrapperName, wrapperVersion: see HttpConfigurationBuilder.streamUri, pollUri, eventsUri: See ServiceEndpointsBuilder.The purpose of this release is to introduce a new logging facade, com.launchdarkly.logging, to streamline how logging works in LaunchDarkly Java and Android code.
Previously, the Android SDK always used Timber for logging. This sometimes led to conflicts with an application's separate use of Timber, as described in #88 and #147.
In this release, the default behavior is still to use Timber, but the logging facade can also be configured programmatically to do simple Android logging without Timber, or to forward output to another framework such as java.util.logging, or to multiple destinations, or to capture output in memory. In a future major version release, the default behavior may be changed so that the SDK does not require Timber as a dependency.
LDConfig.Builder, the new methods logAdapter, logLevel, and loggerName, for the new logging capabilities mentioned above.LDTimberLogging for configuring the SDK's Timber integration.LDAndroidLogging for configuring the SDK to use the Android logging API without Timber.java.util.Random to use java.security.SecureRandom. Even though in this case it is not being used for any cryptographic purpose, but only to produce a pseudo-random delay, static analysis tools may still report every use of java.util.Random as a security risk by default. The purpose of this change is simply to avoid such warnings; it has no practical effect on the behavior of the SDK.LDClient instances was not being cleared after calling close(). (#108)ExecutorService object to be unnecessarily created when flush() was called.baseUri or streamUri to a URI with a trailing slash could cause requests to fail. Now the SDK works correctly regardless of whether these URIs have a trailing slash or not."anonymous": false in analytics event data for users where the anonymous property had not been set at all. In the current user model, "anonymous": false is subtly different from not setting the property (flag rules referencing anonymous will only work if it is explicitly set), so the event data should accurately represent this by omitting the property if it was omitted.variation methods, in an edge case where the SDK received inconsistent data of a kind that the LaunchDarkly services would not normally send (an evaluation result with a value but no variation). This should not be possible in practice, but could happen in test scenarios.LaunchDarklySdk. (Thanks, audkar!)Throttler and ConnectivityManager. (Thanks, res0nance!)LDClient that caused synchronous init()s to unnecessarily block other methods, resulting in ANRs.NullPointerException when event buffer is full and diagnosticOptOut is true. (Thanks, mattyway!)android:label attribute from the SDK's manifest. (Thanks, Exaper!)android:allowBackup tag from the SDK's AndroidManifest.xml file to avoid requiring applications to explicitly replace the tag if given a different value. (#138)SecurityException when thrown on call to getNetworkCapabilities used to detect current network availability. (#129)PendingIntents as FLAG_IMMUTABLE on Android SDK versions that support doing so. Explicitly specifying mutability is required when targeting Android S+. (#133)android:exported attribute on declared receiver elements. This is to meet new requirements in the upcoming Android 12 release.jackson-databind to 2.10.5.1, due to CVE-2020-25649.NullPointerException in DiagnosticEventProcessor.stopScheduler when LDClient.close is called before the application is foregrounded when the SDK was initialized in the background. (#127)This major version has an accompanying Migration Guide. Please see the guide for more information on updating to this version of the SDK, as the following is just a summary of the changes.
Usages of Gson provided types have been removed from the public API, replacing JsonElement with LDValue provided by the SDK. LDValue can represent the same values as a JsonElement, but has a diferent API. See the API documentation for a detailed reference.
LDConfig.Builder customization:
autoAliasingOptOut configuration option that is used to control the new automatic aliasing behavior of the identify method; by setting autoAliasingOptOut to true, identify will not automatically generate alias events.headerTransform configuration option that supersedes the previous additionalHeaders configuration option by allowing fully dynamic updating of headers for requests the SDK makes to the LaunchDarkly service.privateAttributes configuration option that replaces setPrivateAttributeNames, specifying the private attributes as vararg UserAttribute arguments rather than a Set<String>. This allows easily specifying built-in attributes.LDUser(String) constructor that creates a fully default user.LDUser
getAttribute(UserAttribute) for programmatically retrieving attribute values.getCustomAttributes() for retrieving the currently set custom attributes.getPrivateAttributes() for retrieving the attributes set to be private on this user.isAttributePrivate(UserAttribute) for checking if a given attribute is private.getName()LDUser.Builder methods overloads for custom and privateCustom:
custom(String, boolean) and privateCustom(String, boolean) for setting custom attributes to boolean values.custom(String, int), privateCustom(String, int), custom(String, double), and privateCustom(String, double) for setting custom attributes to numeric values.custom(String, LDValue) and privateCustom(String, LDValue) for setting custom attributes to arbitrary data.UserAttribute class, which provides a less error-prone way to refer to user attribute names in configuration. This class can also be used to get arbitrary attribute- LDClient functionality:
alias method that is used to associate two user objects for analytics purposes with an alias event.jsonValueVariation and jsonValueVariationDetail. These are equivalent to the removed and other than using instead of .LDUser instances created before calling LDClient.init without specifying a key would have the key UNKNOWN_ANDROID rather than a device unique key.NullPointerException is thrown if LDClient.close() is called multiple times.android.useAndroidX Android Gradle plugin flag to be set to true in your application's gradle.properties file. If your application previously set the android.enableJetifier Android Gradle plugin flag to true in it's gradle.properties file soley for the LaunchDarkly SDK, this flag can now be removed. Thanks to everyone who requested this enhancement (#103).com.launchdarkly.sdk and com.launchdarkly.sdk.android.LDConfig.Builder setters have been renamed to remove the set prefix, e.g. LDConfig.Builder.setMobileKey has been renamed to LDConfig.Builder.mobileKey.LDClient API changes:
boolVariation and intVariation no longer use nullable object types for argument and return values, instead using primitive types, e.g. Boolean boolVariation(String, Boolean) became boolean boolVariation(String, boolean).boolVariationDetail and intVariationDetail no longer use nullable object types for argument values, instead using primitive types, e.g. boolVariationDetail(String, Boolean) became boolVariationDetail(String, boolean).allFlags() now returns Map<String, LDValue> rather than Map<String, ?>. Rather than the returned Map containing Boolean, Float, and String typed objects, with JSON values represented as strings, the Map contains LDValue typed objects which return the source type (including complex types such as JSON arrays and objects).EvaluationDetail.getVariationIndex() now returns int instead of Integer. No variation index is now represented as the constant EvaluationReason.NO_VARIATION.EvaluationReason is now a single concrete class rather than an abstract base class. Usages of the sub-classes can be replaced with the base class.LDConfig.Builder.pollUri) has changed from app.launchdarkly.com to clientsdk.launchdarkly.com.eventsUri used to send events to the service has changed from https://mobile.launchdarkly.com/mobile to https://mobile.launchdarkly.com. The SDK will now append the expected endpoint path (/mobile) to the configured Uri, which is more consistent with other LaunchDarkly SDKs.LDClient.stringVariation method could be used to retrieve JSON flags in a serialized representation. This compatibility behavior has been removed, and attempts to request a JSON valued flag using stringVariation will behave the same as other mismatched type variation calls.LDClient.identify method will now automatically generate an alias event when switching from an anonymous to a known user. This event associates the two users for analytics purposes as they most likely represent a single person. This behavior can be disabled with the autoAliasingOptOut configuration option.LaunchDarklySdk for easier filtering. Thanks to @valeriyo for the suggestion (#113).LDUser now overrides equals, hashCode, and toString with appropriate implementations.LDUser.Builder.country(String) and LDUser.Builder.privateCountry(String) no longer attempt to look up the country from the provided String (attempting to match it as an ISO-3166-1 alpha-2, alpha-3 code; or a country name) and set the country to the resultant IOS-3166-1 alpha-2 only if successful. The SDK no longer gives this attribute special behavior, and sets the user's country attribute directly as the provided String.LDConfig.Builder:
setBaseUri(Uri) has been removed. Please use setPollUri(Uri) instead.setAdditionalHeaders(Map<String,String>) has been removed. Please use headerTransform(LDHeaderUpdater) instead.setPrivateAttributeNames(Set<String>) has been removed. Please use privateAttributes(UserAttribute...) instead.LDUser.Builder:
country(LDCountryCode) and privateCountry(LDCountryCode) have been removed. Use country(String) or privateCountry(String) to set the country value on a user.custom(String, Number) and privateCustom(String, Number) have been removed. Use the (String, int) or (String, double) overloads instead.custom(String, Boolean) and privateCustom(String, Boolean) have been removed. Use custom(String, boolean) or privateCustom(String, boolean) instead.custom(String, List<String>), LDUser.customString(String, List<String>), LDUser.privateCustomString(String, List<String>). Use custom(String, LDValue) and privateCustom(String, LDValue) instead.customNumber(String, List<Number>) and LDUser.privateCustomNumber(String, List<Number>). Use custom(String, LDValue) and privateCustom(String, LDValue) instead.LDClient:
floatVariation and floatVariationDetail have been removed. Use doubleVariation and doubleVariationDetail instead.jsonVariation and jsonVariationDetail have been removed. Use jsonValueVariation and jsonValueVariationDetail instead.track(String, JsonElement) and track(String, JsonElement, Double) overloads have been removed, please use the designated methods trackData(String, LDValue) and trackMetric(String, LDValue, double) instead.EvaluationDetail has been hidden. Use the new factory methods EvaluationDetail.fromValue and EvaluationDetail.error instead.jsonVariationjsonVariationDetailLDValueJsonElementtrackData(String, LDValue) which replaces track(String, JsonElement). Other than changing to use LDValue the behavior is the same.trackMetric(String, LDValue, double) which replaces track(String, JsonElement, Double). This also uses LDValue rather than JsonElement, and requires a metric value. Otherwise use trackData.LDGson and LDJackson classes, which allow SDK classes like LDUser to be easily converted to or from JSON using the popular Gson and Jackson frameworks.EvaluationDetail.fromValue and EvaluationDetail.error factory methods.LDHeaderUpdater interface for the new headerTransform configuration option.EvaluationReason have been removed in favor of making EvaluationReason a concrete class. The accessors on the sub-classes have been moved to the base class. Instead of using instanceOf to determine the type, use getKind().LDCountryCode has been removed as no SDK APIs use this class.com.launchdarkly.sdk.android.flagstore, com.launchdarkly.sdk.android.gson, com.launchdarkly.sdk.android.response, and com.launchdarkly.sdk.android.tls packages. These classes and interfaces were not intended for external use.Debounce, FeatureFlagFetcher, SummaryEventSharedPreferences, UserSummaryEventSharedPreferences, and Util in com.launchdarkly.sdk.android. These deprecated classes and interfaces were not intended for external use.