### Install Android Sample App Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to build and install the debug version of the Android sample application. ```bash ./gradlew :sample:android-app:installDebug ``` -------------------------------- ### Run All Tests for Featured Platform Source: https://github.com/androidbroadcast/featured/blob/main/featured-platform/CLAUDE.md Executes all tests for the featured-platform module using Gradle. Ensure you have Gradle installed and configured. ```bash ./gradlew :featured-platform:allTests ``` -------------------------------- ### Run All Tests for Featured Detekt Rules Source: https://github.com/androidbroadcast/featured/blob/main/featured-detekt-rules/CLAUDE.md Executes all tests for the featured-detekt-rules module using Gradle. Ensure you have Gradle installed and configured for the project. ```bash ./gradlew :featured-detekt-rules:allTests ``` -------------------------------- ### Wire up ConfigValues in Application Source: https://github.com/androidbroadcast/featured/blob/main/README.md Initialize and wire up the ConfigValues object in your application, using DataStore as the local provider for feature flags. This setup should be done once. ```kotlin val dataStore = PreferenceDataStoreFactory.create { context.dataStoreFile("feature_flags.preferences_pb") } val configValues = ConfigValues( localProvider = DataStoreConfigValueProvider(dataStore), ) ``` -------------------------------- ### Featured Gradle Plugin DSL Example Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Example of defining local flags within the featured Gradle plugin's DSL. This DSL generates typed ConfigParam objects and associated extensions. ```kotlin featured { localFlags { // ... flag definitions ... } } ``` -------------------------------- ### Example xcconfig Content Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig This is an example of the content generated in the xcconfig file. It includes Swift compilation conditions that will be used by Xcode to conditionally compile code. ```xcconfig # Auto-generated by featured-gradle-plugin — do not edit # Include this file in your Xcode Release configuration SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) DISABLE_NEW_CHECKOUT DISABLE_EXPERIMENTAL_UI ``` -------------------------------- ### Multi-module ConfigValues Setup Source: https://github.com/androidbroadcast/featured/blob/main/README.md In a multi-module application, set up shared local providers and individual ConfigValues instances for each feature module, including a debug aggregator. This pattern ensures consistent flag management across modules. ```kotlin // Construct one ConfigValues per feature module + one debug aggregator, all over a shared provider val sharedLocal: LocalConfigValueProvider = defaultLocalProvider(applicationContext) val checkoutConfig = ConfigValues(localProvider = sharedLocal) val promotionsConfig = ConfigValues(localProvider = sharedLocal) val uiConfig = ConfigValues(localProvider = sharedLocal) // Debug-only aggregator that the FeatureFlagsDebugScreen drives val debugConfig = ConfigValues(localProvider = sharedLocal) FeatureFlagsDebugScreen( configValues = debugConfig, registry = GeneratedFeaturedRegistry.all, ) ``` -------------------------------- ### Read a One-Shot Async Configuration Value Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Asynchronously retrieve a specific configuration value. The example shows reading a boolean value for a feature flag. ```swift let configValue = try await configValues.getValue(param: FeatureFlags.shared.newCheckout) let isEnabled: Bool = configValue.value ``` -------------------------------- ### Initialize ConfigValues with Default Local Provider Source: https://github.com/androidbroadcast/featured/blob/main/featured-platform/README.md Instantiate `ConfigValues` using `DefaultLocalProvider()` to get the recommended local persistence for the current platform. This provider defaults to DataStore on Android, NSUserDefaults on iOS, and Java Preferences on JVM. ```kotlin val configValues = ConfigValues( localProvider = DefaultLocalProvider(), remoteProvider = firebaseProvider, ) ``` -------------------------------- ### Initialize FirebaseConfigValueProvider Source: https://github.com/androidbroadcast/featured/wiki/Providers Instantiate FirebaseConfigValueProvider with a default ConfigValues object. Fetch and activate configuration values on app start by calling `configValues.fetch()` within a coroutine scope. ```kotlin import dev.androidbroadcast.featured.firebase.FirebaseConfigValueProvider val configValues = ConfigValues( localProvider = DataStoreConfigValueProvider(dataStore), remoteProvider = FirebaseConfigValueProvider(), ) // Fetch and activate on app start — suspend function, call from a coroutine lifecycleScope.launch { configValues.fetch() } ``` -------------------------------- ### Create Combine Publisher from AsyncStream Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Build a Combine publisher on top of an AsyncStream to integrate with Combine-based reactive programming patterns. This example demonstrates updating a @Published property within a ViewModel. ```swift import Combine class CheckoutViewModel: ObservableObject { @Published var isNewCheckoutEnabled: Bool = false private let configValues: ConfigValues init(configValues: ConfigValues) { self.configValues = configValues } func startObserving() { Task { for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) { await MainActor.run { self.isNewCheckoutEnabled = configValue.value } } } } } ``` ```swift featureFlags.publisher(for: newCheckoutFlag) .receive(on: DispatchQueue.main) .sink { isEnabled in updateUI(isEnabled) } .store(in: &cancellables) ``` -------------------------------- ### Clone Repository and Build Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Clone the Featured repository and build the project using Gradle. This is the initial step for setting up the development environment. ```bash git clone https://github.com/AndroidBroadcast/Featured.git cd Featured ./gradlew assemble ``` -------------------------------- ### Run Compose Desktop Sample App Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to run the Compose Desktop sample application. ```bash ./gradlew :sample:desktop:run ``` -------------------------------- ### Build All Projects Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to build all modules and artifacts within the project. ```bash ./gradlew assemble ``` -------------------------------- ### Example R8 Assumevalues Rule for Local Flag Source: https://github.com/androidbroadcast/featured/wiki/Android-DCE-R8 This is an example of a generated R8 rule for a local boolean flag 'new_checkout' with a default value of false. It instructs R8 to assume the flag accessor always returns false. ```proguard -assumevalues class dev.example.app.GeneratedLocalFlagsKt { boolean isNewCheckoutEnabled(dev.androidbroadcast.featured.ConfigValues) return false; } ``` -------------------------------- ### Configure JVM/Desktop Project with Gradle Source: https://github.com/androidbroadcast/featured/wiki/Installation Apply the featured Gradle plugin and BOM, then include the core and javaprefs-provider artifacts for JVM-specific configurations. ```kotlin plugins { id("dev.androidbroadcast.featured") version "" } dependencies { implementation(platform("dev.androidbroadcast.featured:featured-bom:")) implementation("dev.androidbroadcast.featured:featured-core") implementation("dev.androidbroadcast.featured:javaprefs-provider") } ``` -------------------------------- ### Reactive Flag Read in ViewModel Source: https://github.com/androidbroadcast/featured/wiki/Getting-Started Observe the 'new_checkout' flag using `observe` and `stateIn` to get a `StateFlow` for reactive updates in a ViewModel. ```kotlin val isNewCheckoutEnabled: StateFlow = configValues.observe(GeneratedLocalFlags.newCheckout) .map { it.value } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), false) ``` -------------------------------- ### Build Registry Inline Source: https://github.com/androidbroadcast/featured/wiki/Debug-UI For small or single-module projects, you can manually create a list of configuration parameters for the debug screen registry. ```kotlin val registry = listOf(MyFlags.flagA, MyFlags.flagB, MyFlags.flagC) ``` -------------------------------- ### Initialize and Fetch Configuration Values Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Initialize the ConfigValues instance and trigger a background fetch. This should be called before serving any screens. At least one provider (local or remote) must be non-nil. ```swift @MainActor class AppState: ObservableObject { let configValues: ConfigValues init() { configValues = ConfigValues( localProvider: nil, remoteProvider: nil, onProviderError: { error in print("Featured error: \(error)") } ) } func setup() async { do { try await configValues.initialize() try await configValues.fetch() } catch { print("Featured setup error: \(error)") } } } ``` -------------------------------- ### Run Assemble Release Task with Configuration Cache Option Source: https://github.com/androidbroadcast/featured/blob/main/docs/specs/2026-05-16-gradle-plugin-cc-support.md Helper function to run the 'assembleRelease' task, with an option to enable the configuration cache. Captures the build result. ```kotlin private fun runAssembleRelease(projectDir: File, cc: Boolean): BuildResult { val args = buildList { add("assembleRelease") add("--stacktrace") if (cc) { add("--configuration-cache") add("--configuration-cache-problems=fail") } } return GradleRunner.create() .withProjectDir(projectDir) .withArguments(args) .withPluginClasspath() .build() } ``` -------------------------------- ### Assemble Debug Build Source: https://github.com/androidbroadcast/featured/wiki/Sample-App Assemble the debug build for the sample application. This is a standard Gradle command. ```bash ./gradlew :sample:assembleDebug ``` -------------------------------- ### Access Feature Flag Value Source: https://github.com/androidbroadcast/featured/blob/main/README.md Read the generated extension for a feature flag to check its current status. This example shows how to access the 'new_checkout' flag. ```kotlin val isEnabled: Boolean = configValues.isNewCheckoutEnabled() ``` -------------------------------- ### Guard AppDelegate/SceneDelegate Observers with #if Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig Use `#if !DISABLE_` to guard the setup of observers in AppDelegate or SceneDelegate. This prevents observers related to disabled features from being initialized. ```swift #if !DISABLE_NEW_CHECKOUT setupNewCheckoutObservers() #endif ``` -------------------------------- ### Run All Tests Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Execute all tests in the project using the Gradle wrapper. This command is used to ensure the codebase is functioning as expected. ```bash ./gradlew test ``` -------------------------------- ### Gradle Command for Fixture Build Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/fixture-report-2026-05-17.md Execute this command within the isolated fixture directory to build the project with the configuration cache enabled and fail on any problems. ```bash cd /tmp/featured-fixture-ac3 gradle assembleRelease --configuration-cache --configuration-cache-problems=fail ``` -------------------------------- ### Generated Local Integer Flag Accessor Source: https://github.com/androidbroadcast/featured/wiki/Declaring-Flags Example of generated Kotlin code for an integer local flag. The plugin creates a typed accessor on `ConfigValues` to retrieve the flag's value. ```kotlin internal object GeneratedLocalFlags { val maxCartItems: ConfigParam = ConfigParam( key = "max_cart_items", defaultValue = 10, ) } fun ConfigValues.getMaxCartItems(): Int = getValue(GeneratedLocalFlags.maxCartItems).value ``` -------------------------------- ### Gradle Commands for Configuration Cache Verification Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/sample-report-2026-05-17.md Execute these Gradle commands to test Configuration Cache on different sample modules. Ensure the `--configuration-cache` and `--configuration-cache-problems=warn` flags are used. ```bash ./gradlew :sample:android-app:assembleRelease --configuration-cache --configuration-cache-problems=warn ./gradlew :sample:desktop:packageDistributionForCurrentOs --configuration-cache --configuration-cache-problems=warn ./gradlew :sample:shared:assemble --configuration-cache --configuration-cache-problems=warn ``` -------------------------------- ### Generated Local Boolean Flag Accessor Source: https://github.com/androidbroadcast/featured/wiki/Declaring-Flags Example of generated Kotlin code for a boolean local flag. The plugin creates a typed accessor on `ConfigValues` to retrieve the flag's value. ```kotlin // Generated — do not edit internal object GeneratedLocalFlags { val newCheckout: ConfigParam = ConfigParam( key = "new_checkout", defaultValue = false, ) } // Public extension on ConfigValues fun ConfigValues.isNewCheckoutEnabled(): Boolean = getValue(GeneratedLocalFlags.newCheckout).value ``` -------------------------------- ### SwiftUI Integration for Feature Flags Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Integrate feature flag states into a SwiftUI View. This example shows conditionally displaying different UI elements based on the `isNewCheckoutEnabled` state managed by a ViewModel. ```swift struct CheckoutView: View { @StateObject private var viewModel: CheckoutViewModel var body: some View { Group { if viewModel.isNewCheckoutEnabled { NewCheckoutFlow() } else { LegacyCheckoutFlow() } } .onAppear { viewModel.startObserving() } } } ``` -------------------------------- ### Run Plugin Unit Tests Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to execute unit tests specifically for the Gradle plugin, which has over 43 test cases. ```bash ./gradlew :featured-gradle-plugin:test ``` -------------------------------- ### Run All Featured Tests Source: https://github.com/androidbroadcast/featured/blob/main/featured-testing/CLAUDE.md Executes all tests in the featured-testing module using Gradle. ```bash ./gradlew :featured-testing:allTests ``` -------------------------------- ### Apply Gradle Plugin and Declare Dependencies Source: https://github.com/androidbroadcast/featured/wiki/Getting-Started Apply the Featured Gradle plugin and declare core and persistence dependencies. Replace `` with the latest version. ```kotlin // build.gradle.kts plugins { id("dev.androidbroadcast.featured") version "" } dependencies { implementation(platform("dev.androidbroadcast.featured:featured-bom:")) // Core runtime — always required implementation("dev.androidbroadcast.featured:featured-core") // Local persistence — DataStore is the recommended choice for Android implementation("dev.androidbroadcast.featured:featured-datastore-provider") } ``` -------------------------------- ### Run All Tests for Featured Lint Rules Source: https://github.com/androidbroadcast/featured/blob/main/featured-lint-rules/CLAUDE.md Execute all tests for the featured lint rules module using the Gradle wrapper. This command is used to verify the functionality and correctness of the lint rules. ```bash ./gradlew :featured-lint-rules:allTests ``` -------------------------------- ### Create and Push Version Tag Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Create a Git tag for the new version and push it to the remote repository. This action triggers the automated release workflow. ```bash git tag v1.0.0 git push origin v1.0.0 ``` -------------------------------- ### Run All Tests for KMP Module Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to run all tests across different targets (JVM, Android, iOS) for a Kotlin Multiplatform module. ```bash ./gradlew :featured-debug-ui:allTests ``` -------------------------------- ### Check Code Formatting Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Verify that the project's code adheres to the defined formatting standards using Spotless. This command checks for any formatting issues. ```bash ./gradlew spotlessCheck ``` -------------------------------- ### Add Repositories to settings.gradle.kts Source: https://github.com/androidbroadcast/featured/wiki/Getting-Started Configure Maven repositories for dependency resolution. Ensure `mavenCentral()` and `google()` are included. ```kotlin dependencyResolutionManagement { repositories { mavenCentral() google() } } ``` -------------------------------- ### Run All Tests for Featured Debug UI Source: https://github.com/androidbroadcast/featured/blob/main/featured-debug-ui/CLAUDE.md Execute all tests for the featured-debug-ui module using the Gradle wrapper. ```bash ./gradlew :featured-debug-ui:allTests ``` -------------------------------- ### Initialize ConfigValues with DataStore Provider Source: https://github.com/androidbroadcast/featured/wiki/Getting-Started Create a `ConfigValues` instance using `DataStoreConfigValueProvider` for local flag storage. This should be done once at app startup. ```kotlin import androidx.datastore.preferences.core.PreferenceDataStoreFactory import dev.androidbroadcast.featured.ConfigValues import dev.androidbroadcast.featured.datastore.DataStoreConfigValueProvider val dataStore = PreferenceDataStoreFactory.create { context.dataStoreFile("feature_flags.preferences_pb") } val configValues = ConfigValues( localProvider = DataStoreConfigValueProvider(dataStore), ) ``` -------------------------------- ### Apply Gradle Plugin and Define Dependencies Source: https://github.com/androidbroadcast/featured/wiki/Installation Apply the featured Gradle plugin and declare core, compose, persistence, remote, and debug UI dependencies. The BOM manages versioning. ```kotlin build.gradle.kts plugins { id("dev.androidbroadcast.featured") version "" } dependencies { implementation(platform("dev.androidbroadcast.featured:featured-bom:")) // Core runtime — always required implementation("dev.androidbroadcast.featured:featured-core") // Compose extensions (collectAsState, LocalConfigValues) implementation("dev.androidbroadcast.featured:featured-compose") // Local persistence providers — pick one or both implementation("dev.androidbroadcast.featured:featured-datastore-provider") implementation("dev.androidbroadcast.featured:featured-sharedpreferences-provider") // Remote provider implementation("dev.androidbroadcast.featured:featured-firebase-provider") // Debug UI — debug builds only debugImplementation("dev.androidbroadcast.featured:featured-debug-ui") } ``` -------------------------------- ### Snapshot Top-Level Subdirs for Configuration Cache Source: https://github.com/androidbroadcast/featured/blob/main/docs/specs/2026-05-16-gradle-plugin-cc-support.md Helper function to snapshot top-level subdirectories under build/reports/configuration-cache. Used for verifying configuration cache behavior. ```kotlin private fun ccHashDirs(projectDir: File): Set { val root = projectDir.resolve("build/reports/configuration-cache") if (!root.exists()) return emptySet() return root.listFiles { f -> f.isDirectory } ?.map { it.name } ?.toSet() ?: emptySet() } ``` -------------------------------- ### ConfigCatConfigValueProvider Initialization Source: https://github.com/androidbroadcast/featured/wiki/Providers Initialize a ConfigCatConfigValueProvider to wrap the ConfigCat KMP SDK. Remote values override local values. Requires the 'featured-configcat-provider' dependency. ```kotlin import com.configcat.ConfigCatClient import dev.androidbroadcast.featured.configcat.ConfigCatConfigValueProvider val client = ConfigCatClient(sdkKey = "YOUR_SDK_KEY") val provider = ConfigCatConfigValueProvider(client) val configValues = ConfigValues(remoteProvider = provider) // Fetch latest values — suspend function, call from a coroutine lifecycleScope.launch { configValues.fetch() } ``` -------------------------------- ### Enable Configuration Cache Source: https://github.com/androidbroadcast/featured/wiki/Configuration-Cache Add this line to your gradle.properties file to enable the Gradle Configuration Cache. ```properties org.gradle.configuration-cache=true ``` -------------------------------- ### Assemble Debug Build with Firebase Source: https://github.com/androidbroadcast/featured/wiki/Sample-App Assemble the debug build for the sample application, enabling Firebase integration. Requires `google-services.json` to be present. ```bash ./gradlew :sample:assembleDebug -PhasFirebase=true ``` -------------------------------- ### Publish Gradle Plugin Locally Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to publish the Gradle plugin to the local Maven repository, allowing it to be used in other projects. ```bash ./gradlew publishToMavenLocal ``` -------------------------------- ### Configure Gradle Repositories Source: https://github.com/androidbroadcast/featured/wiki/Installation Add Maven Central and Google repositories to your Gradle settings. This is required for dependency resolution. ```kotlin settings.gradle.kts dependencyResolutionManagement { repositories { mavenCentral() google() } } ``` -------------------------------- ### Wiring Provider via Variant API Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md This snippet shows how the `featured-gradle-plugin` wires a task provider to the `variant.proguardFiles` collection. It uses `flatMap` to expose the output file as a `Provider`, which AGP can use to infer task dependencies. ```kotlin androidComponents.onVariants { variant -> variant.proguardFiles.add( proguardTask.flatMap { it.outputFile }) } ``` -------------------------------- ### Providing ConfigValues via CompositionLocal (Kotlin) Source: https://github.com/androidbroadcast/featured/wiki/Reading-Flags-Kotlin Sets up a CompositionLocal to provide ConfigValues throughout the composition tree, avoiding the need to pass it manually to every composable. Demonstrates how descendant composables can access it. ```kotlin import dev.androidbroadcast.featured.compose.LocalConfigValues // At the root of your composition (e.g. in MainActivity or NavHost) CompositionLocalProvider(LocalConfigValues provides configValues) { AppContent() } // In any descendant composable @Composable fun SomeScreen() { val configValues = LocalConfigValues.current val isEnabled by configValues.collectAsState(GeneratedLocalFlags.newCheckout) // … } ``` -------------------------------- ### Run Specific Module Unit Tests Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to run unit tests for a specific module, in this case, the 'core' module. ```bash ./gradlew :core:test ``` -------------------------------- ### Check Marker String in R8 Configuration Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md Uses grep to check for the marker string in R8's configuration.txt artifact. Expected to find 0 matches. ```bash grep -F "featured-cc-marker" build/outputs/mapping/release/configuration.txt ``` -------------------------------- ### Project Module Overview Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md This diagram illustrates the module dependencies within the Android Broadcast Featured project. It shows how different provider modules interact with the core module. ```text featured-compose ──┐ firebase-provider ─┤ datastore-provider ┼──► core sharedprefs-provider┤ sample ─────────────┘ ``` -------------------------------- ### Successful Build Result Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/fixture-report-2026-05-17.md Indicates a successful build with configuration cache entry stored and no actionable tasks failing. ```text BUILD SUCCESSFUL in 26s 42 actionable tasks: 42 executed Configuration cache entry stored. ``` -------------------------------- ### DataStoreConfigValueProvider Initialization Source: https://github.com/androidbroadcast/featured/wiki/Providers Initialize a DataStoreConfigValueProvider for persisting flag overrides on Android. Requires the 'featured-datastore-provider' dependency. ```kotlin import androidx.datastore.preferences.core.PreferenceDataStoreFactory import dev.androidbroadcast.featured.datastore.DataStoreConfigValueProvider val dataStore = PreferenceDataStoreFactory.create { context.dataStoreFile("feature_flags.preferences_pb") } val configValues = ConfigValues( localProvider = DataStoreConfigValueProvider(dataStore), ) ``` -------------------------------- ### Run All Tests for Featured Compose Source: https://github.com/androidbroadcast/featured/blob/main/featured-compose/CLAUDE.md Executes all tests within the featured-compose module. This command is useful for ensuring the integrity of the compose module before or after making changes. ```bash ./gradlew :featured-compose:allTests ``` -------------------------------- ### Implement Custom LocalConfigValueProvider Source: https://github.com/androidbroadcast/featured/wiki/Providers Implement the `LocalConfigValueProvider` interface to create a custom local configuration backend. This allows for writable and observable local storage for configuration values. ```kotlin class MyLocalProvider : LocalConfigValueProvider { override suspend fun get(param: ConfigParam): ConfigValue? { /* ... */ } override fun observe(param: ConfigParam): Flow> { /* ... */ } override suspend fun set(param: ConfigParam, value: T) { /* ... */ } override suspend fun resetOverride(param: ConfigParam) { /* ... */ } override suspend fun clear() { /* ... */ } } ``` -------------------------------- ### Apply Code Formatting Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Automatically fix code formatting issues according to the project's standards using Spotless. This command applies the necessary formatting changes. ```bash ./gradlew spotlessApply ``` -------------------------------- ### NSUserDefaultsConfigValueProvider Initialization Source: https://github.com/androidbroadcast/featured/wiki/Providers Initialize an NSUserDefaultsConfigValueProvider for iOS/macOS. Requires the 'featured-nsuserdefaults-provider' dependency. Supports String, Int, Long, Float, Double, Boolean types. ```kotlin import dev.androidbroadcast.featured.nsuserdefaults.NSUserDefaultsConfigValueProvider // Standard user defaults val provider = NSUserDefaultsConfigValueProvider() // Custom suite (e.g. for App Groups) val provider = NSUserDefaultsConfigValueProvider(suiteName = "com.example.app.flags") val configValues = ConfigValues(localProvider = provider) ``` -------------------------------- ### InMemoryConfigValueProvider Initialization Source: https://github.com/androidbroadcast/featured/wiki/Providers Initialize an in-memory provider for unit tests or Compose previews. Values are lost when the process terminates. ```kotlin val configValues = ConfigValues( localProvider = InMemoryConfigValueProvider(), ) ``` -------------------------------- ### Experiment Command Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md This command executes a specific integration test for the AC-5a experiment. It targets a test that removes the fallback dependency and injects a marker into the generated Proguard rules. ```bash ./gradlew :featured-gradle-plugin:test \ --tests "dev.androidbroadcast.featured.gradle.FeaturedPluginIntegrationTest.AC5A experiment - assembleRelease with fallback removed and marker injected" ``` -------------------------------- ### Import FeaturedCore Module Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Import the main module for FeaturedCore functionality in your Swift code. ```swift import FeaturedCore ``` -------------------------------- ### Configure iOS Project with Swift Package Manager Source: https://github.com/androidbroadcast/featured/wiki/Installation Add the Featured package to your Xcode project or Package.swift file. Ensure FeaturedCore is listed as a dependency for your target. ```swift Package.swift dependencies: [ .package( url: "https://github.com/AndroidBroadcast/Featured", from: "" ) ], targets: [ .target( name: "YourTarget", dependencies: [ .product(name: "FeaturedCore", package: "Featured"), ] ) ] ``` -------------------------------- ### Relevant Task Graph Slice Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md This output shows a slice of the executed task graph from the experiment. It is used to verify the execution order of tasks, particularly `:generateProguardRules` relative to `:mergeReleaseGeneratedProguardFiles` and `:minifyReleaseWithR8`. ```text :resolveFeatureFlags SUCCESS (position 2) :extractProguardFiles SUCCESS (position 5) :generateProguardRules SUCCESS (position 23) :mergeReleaseGeneratedProguardFiles SUCCESS (position 46) :minifyReleaseWithR8 SUCCESS (position 47) ``` -------------------------------- ### Verify Code Coverage Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to verify code coverage for the 'core' module, which requires a minimum of 90% line coverage. ```bash ./gradlew :core:koverVerify ``` -------------------------------- ### JavaPreferencesConfigValueProvider Initialization Source: https://github.com/androidbroadcast/featured/wiki/Providers Initialize a JavaPreferencesConfigValueProvider for JVM/Desktop environments. Requires the 'featured-javaprefs-provider' dependency. Supports String, Int, Long, Float, Double, Boolean types. ```kotlin import dev.androidbroadcast.featured.javaprefs.JavaPreferencesConfigValueProvider val provider = JavaPreferencesConfigValueProvider() // Or with a custom node: val provider = JavaPreferencesConfigValueProvider( node = Preferences.userRoot().node("com/example/myapp/flags") ) val configValues = ConfigValues(localProvider = provider) ``` -------------------------------- ### Run Shrinker Tests Source: https://github.com/androidbroadcast/featured/wiki/Android-DCE-R8 Execute the tests within the 'featured-shrinker-tests' module to verify that the generated R8 rules correctly perform dead-code elimination. ```bash ./gradlew :featured-shrinker-tests:test ``` -------------------------------- ### Generate Featured Registry (Aggregator Only) Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Aggregator-only Gradle task that produces GeneratedFeaturedRegistry.kt, listing all ConfigParam objects across modules. ```bash generateFeaturedRegistry ``` -------------------------------- ### TestKit Execution Parameters Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md These are the parameters used internally by the TestKit when running the experiment. They include enabling configuration cache, verbose info logging, and stack traces for debugging. ```bash assembleRelease --configuration-cache --info --stacktrace ``` -------------------------------- ### Generate HTML Code Coverage Report Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Command to generate an HTML report for code coverage of the 'core' module. ```bash ./gradlew :core:koverHtmlReport ``` -------------------------------- ### Implement Custom RemoteConfigValueProvider Source: https://github.com/androidbroadcast/featured/wiki/Providers Implement the `RemoteConfigValueProvider` interface to create a custom remote configuration backend. This involves defining how to fetch values from your backend and how to retrieve them. ```kotlin class MyRemoteProvider : RemoteConfigValueProvider { override suspend fun fetch(activate: Boolean) { /* fetch from your backend */ } override suspend fun get(param: ConfigParam): ConfigValue? { /* ... */ } override fun observe(param: ConfigParam): Flow> { /* ... */ } } ``` -------------------------------- ### Symlink xcconfig to Xcode Project Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig Use this command to create a symbolic link to the generated xcconfig file. This approach ensures the link is resolved automatically on every build. ```bash ln -sf ../../shared/build/featured/FeatureFlags.generated.xcconfig \ iosApp/Configuration/FeatureFlags.generated.xcconfig ``` -------------------------------- ### Wire Aggregator Output to Source Set Source: https://github.com/androidbroadcast/featured/blob/main/CLAUDE.md Manually wire the aggregator's output into a source set. This is necessary because the plugin cannot assume the build environment (KMP, AGP, or plain JVM). ```kotlin kotlin.sourceSets.getByName("commonMain").kotlin.srcDir( tasks.named("generateFeaturedRegistry").map { it.outputs.files.singleFile.parentFile } ) ``` -------------------------------- ### Automate xcconfig Generation with Run Script Phase Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig Add a Run Script build phase to your Xcode target to automate the generation and copying of the xcconfig file before compilation. Ensure it runs on every build by setting 'Based on dependency analysis' to Off. ```bash cd "${SRCROOT}/.." ./gradlew :shared:generateXcconfig --quiet cp shared/build/featured/FeatureFlags.generated.xcconfig \ iosApp/Configuration/FeatureFlags.generated.xcconfig ``` -------------------------------- ### Code Coverage Verification and Reporting Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Verify code coverage for the core module and generate an HTML report. The core module requires a minimum of 90% line coverage. ```bash ./gradlew :core:koverVerify ./gradlew :core:koverHtmlReport ``` -------------------------------- ### Generate xcconfig Gradle Task Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig Run this Gradle task to generate the xcconfig file for Swift compilation conditions. The output file is typically located in the build directory of the module containing your feature flag declarations. ```bash ./gradlew :shared:generateXcconfig ``` -------------------------------- ### Check --info Log for Marker Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md Searches the --info log for mentions of the generated rules file. Expects only the plugin's generation log line, not R8's consumption. ```bash grep "proguard-featured" --info log ``` -------------------------------- ### Copy xcconfig to Xcode Project Source: https://github.com/androidbroadcast/featured/wiki/iOS-DCE-xcconfig Use this command to copy the generated xcconfig file to a stable path within your Xcode project tree. This approach requires running the copy command after every 'generateXcconfig' invocation. ```bash cp shared/build/featured/FeatureFlags.generated.xcconfig \ iosApp/Configuration/FeatureFlags.generated.xcconfig ``` -------------------------------- ### Observe Configuration Changes with AsyncStream Source: https://github.com/androidbroadcast/featured/wiki/iOS-Usage Observe changes to a configuration parameter using an AsyncStream, which bridges Kotlin Flows. This is useful for reactive updates within a Task tied to a view's lifetime. ```swift for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) { updateUI(configValue.value) } ``` ```swift .task { for await configValue in configValues.observe(param: FeatureFlags.shared.newCheckout) { isNewCheckoutEnabled = configValue.value } } ``` -------------------------------- ### Verify Merge Task Output Directory Source: https://github.com/androidbroadcast/featured/blob/main/docs/cc-verification/agp-propagation-check-2026-05-16.md Checks the output directory for the merge task. Expected to be empty, indicating no files were produced. ```text build/intermediates/generated_proguard_file/release/mergeReleaseGeneratedProguardFiles/ (empty — no files produced) ``` -------------------------------- ### Apply Plugin and Declare Local Flags in Feature Module Source: https://github.com/androidbroadcast/featured/wiki/Multi-Module-Setup Apply the 'dev.androidbroadcast.featured' plugin and declare local flags within the 'featured' block in a feature module's build script. ```kotlin // :feature:checkout/build.gradle.kts plugins { id("dev.androidbroadcast.featured") // … other plugins } featured { localFlags { boolean("checkout_new_flow", default = false) { description = "Enable the redesigned checkout flow" category = "checkout" expiresAt = "2026-09-01" } } } ``` ```kotlin // :feature:profile/build.gradle.kts plugins { id("dev.androidbroadcast.featured") } featured { localFlags { boolean("profile_v2", default = false) { description = "Enable the new profile screen" category = "profile" } } } ``` -------------------------------- ### Use FakeConfigValues for Previews Source: https://github.com/androidbroadcast/featured/blob/main/featured-compose/README.md Employ FakeConfigValues within @Preview composables to simulate flag states without affecting runtime behavior. ```kotlin @Preview @Composable fun MyScreenPreview() { val fakeFlags = FakeConfigValues(MyFlags.newCheckout to true) CompositionLocalProvider(LocalConfigValues provides fakeFlags) { MyScreen() } } ``` -------------------------------- ### Run Android Instrumentation Tests Source: https://github.com/androidbroadcast/featured/blob/main/CONTRIBUTING.md Execute Android instrumentation tests. This requires a connected Android device or an emulator to run. ```bash ./gradlew :core:connectedAndroidTest ``` -------------------------------- ### Add featured-testing as Test Implementation Source: https://github.com/androidbroadcast/featured/blob/main/featured-testing/README.md Include the featured-testing library as a test dependency in your project. This should only be used for testing and not included in production builds. ```kotlin testImplementation("dev.androidbroadcast.featured:featured-testing") ``` -------------------------------- ### Build Registry with Aggregator Plugin Source: https://github.com/androidbroadcast/featured/wiki/Debug-UI For multi-module projects, apply the featured aggregator plugin and declare feature modules. This automatically generates a registry of all flags. ```kotlin plugins { id("dev.androidbroadcast.featured") id("dev.androidbroadcast.featured.application") } dependencies { featuredAggregation(project(":feature-checkout")) featuredAggregation(project(":feature-profile")) // Modules with enum flags also need a regular implementation dep: implementation(project(":feature-checkout")) } // Wire the generated source set: kotlin.sourceSets.commonMain.kotlin.srcDir( layout.buildDirectory.dir("generated/featured/commonMain"), ) ``` -------------------------------- ### Create Fake ConfigValues for Testing Source: https://github.com/androidbroadcast/featured/wiki/Best-Practices Use `fakeConfigValues` from the `featured-testing` library in unit tests to create an in-memory configuration. This avoids persistent storage side effects and allows for simulating flag changes. ```kotlin import dev.androidbroadcast.featured.testing.fakeConfigValues // Build a ConfigValues with specific initial values val configValues = fakeConfigValues { set(GeneratedLocalFlags.newCheckoutFlow, true) set(GeneratedLocalFlags.darkTheme, false) } // Read the initial value val value = configValues.getValue(GeneratedLocalFlags.newCheckoutFlow) // true // Simulate a flag change mid-test configValues.override(GeneratedLocalFlags.newCheckoutFlow, false) // … assert the code reacted to the updated value ``` ```kotlin import dev.androidbroadcast.featured.testing.fake val configValues = ConfigValues.fake { set(GeneratedLocalFlags.newCheckoutFlow, true) } ``` -------------------------------- ### Applying and Resetting Flag Overrides (Kotlin) Source: https://github.com/androidbroadcast/featured/wiki/Reading-Flags-Kotlin Demonstrates how to apply a temporary local override to a flag, reverting to the stored or default value, and clearing all overrides. Overrides take precedence over provider values and survive remote fetches. ```kotlin // Apply a local override configValues.override(GeneratedLocalFlags.newCheckout, true) // Revert to the stored or default value configValues.resetOverride(GeneratedLocalFlags.newCheckout) // Clear all local overrides configValues.clearOverrides() ```