Releases: androidbroadcast/Featured
Release list
v1.2.0
Featured 1.2.0
Added
ConfigValues.warmUp(params)— new suspend function that resolves the given params in parallel
through the full priority chain and batch-writes the sync snapshot atomically, so
getValueCachedreturns fresh values at startup without requiring active subscribers. Call
configValues.warmUp(GeneratedFeaturedRegistry.all)once at app startup.fetch()and
initialize()now automatically refresh all warmed params after their provider completes,
keeping the snapshot current on every remote refresh cycle. (#261)FeatureFlagsDebugScreennow includes a search field and filters. A collapsible search bar
filters flags by key and category; an «Overridden only» chip narrows the list to flags with
active local overrides. Empty-result states provide contextual messages with a «Clear filters»
action. State (query, search expanded, filter) survives configuration changes. (#263)- Gradle plugin:
VerifyExpiredFlagsTask— on every build that runs flag code generation, the
plugin now emits a build warning for each feature flag whoseexpiresAtdate is in the past.
The check always runs even when upstream tasks are restored from cache, and is wired into all
codegen paths so it cannot be bypassed by invoking a single generation task. (#265) - Gradle plugin: new
expiredFlagsModeDSL property (featured { expiredFlagsMode = ExpiredFlagsMode.ERROR }).
Default isWARN(behavior unchanged);ERRORfails the build with aGradleExceptionlisting
every expired flag (module, key, expiry date) instead of emitting warnings. InvalidexpiresAt
format values are never escalated regardless of the mode. (#266) FeatureFlagsDebugScreengains a «Reset all overrides» action in the top bar. A confirmation
dialog shows the number of overrides to be cleared; after reset, a snackbar with an Undo
action restores the previous values. Partial failures (reset or undo) are reported
individually. (#269)ValueResolutionStrategy— a pluggable policy that selects the final value from the resolved
local, remote, and default candidates. Pass it via the new optionalresolutionStrategy
parameter ofConfigValues; the built-inValueResolutionStrategy.Defaultpreserves the
classiclocal ?: remote ?: defaultchain, so existing consumers are unaffected. Enables
policies such as "kill-switch AND" (local and remote must both betrue) and remote-only
resolution. (#276)- Gradle plugin: new
generation { }DSL block for customizing the generated code — package
(packageName), object names (className, replaces the defaultGenerated{Local,Remote}Flags<Suffix>
name entirely), and visibility (visibility = FeaturedVisibility.PUBLIC/INTERNAL, default INTERNAL,
applied to the objects and theirConfigValuesextensions). Settings can be declared module-wide in
featured { generation { } }and overridden per section inlocalFlags { }/remoteFlags { }.
ProGuard-assumevaluesrules and iOS const-val files follow the local section's effective package,
keeping release-build DCE intact with custom packages. (#278) NSUserDefaultsConfigValueProvidernow supportsTypeConverter— call
registerConverter(KClass, TypeConverter)or the inline reified overload (API mirrors
DataStoreConfigValueProvider1:1). Non-primitive values are serialized to String; enum flags
declared in the shared DSL now work on iOS, restoring cross-platform parity. (#271)FeatureFlagsDebugScreengains an optionalonError: (Throwable) -> Unitparameter that
receives all internal diagnostic errors (provider failures, override write errors, reset/undo
failures). The default behavior (print to stdout with full stack trace) is preserved; pass{}
to silence. Mirrors theConfigValues.onProviderErrorcontract. (#273)FirebaseConfigValueProvidernow implementsInitializableConfigValueProvider:initialize()
callsFirebaseRemoteConfig.ensureInitialized()to warm the on-disk cache (activated, fetched,
and defaults) into memory without a network fetch. As a resultConfigValues.initialize()makes
previously persisted Remote Config values readable viaget()immediately at app start, before
the firstfetch(). It does not activate fetched-but-unactivated config. (#163)
Changed
ConfigValuesdefaultonProviderErrorhandler changed from a silent no-op to platform
logging: Android usesLog.w("Featured", …), iOS usesNSLog, JVM writes toSystem.err.
PassonProviderError = {}to silence. Exceptions thrown by a custom handler are swallowed;
CancellationExceptionis rethrown instead of being reported as a provider error. (#260)LocalConfigValueProvider.observe()contract is now normative: the flow always emits
immediately on collection (the stored value, orConfigValue(defaultValue, Source.DEFAULT)
when the key was never written), then on every change.SharedPreferencesConfigValueProvider,
JavaPrefsConfigValueProvider,NSUserDefaultsConfigValueProvider, and
InMemoryConfigValueProviderare updated to this contract.ConfigValues.observe()now uses
a trigger model — local emissions are change signals that drive a fullgetValue()re-resolve
through the priority chain, eliminating the DEFAULT-clobbers-REMOTE flicker. (#267)NSUserDefaultsConfigValueProvider.clear()now limits deletion to keys written by this
provider instance (tracked in a persistent index); previouslyclear()wiped the entire
UserDefaults suite, which was destructive forstandardUserDefaults. Foreign keys in the same
suite are preserved.clear()now also notifies activeobserve()flows, emitting the
DEFAULT-sourced value for every previously stored key. (#270)ConfigValuesnow reads both providers before resolving a value; previously the remote
provider was skipped when the local provider returned a value. Resolved values are unchanged
under the default strategy, butonProviderErrormay now be invoked for remote failures that
were previously masked by a local override. (#276)- Gradle plugin: the generated
ConfigValuesextensions are now split into two files —
GeneratedLocalFlagExtensions<Suffix>.ktandGeneratedRemoteFlagExtensions<Suffix>.kt
(previously a singleGeneratedFlagExtensions<Suffix>.kt) — because each section can now have its
own package and visibility. The ProGuard-assumevaluesclass name changed accordingly; both the
sources and the rules are regenerated together by the plugin, so no consumer action is required.
(#278) - Dependency updates raised
androidx.coreto 1.19.0, which requires Android consumers to build
withcompileSdk 37or higher; the library itself now compiles withcompileSdk 37. (#282) - The firebase provider's
FetchExceptionis renamed toFirebaseConfigException. Since the type
now wraps failures from bothfetch()andinitialize()— not only fetches — the
operation-neutral name reflects its actual scope. Breaking: update anycatch/references to
use the new name. (#289)
Removed
- Gradle plugin: the
scanAllLocalFlagsroot-project aggregation task has been removed. The
plugin no longer accessesrootProjectand is now compatible with Gradle Project Isolation.
Use./gradlew resolveFeatureFlags(Gradle name-matched task invocation) to resolve flags
across all modules that apply the plugin. (#186)
Fixed
- Gradle plugin:
toCamelCaseconversion now fully lowercases each word before capitalising
the first letter, so ALL_CAPS flag keys produce correct camelCase names.
DARK_MODE→darkMode(wasdarkMODE),NEW_CHECKOUT_FLOW→newCheckoutFlow
(wasnewCHECKOUTFLOW). Generated function/property names change for any multi-word
ALL_CAPS flag key (e.g.isDarkMODEEnabled→isDarkModeEnabled). (#248)
v1.1.1
What's Changed
- Back-merge v1.1.0 release and bump develop to 1.2.0-SNAPSHOT by @kirich1409 in #236
- Auto-release to Maven Central on version tags by @kirich1409 in #237
- fix: register generated ProGuard rules as consumerProguardFiles for Android library modules by @kirich1409 in #240
- fix(gradle-plugin): use lazy providers for flag descriptor wiring to fix stale build cache by @kirich1409 in #241
- Prepare v1.1.1 release by @kirich1409 in #242
- Release v1.1.1 by @kirich1409 in #243
- ci: upload to Central Portal as USER_MANAGED, drop auto-release by @kirich1409 in #246
Full Changelog: v1.1.0...v1.1.1
v1.1.0
What's Changed
- Back-merge v1.0.0 release and bump develop to 1.1.0-SNAPSHOT by @kirich1409 in #222
- Publish Gradle plugin to Plugin Portal, keep Central listing clean by @kirich1409 in #228
- Add dispatchable Plugin Portal publish workflow to main by @kirich1409 in #232
- Extract Gradle Plugin Portal publish into a separate dispatchable workflow by @kirich1409 in #231
- Lower JVM target from 21 to 17 by @kirich1409 in #233
- Prepare v1.1.0 release by @kirich1409 in #235
Full Changelog: v1.0.0...v1.1.0
v1.0.0
What's Changed
- Add develop branch to CI pipeline triggers by @kirich1409 in #192
- Rename proguard task to generateFeaturedProguardRules by @kirich1409 in #190
- Fix ConfigValues.observe to catch provider exceptions by @kirich1409 in #196
- Register enum converter for CheckoutVariant in sample by @kirich1409 in #194
- Document enum-flag converter requirement by @kirich1409 in #195
- Migrate user documentation to GitHub Wiki by @kirich1409 in #193
- Publish per-module Featured manifest (producer side) by @kirich1409 in #197
- Add aggregator plugin and GeneratedFeaturedRegistry codegen by @kirich1409 in #198
- Remove FlagRegistry; make FeatureFlagsDebugScreen UI-agnostic by @kirich1409 in #199
- Multi-module sample showcasing Featured aggregator plugin by @kirich1409 in #200
- Restore R8 per-function DCE: sync getValueCached + ProGuard rule fix by @kirich1409 in #201
- Per-module ConfigValues + internal generated objects by @kirich1409 in #202
- Move Gradle plugin from build-logic/ to repo root by @kirich1409 in #215
- ci(codeql): force Kotlin recompile so CodeQL sees source by @kirich1409 in #218
- chore: release 1.0.0 — Android-stable, docs restructure by @kirich1409 in #216
- test(shrinker): cover -keep defeating flag dead-code elimination by @kirich1409 in #217
- Prepare v1.0.0 release by @kirich1409 in #219
- Port shrinker DCE test (#217) and CodeQL fix (#218) to develop by @kirich1409 in #221
- Release v1.0.0 by @kirich1409 in #220
- Wire Gradle Plugin Portal publishing for clean 1.0.0 release by @kirich1409 in #230
Full Changelog: v1.0.0-Beta1...v1.0.0
v1.0.0-Beta1
Featured 1.0.0-Beta1
First public beta of Featured — a type-safe, reactive configuration / feature-flag library for Kotlin Multiplatform (Android, iOS, JVM/Desktop).
⚠️ Beta release. Public API is feature-complete but may still change before 1.0.0 GA based on community feedback.
Highlights
- 🎯 Type-safe flags —
ConfigParam<T>with default values;enumand sealed-class multivariate flags. - ⚡ Reactive by design — observe values as Kotlin
Flow, ComposeState, or CombinePublisheron iOS. - 🔌 Pluggable providers — drop-in local (
InMemory,SharedPreferences,DataStore,NSUserDefaults,JavaPreferences) and remote (Firebase Remote Config); remote overrides local. - 🛠 Gradle plugin — declare flags in
build.gradle.kts, get generated typed extensions, R8assumevaluesrules, iOSxcconfig, and per-moduleFlagRegistryinitializers. Configuration Cache compatible (Gradle 9+, AGP 9+). - 🔍 Static analysis — Android Lint (
UncheckedFlagAccess,ExpiredFeatureFlag,InvalidFlagReference,HardcodedFlagValue) and Detekt (@BehindFlag/@AssumesFlag) rules to catch flag misuse at build time. - 🍎 First-class iOS — XCFramework via Swift Package Manager, SKIE-bridged Swift API with Combine,
@MainActorandSendablecorrectness. - 🧪 Test-friendly —
featured-testingmodule withFakeConfigValuesand a small DSL. - 🎛 Debug UI — Compose Multiplatform overlay to inspect and override flag values at runtime.
Installation
// build.gradle.kts
plugins {
id("dev.androidbroadcast.featured") version "1.0.0-Beta1"
}
dependencies {
implementation(platform("dev.androidbroadcast.featured:featured-bom:1.0.0-Beta1"))
implementation("dev.androidbroadcast.featured:featured-core")
implementation("dev.androidbroadcast.featured:featured-compose") // optional
}iOS via Swift Package Manager:
.package(url: "https://github.com/androidbroadcast/Featured.git", from: "1.0.0-Beta1")See the quick-start guide for full setup.
Requirements
- Kotlin 2.x · Gradle 9.0+ · AGP 9.0+
- Android minSdk 21+, targetSdk 35
- iOS 14+ (XCFramework via SPM)
- JVM 17+
Artifacts
- 📦 Maven Central — all JVM / Android / KMP modules
- 🍎
FeaturedCore.xcframework.zip— attached to this release; consumed automatically via SPM
What's new
Full list of additions, changes, removals and fixes: see CHANGELOG.md → 1.0.0-Beta1.
Feedback
Beta feedback is the point of this release — please file issues, especially around API ergonomics, code-generation edge cases, and Configuration Cache behavior.
- 🐛 Report a bug
- 💡 Request a feature
- 🔒 Security: see SECURITY.md
Full Changelog: https://github.com/androidbroadcast/Featured/commits/v1.0.0-Beta1