A powerful development tool that stores app settings and feature toggles in an external application, ensuring they persist across clean data operations and app reinstalls. Perfect for Android developers who need reliable feature flag management during development.
The toggles-flow library provides a reactive approach to feature toggles using Kotlin Flow, making it easy to respond to configuration changes in real-time.
Add the toggles-flow library to your project:
implementation("se.eelde.toggles:toggles-flow:0.0.3")import se.eelde.toggles.flow.Toggles
class MyActivity : AppCompatActivity() {
private val toggles = Toggles(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Boolean toggle with default value
lifecycleScope.launch {
toggles.toggle("enable_new_feature", false).collect { isEnabled ->
if (isEnabled) {
showNewFeature()
} else {
showOldFeature()
}
}
}
// String configuration
lifecycleScope.launch {
toggles.toggle("api_endpoint", "https://api.example.com").collect { endpoint ->
configureApiClient(endpoint)
}
}
// Integer configuration
lifecycleScope.launch {
toggles.toggle("max_retry_count", 3).collect { retryCount ->
setMaxRetries(retryCount)
}
}
}
}Install the companion app to manage your feature toggles:
- Download from Google Play Store
- View source code on GitHub
The app stores your settings behind a content provider, ensuring configurations persist across app reinstalls and clean data operations.
enum class LogLevel { DEBUG, INFO, WARN, ERROR }
lifecycleScope.launch {
toggles.toggle("log_level", LogLevel::class.java, LogLevel.INFO).collect { level ->
logger.setLevel(level)
}
}@HiltViewModel
class FeatureViewModel @Inject constructor(
application: Application,
private val toggles: Toggles
) : ViewModel() {
val featureEnabled = toggles.toggle("new_dashboard", false)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = false
)
}For simple one-time toggle fetching without reactive updates. Similar API to Android's SharedPreferences.
implementation("se.eelde.toggles:toggles-prefs:0.0.2")import se.eelde.toggles.prefs.TogglesPreferences
val togglesPrefs = TogglesPreferences(context)
val isEnabled = togglesPrefs.getBoolean("feature_toggle_key", false)Note: Consider using toggles-flow for reactive updates and better integration with modern Android development patterns.
Low-level library for communicating with the toggles application via content provider. Generally not needed unless you're implementing custom toggle management.
implementation("se.eelde.toggles:toggles-core:0.0.3")For release builds, you have two options to disable the toggles functionality:
- Use the provided no-op libraries (recommended for convenience)
- Implement your own no-op variant of the
TogglesorTogglesPreferencesinterface
The no-op versions return default values immediately without connecting to the Toggles app, eliminating unnecessary overhead in production builds.
To enable feature toggles in debug builds while automatically disabling them in release builds, configure your dependencies based on build type:
dependencies {
debugImplementation("se.eelde.toggles:toggles-flow:0.0.3")
releaseImplementation("se.eelde.toggles:toggles-flow-noop:0.0.3")
}dependencies {
debugImplementation("se.eelde.toggles:toggles-prefs:0.0.2")
releaseImplementation("se.eelde.toggles:toggles-prefs-noop:0.0.2")
}The no-op libraries provide identical APIs but with minimal implementations:
- They do not connect to the Toggles app
- They immediately return the default values you provide
- They add zero runtime overhead to your release builds
- They maintain the same API, so no code changes are needed
// In debug builds: reads from Toggles app, observes changes
// In release builds: immediately returns 'false', never changes
toggles.toggle("enable_new_feature", false).collect { isEnabled ->
// Debug: reflects actual toggle value from Toggles app
// Release: always receives 'false' (the default value)
}- Development flexibility: Full feature toggle control during development
- Production efficiency: Zero overhead in release builds
- Seamless transition: Same code works in both debug and release
- No app dependency: Release builds don't require the Toggles app to be installed
If you prefer more control or want to customize the behavior, you can implement your own no-op version:
class MyNoOpToggles(context: Context) : Toggles {
override fun toggle(key: String, defaultValue: Boolean): Flow<Boolean> = flowOf(defaultValue)
override fun toggle(key: String, defaultValue: Int): Flow<Int> = flowOf(defaultValue)
override fun toggle(key: String, defaultValue: String): Flow<String> = flowOf(defaultValue)
override fun <T : Enum<T>> toggle(key: String, type: Class<T>, defaultValue: T): Flow<T> = flowOf(defaultValue)
}class MyNoOpTogglesPreferences(context: Context) : TogglesPreferences {
override fun getBoolean(key: String, defValue: Boolean): Boolean = defValue
override fun getInt(key: String, defValue: Int): Int = defValue
override fun getString(key: String, defValue: String): String = defValue
override fun <T : Enum<T>> getEnum(key: String, type: Class<T>, defValue: T): T = defValue
}Then configure your dependency injection or factory to provide the appropriate implementation based on build type. The provided no-op libraries exist for convenience so you don't have to write this boilerplate yourself.
We welcome contributions! Please follow these steps to contribute:
- Fork the repository on GitHub.
- Create a new branch for your feature or bugfix.
- Write your code and tests.
- Submit a pull request with a clear description of your changes.
If you encounter any issues or have questions, please open an issue on GitHub.
-
Clone the repository:
git clone https://github.com/eelde/toggles.git cd toggles -
Build the project:
./gradlew build
-
Run tests:
./gradlew test -
Install the sample app to test the libraries:
./gradlew :toggles-sample:installDebug
- Android Studio Arctic Fox or newer
- JDK 17 or higher
- Android SDK API 21+ (for using the libraries)
- Android SDK API 35 (for building the sample app)


