{"id":73900,"date":"2025-08-13T12:04:28","date_gmt":"2025-08-13T06:34:28","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=73900"},"modified":"2025-10-13T15:06:52","modified_gmt":"2025-10-13T09:36:52","slug":"feature-toggles-remote-config-and-a-b-testing-in-android-ship-faster-without-fear-2","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/feature-toggles-remote-config-and-a-b-testing-in-android-ship-faster-without-fear-2\/","title":{"rendered":"Feature Toggles, Remote Config, and A\/B Testing in Android: Ship Faster Without Fear"},"content":{"rendered":"<div class=\"max-w-4xl mx-auto bg-white p-6 md:p-12 rounded-2xl shadow-xl space-y-8\">\n<header class=\"text-center mb-10\">\n<div class=\"mceTemp\"><\/div>\n<p class=\"text-3xl sm:text-4xl font-extrabold text-blue-900 leading-tight\"><strong><span style=\"font-size: 16px;\">Imagine you&#8217;re an app developer. You&#8217;ve worked hard on a new feature, but just before it&#8217;s ready, a bug appears. You have a hard choice: either you delay the launch to fix the bug, or you release the feature with the bug and hope it doesn&#8217;t cause problems.<\/span><\/strong><\/p>\n<\/header>\n<section class=\"space-y-4\">\n<p class=\"text-lg text-gray-700 leading-relaxed\">This happens because usually, when you release new code, the new features are turned on right away. A better way to work is a method called <strong class=\"font-semibold text-blue-800\">progressive delivery<\/strong>. This lets you release your code and your features at different times. This means you can ship code all the time while having full control over when and how new features are turned on.<\/p>\n<p class=\"text-lg text-gray-700 leading-relaxed\">To do this, you can use three important tools: Feature Toggles, Remote Config, and A\/B Testing. By understanding and using them, you can build a more reliable release process that uses real user data.<\/p>\n<\/section>\n<p><!-- The Foundation: Feature Toggles --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">1. The Foundation: Feature Toggles<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">A <strong class=\"font-semibold text-blue-800\">Feature Toggle<\/strong> is like a switch in your app&#8217;s code. You can use it to turn a new feature on or off. You can build all the code for a new feature, but the switch lets you decide when people can actually see and use it. This way, you can put the new code into your app, but keep the feature hidden until you are ready.<\/p>\n<p class=\"font-semibold text-gray-900\">Without a toggle:<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">startNewCheckoutFlow()<\/code><\/pre>\n<\/div>\n<p class=\"font-semibold text-gray-900\">With a toggle:<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">if (isFeatureEnabled(FeatureToggle.NewCheckout)) {\r\n    startNewCheckoutFlow()\r\n} else {\r\n    startLegacyCheckoutFlow()\r\n}<\/code><\/pre>\n<\/div>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Key Benefits:<\/h4>\n<ul class=\"list-disc list-inside space-y-2 text-lg text-gray-700 leading-relaxed pl-4\">\n<li><strong class=\"font-semibold text-blue-800\">Safe Testing:<\/strong> You can hide new, experimental features behind a toggle and only show them to a small group of internal testers.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Less Risk:<\/strong> If a new feature causes a big crash or problem, you can turn it off instantly with a toggle. This saves you from having to release a whole new app update just to fix the issue.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Continuous Delivery:<\/strong> Developers can add new code to the main app often, knowing that the new feature will stay hidden until it&#8217;s ready for everyone.<\/li>\n<\/ul>\n<\/section>\n<p><!-- The Brains: Remote Config --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">2. The Brains: Remote Config<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">While a simple on\/off switch in your code is good, it&#8217;s not very flexible. You can&#8217;t change it without releasing a new app update. **Remote Config** is a tool that lets you control these switches from a central place on the internet. This means you can turn features on or off, or change things like a welcome message, without making users update their app.<\/p>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Remote Config allows you to change more than just on\/off switches:<\/h4>\n<ul class=\"list-disc list-inside space-y-2 text-lg text-gray-700 leading-relaxed pl-4\">\n<li><strong class=\"font-semibold text-blue-800\">Boolean flags:<\/strong> Turn features on or off (`enable_new_ui`).<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Strings:<\/strong> Update UI text or messages (`home_title`).<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Numbers:<\/strong> Change a setting for your app (`max_cart_items`).<\/li>\n<li><strong class=\"font-semibold text-blue-800\">JSON objects:<\/strong> Store more complex information for special settings.<\/li>\n<\/ul>\n<p class=\"text-lg text-gray-700 leading-relaxed\">The most popular tool for this on Android is <strong class=\"font-semibold text-blue-800\">Firebase Remote Config<\/strong>, which is a powerful and simple platform with features like rolling out to a percentage of users, targeting specific groups, and A\/B testing.<\/p>\n<\/section>\n<p><!-- How it Works: The Progressive Delivery Flow --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">How it Works: The Progressive Delivery Flow<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">This diagram shows how your Android app, the remote configuration, and the user all connect:<\/p>\n<div class=\"relative code-block-container\">\n<div id=\"attachment_76267\" style=\"width: 310px\" class=\"wp-caption alignleft\"><img aria-describedby=\"caption-attachment-76267\" decoding=\"async\" loading=\"lazy\" class=\"size-medium wp-image-76267\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config-300x200.png\" alt=\"Flow diagram of Remote Config\" width=\"300\" height=\"200\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config-300x200.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config-1024x683.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config-768x512.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config-624x416.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/09\/firebase-remote-config.png 1536w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><p id=\"caption-attachment-76267\" class=\"wp-caption-text\">Firebase Remote config<\/p><\/div>\n<\/div>\n<p class=\"text-lg text-gray-700 leading-relaxed\">The app gets its settings from the server, which you manage using the Firebase Console. The app then uses these settings to decide what features to show the user.<\/p>\n<\/section>\n<p><!-- The Experimentation Engine: A\/B Testing --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">3. The Experimentation Engine: A\/B Testing<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">A\/B Testing is a way to find out which version of a feature works best. You can show one version to some users (Group A) and a different version to other users (Group B). Then you compare the results to see which one is more successful, like which one gets more clicks or sales.<\/p>\n<p class=\"text-lg text-gray-700 leading-relaxed\">Remote Config gives you the ability to show different versions of a feature to different users. A\/B testing is the process of setting up and looking at the results of this test. This process removes guesswork and helps you check your ideas with real user data.<\/p>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">The A\/B Testing Process:<\/h4>\n<ol class=\"list-decimal list-inside space-y-2 text-lg text-gray-700 leading-relaxed pl-4\">\n<li><strong class=\"font-semibold text-blue-800\">Have an Idea:<\/strong> What do you want to test? For example, &#8220;A green checkout button will get 10% more purchases than a blue one.&#8221;<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Create Versions:<\/strong> Use Remote Config to make a &#8220;Control&#8221; group (Version A) with the blue button and an &#8220;Experiment&#8221; group (Version B) with the green button.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Show to Users:<\/strong> The A\/B testing tool randomly puts users into one of the groups.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Track Results:<\/strong> Use a tool like Firebase Analytics to track your goal (e.g., button clicks) for each group.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Analyze:<\/strong> The tool will tell you which version was the winner based on the data.<\/li>\n<li><strong class=\"font-semibold text-blue-800\">Rollout:<\/strong> You can then turn on the winning version for all users with a single click.<\/li>\n<\/ol>\n<\/section>\n<p><!-- Getting Started with Firebase in Android (Step-by-Step) --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">Getting Started with Firebase in Android (Step-by-Step)<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">Here&#8217;s a simple guide on how to get started using Kotlin and Firebase.<\/p>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Step 1: Add the Firebase SDK<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">First, you need to add the Firebase SDK to your app&#8217;s `build.gradle.kts` file.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">\/\/ build.gradle.kts (Module: app)\r\ndependencies {\r\n    \/\/ ... other dependencies\r\n    implementation(\"com.google.firebase:firebase-config-ktx\")\r\n    implementation(platform(\"com.google.firebase:firebase-bom:32.7.0\")) \/\/ Recommended for versioning\r\n}<\/code><\/pre>\n<\/div>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Step 2: Set Default Values<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">You should always set a default value for your features. These are used when the app first launches and hasn&#8217;t yet connected to the internet to get new settings, or if there&#8217;s no internet connection at all.<\/p>\n<p class=\"text-lg text-gray-700 leading-relaxed\">Create a new XML file at `res\/xml\/remote_config_defaults.xml`.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">&lt;!-- res\/xml\/remote_config_defaults.xml --&gt;\r\n&lt;defaultsMap&gt;\r\n    &lt;entry&gt;\r\n        &lt;key&gt;enable_new_ui&lt;\/key&gt;\r\n        &lt;value&gt;false&lt;\/value&gt;\r\n    &lt;\/entry&gt;\r\n    &lt;entry&gt;\r\n        &lt;key&gt;welcome_message&lt;\/key&gt;\r\n        &lt;value&gt;\"Hello from defaults!\"&lt;\/value&gt;\r\n    &lt;\/entry&gt;\r\n&lt;\/defaultsMap&gt;<\/code><\/pre>\n<\/div>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Step 3: Get &amp; Activate the Config<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">In your app&#8217;s main code, get the latest settings from the server.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">\/\/ A good place to do this is when your app first starts.\r\nval remoteConfig = Firebase.remoteConfig\r\n\r\n\/\/ Set how often the app should check for new settings (e.g., 1 hour)\r\nval configSettings = remoteConfigSettings {\r\n    minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) 0 else 3600\r\n}\r\nremoteConfig.setConfigSettingsAsync(configSettings)\r\n\r\n\/\/ Set the default values from the XML file\r\nremoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)\r\n\r\n\/\/ Get the latest settings from the server and use them\r\nremoteConfig.fetchAndActivate()\r\n    .addOnCompleteListener { task -&gt;\r\n        if (task.isSuccessful) {\r\n            val updated = task.result\r\n            Log.d(\"RemoteConfig\", \"Config params updated: $updated\")\r\n        } else {\r\n            Log.e(\"RemoteConfig\", \"Fetch failed.\")\r\n        }\r\n        \/\/ Now you can use the settings, whether they are new or the defaults.\r\n        updateUI()\r\n    }<\/code><\/pre>\n<\/div>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Step 4: Read Flags in Code<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">You can read the flags anywhere in your code after they have been loaded.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">fun updateUI() {\r\n    val remoteConfig = Firebase.remoteConfig\r\n    val isEnabled = remoteConfig.getBoolean(\"enable_new_ui\")\r\n    val welcomeMessage = remoteConfig.getString(\"welcome_message\")\r\n\r\n    \/\/ Use the values to control what the user sees\r\n    if (isEnabled) {\r\n        \/\/ Show the new user interface\r\n    } else {\r\n        \/\/ Show the old user interface\r\n    }\r\n\r\n    val textView = findViewById&lt;TextView&gt;(R.id.welcome_text_view)\r\n    textView.text = welcomeMessage\r\n}<\/code><\/pre>\n<\/div>\n<\/section>\n<p><!-- Advanced Strategies &amp; Best Practices --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">Advanced Strategies &amp; Best Practices<\/h3>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Structuring Feature Flags (Clean &amp; Scalable)<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">For bigger apps, using a helper function with a list of all your flags is a good way to keep your code clean and organized.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">enum class FeatureToggle(val key: String) {\r\n    NewDashboard(\"feature_new_dashboard\"),\r\n    CheckoutV2(\"feature_checkout_v2\"),\r\n    DynamicBanner(\"feature_dynamic_banner\")\r\n}\r\n\r\nfun isFeatureEnabled(toggle: FeatureToggle): Boolean {\r\n    return Firebase.remoteConfig.getBoolean(toggle.key)\r\n}<\/code><\/pre>\n<\/div>\n<p class=\"text-lg text-gray-700 leading-relaxed\">This prevents you from having to type the same flag names over and over and helps avoid mistakes.<\/p>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Scalable Rollout Strategy<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">A smart rollout plan lowers risk and lets you test new features with real users before you launch them to everyone.<\/p>\n<div class=\"overflow-x-auto rounded-xl\">\n<table class=\"min-w-full bg-gray-100 divide-y divide-gray-300\">\n<thead class=\"bg-gray-200\">\n<tr>\n<th class=\"px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider rounded-tl-xl\" scope=\"col\">Stage<\/th>\n<th class=\"px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider rounded-tr-xl\" scope=\"col\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"bg-white divide-y divide-gray-200\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">Dev Only<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">The feature is only available to your internal development and test accounts.<\/td>\n<\/tr>\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">Internal QA<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">The feature is turned on for a small group of internal testers.<\/td>\n<\/tr>\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">5% Rollout<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">You release the feature to a small percentage of real users to get early feedback and check for problems.<\/td>\n<\/tr>\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">50% Rollout<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">You slowly give the feature to more users to make sure it&#8217;s stable and works well.<\/td>\n<\/tr>\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">100% Rollout<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">The feature is stable and is turned on for all users.<\/td>\n<\/tr>\n<tr>\n<td class=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">Cleanup<\/td>\n<td class=\"px-6 py-4 text-sm text-gray-700\">After the feature is fully released and stable, you remove the switch and the old code.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h4 class=\"text-xl font-bold text-gray-900 mt-6\">Analytics &amp; Monitoring<\/h4>\n<p class=\"text-lg text-gray-700 leading-relaxed\">To make decisions based on facts, you must link your feature flags to your crash reports and analytics. Firebase Crashlytics and Analytics make this easy.<\/p>\n<div class=\"relative code-block-container\">\n<pre class=\"bg-gray-100 p-4 rounded-xl text-sm overflow-x-auto\"><code class=\"text-gray-800\" style=\"font-family: 'Courier New', monospace; font-size: 16px;\">\/\/ Tell Crashlytics which features are on for the user\r\nCrashlytics.setCustomKey(\"feature_new_dashboard\", isFeatureEnabled(FeatureToggle.NewDashboard))\r\n\r\n\/\/ Track which version of a test a user is in\r\nFirebase.analytics.setUserProperty(\"checkout_variant\", variant)<\/code><\/pre>\n<\/div>\n<\/section>\n<p><!-- Conclusion --><\/p>\n<section class=\"space-y-4\">\n<h3 class=\"text-2xl font-bold text-gray-900 pt-6\">Conclusion<\/h3>\n<p class=\"text-lg text-gray-700 leading-relaxed\">Using Feature Toggles, Remote Config, and A\/B Testing changes the way you build apps for the better. Instead of big, risky releases, you can constantly improve your app based on what you learn. You can try new ideas with a small group of users, turn off bad features right away, and make the app better for everyone.<\/p>\n<p class=\"text-lg text-gray-700 leading-relaxed\">By shipping faster without fear, you can stay ahead of the competition and build a product that your users truly love.<\/p>\n<\/section>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Imagine you&#8217;re an app developer. You&#8217;ve worked hard on a new feature, but just before it&#8217;s ready, a bug appears. You have a hard choice: either you delay the launch to fix the bug, or you release the feature with the bug and hope it doesn&#8217;t cause problems. This happens because usually, when you release [&hellip;]<\/p>\n","protected":false},"author":2121,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":53},"categories":[518],"tags":[4845],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/73900"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/2121"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=73900"}],"version-history":[{"count":8,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/73900\/revisions"}],"predecessor-version":[{"id":76707,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/73900\/revisions\/76707"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=73900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=73900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=73900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}