diff --git a/core/src/commonMain/kotlin/dev/androidbroadcast/featured/TypeConverter.kt b/core/src/commonMain/kotlin/dev/androidbroadcast/featured/TypeConverter.kt index 7c17063..db3efc5 100644 --- a/core/src/commonMain/kotlin/dev/androidbroadcast/featured/TypeConverter.kt +++ b/core/src/commonMain/kotlin/dev/androidbroadcast/featured/TypeConverter.kt @@ -50,6 +50,22 @@ public interface TypeConverter { * converter.fromString("UNKNOWN") // throws IllegalArgumentException * ``` * + * ## Compatible providers + * + * Pass the returned converter to `registerConverter` on any of these providers before the first + * read or write of an enum flag: + * + * - `DataStoreConfigValueProvider.registerConverter(enumConverter())` + * - `JavaPreferencesConfigValueProvider.registerConverter(enumConverter())` + * - `SharedPreferencesProviderConfig.registerConverter(enumConverter())` + * + * `FirebaseConfigValueProvider` handles enums automatically via reflection — no registration + * is required. + * + * **iOS caveat:** `NSUserDefaultsConfigValueProvider` does not support enums at this time — + * it has no converter API. Use a `String` flag as a workaround on iOS and convert the raw + * value to your enum manually at the call site. + * * @param T The enum class to convert. * @return A [TypeConverter] that round-trips [T] by enum constant name. */ diff --git a/featured-gradle-plugin/README.md b/featured-gradle-plugin/README.md new file mode 100644 index 0000000..e241f7d --- /dev/null +++ b/featured-gradle-plugin/README.md @@ -0,0 +1,54 @@ +# featured-gradle-plugin + +Gradle plugin for the [Featured](../README.md) configuration management library. + +Apply it to a module and declare flags in the `featured { }` DSL block; the plugin generates +typed `ConfigParam` objects, `ConfigValues` extension functions, and R8 shrinker rules. + +## Enum flags + +Declare an enum-typed flag with the `enum(...)` DSL function: + +```kotlin +// build.gradle.kts +featured { + localFlags { + enum( + key = "checkout_variant", + typeFqn = "com.example.CheckoutVariant", + default = "LEGACY", + ) + } +} +``` + +### Runtime converter requirement (Android / JVM) + +Storage-backed local providers serialize values as strings. Before the first read or write of +an enum flag you must register an `enumConverter` on the provider, otherwise the provider +throws `IllegalArgumentException` synchronously. + +Affected providers and the required registration call: + +| Provider | Registration | +|---|---| +| `DataStoreConfigValueProvider` | `provider.registerConverter(enumConverter())` | +| `JavaPreferencesConfigValueProvider` | `provider.registerConverter(enumConverter())` | +| `SharedPreferencesProviderConfig` | `provider.registerConverter(enumConverter())` | + +`FirebaseConfigValueProvider` handles enums automatically via reflection — no registration +is needed. + +```kotlin +// Runtime wiring example (DataStore) +val provider = DataStoreConfigValueProvider(dataStore).apply { + registerConverter(enumConverter()) +} +val configValues = ConfigValues(localProvider = provider) +``` + +### iOS caveat + +`NSUserDefaultsConfigValueProvider` does not support enums at this time — it has no converter +API. Use a `String` flag as a workaround on iOS and convert the raw value to your enum manually +at the call site. diff --git a/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagContainer.kt b/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagContainer.kt index 5003422..994a516 100644 --- a/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagContainer.kt +++ b/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagContainer.kt @@ -84,8 +84,49 @@ public class FlagContainer { /** * Declares an enum-typed feature flag. * - * Enum flags are intentionally excluded from R8 `-assumevalues` DCE rules — the value - * cannot be assumed at build time (it is resolved at runtime from providers). + * The plugin generates a typed `ConfigParam` backed by this declaration. Enum flags are + * intentionally excluded from R8 `-assumevalues` DCE rules — the value cannot be assumed at + * build time (it is resolved at runtime from providers). + * + * ## Runtime converter requirement (Android / JVM) + * + * Storage-backed local providers serialize values as strings and require an explicit + * [enumConverter] registration before the first read or write of this flag. Without it the + * provider throws [IllegalArgumentException] synchronously. Affected providers: + * + * - `DataStoreConfigValueProvider` + * - `JavaPreferencesConfigValueProvider` + * - `SharedPreferencesProviderConfig` + * + * Firebase Remote Config (`FirebaseConfigValueProvider`) handles enums automatically via + * reflection — no `registerConverter` call is needed there. + * + * **iOS caveat:** `NSUserDefaultsConfigValueProvider` does not support enums at this time — + * it has no converter API. Use a `String` flag as a workaround on iOS and convert the raw + * value to your enum manually at the call site. + * + * ## Example + * + * ```kotlin + * // Gradle DSL — declaration + * featured { + * localFlags { + * enum( + * key = "checkout_variant", + * typeFqn = "com.example.CheckoutVariant", + * default = "LEGACY", + * ) + * } + * } + * ``` + * + * ```kotlin + * // Runtime — required wiring for non-Firebase local providers + * val provider = DataStoreConfigValueProvider(dataStore).apply { + * registerConverter(enumConverter()) + * } + * val configValues = ConfigValues(localProvider = provider) + * ``` * * @param key The configuration key string (e.g. `"checkout_variant"`). * @param typeFqn The fully-qualified Kotlin class name of the enum (e.g. `"com.example.CheckoutVariant"`).