0Pricing
Flutter Mobile Development · Ders

Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar

Özellikleri uzaktan açıp kapatın ve uygulamayı yeniden göndermeden değişiklikleri kademeli olarak yayınlayın.

Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar, CoddyKit'te ücretsiz bir Flutter Mobile Development dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Flutter Mobile Development öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Flutter Mobile Development kursu toplamda 4 dersten oluşur.

Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.

Why Remote Config

App store review cycles are slow. If a feature ships broken, you may wait days for a hotfix to reach users. Remote configuration decouples shipping the code from turning it on.

  • Feature flags gate code paths behind a boolean you control from a server.
  • Remote config delivers tunable values (strings, numbers, JSON) without a new build.
  • Staged rollouts expose a change to a growing percentage of users.

In Flutter the common tool is firebase_remote_config, but the same patterns apply to LaunchDarkly, ConfigCat, or your own backend.

Modeling a Flag Locally

Before wiring any SDK, model your flags as plain Dart so the rest of the app never touches raw strings. A typed config object keeps defaults explicit and makes the code testable.

This is pure Dart with sensible defaults baked in — exactly what you ship if the network is unavailable.

class AppConfig {
  final bool newCheckoutEnabled;
  final int maxUploadMb;
  final String welcomeMessage;

  const AppConfig({
    this.newCheckoutEnabled = false,
    this.maxUploadMb = 10,
    this.welcomeMessage = 'Welcome!',
  });
}

void main() {
  const defaults = AppConfig();
  print('checkout: ${defaults.newCheckoutEnabled}');
  print('maxUploadMb: ${defaults.maxUploadMb}');
  print('welcome: ${defaults.welcomeMessage}');
}

Firebase Remote Config Setup

With Firebase initialized, you grab the FirebaseRemoteConfig singleton, set in-app defaults, and configure fetch behavior via RemoteConfigSettings.

  • fetchTimeout caps how long a fetch waits.
  • minimumFetchInterval throttles fetches to respect quotas. Use a small value in debug, hours in production.

Defaults guarantee the app behaves sanely before the first successful fetch.

import 'package:firebase_remote_config/firebase_remote_config.dart';

Future<FirebaseRemoteConfig> initRemoteConfig() async {
  final rc = FirebaseRemoteConfig.instance;

  await rc.setConfigSettings(RemoteConfigSettings(
    fetchTimeout: const Duration(seconds: 10),
    minimumFetchInterval: const Duration(hours: 6),
  ));

  await rc.setDefaults(const {
    'new_checkout_enabled': false,
    'max_upload_mb': 10,
    'welcome_message': 'Welcome!',
  });

  return rc;
}

Fetch and Activate

Remote Config separates fetch (download values into a local cache) from activate (make the fetched values live). The convenience method fetchAndActivate() does both and returns whether new values were activated.

Always wrap the call: a network failure should fall back to the last activated values or your in-app defaults — never crash the launch path.

Future<void> refreshConfig(FirebaseRemoteConfig rc) async {
  try {
    final updated = await rc.fetchAndActivate();
    if (updated) {
      // New values are now live; rebuild dependent UI.
      print('Remote config activated with new values');
    }
  } catch (e) {
    // Offline or quota hit: keep last-known-good values.
    print('Remote config fetch failed, using cached/defaults: $e');
  }
}

Reading Typed Values

Remote Config stores everything as strings under the hood but exposes typed getters: getBool, getInt, getDouble, getString. Map them back into your AppConfig so the rest of the app stays typed.

Centralize this mapping in one place. If a key name changes, you fix it once.

import 'package:firebase_remote_config/firebase_remote_config.dart';

AppConfig readConfig(FirebaseRemoteConfig rc) {
  return AppConfig(
    newCheckoutEnabled: rc.getBool('new_checkout_enabled'),
    maxUploadMb: rc.getInt('max_upload_mb'),
    welcomeMessage: rc.getString('welcome_message'),
  );
}

Gating UI Behind a Flag

A feature flag should guard a single decision point. Read it once near the top of the widget tree (or from a provider) and branch.

Keep the gate shallow: branch on the flag, not deep inside business logic, so removing the flag later is a clean deletion.

Widget buildCheckout(BuildContext context, AppConfig config) {
  if (config.newCheckoutEnabled) {
    return const NewCheckoutScreen();
  }
  return const LegacyCheckoutScreen();
}

Parsing JSON-Valued Config

For richer payloads, store a JSON string in a single key and decode it. This lets one flag carry a whole structured experiment — themes, thresholds, ordered lists — without adding dozens of keys.

Below is standalone Dart showing the decode-and-fallback pattern you would apply to rc.getString('promo_banner').

import 'dart:convert';

class PromoBanner {
  final String text;
  final int priority;
  PromoBanner(this.text, this.priority);
}

PromoBanner parsePromo(String raw) {
  try {
    final map = jsonDecode(raw) as Map<String, dynamic>;
    return PromoBanner(
      map['text'] as String? ?? '',
      map['priority'] as int? ?? 0,
    );
  } catch (_) {
    return PromoBanner('', 0); // malformed JSON -> safe default
  }
}

void main() {
  final ok = parsePromo('{"text":"Summer Sale","priority":5}');
  print('${ok.text} (${ok.priority})');
  final bad = parsePromo('not-json');
  print('fallback text empty: ${bad.text.isEmpty}');
}

Staged Rollout by Percentage

A staged rollout exposes a feature to, say, 1% of users, then 10%, then 50%, then 100% — watching crash and metric dashboards at each step. Firebase Remote Config does this server-side with percentage conditions based on a stable, randomized user bucket.

The key requirement: bucketing must be stable. A user assigned to the rollout must stay in it across sessions, otherwise the UI flickers and metrics are meaningless.

Stable Client-Side Bucketing

If you roll your own backend instead of Firebase, you implement bucketing on the client. Hash a stable user id into a value in [0, 100) and compare against the rollout threshold. The same id always lands in the same bucket.

This deterministic hashing is the heart of staged rollouts and A/B splits.

int bucketOf(String userId) {
  // Simple stable hash -> 0..99
  var hash = 0;
  for (final code in userId.codeUnits) {
    hash = (hash * 31 + code) & 0x7fffffff;
  }
  return hash % 100;
}

bool isInRollout(String userId, int percent) {
  return bucketOf(userId) < percent;
}

void main() {
  const id = 'user-42';
  print('bucket: ${bucketOf(id)}');
  print('in 10% rollout: ${isInRollout(id, 10)}');
  print('stable on retry: ${bucketOf(id) == bucketOf(id)}');
}

Kill Switches and Safe Defaults

The most valuable flag is a kill switch: a remote boolean that instantly disables a risky feature without a release. Two rules make kill switches reliable:

  • The safe state must be the default. A kill switch should default to false (feature off) so a failed fetch never accidentally enables the risky path.
  • Read the flag at the decision point every time, not once at startup, so flipping it takes effect on the next config refresh.

For Remote Config, schedule a refresh on app resume so a kill switch propagates within one foreground cycle.

// Default OFF => a fetch failure leaves the risky feature disabled.
bool experimentalSyncEnabled(AppConfig config) {
  return config.newCheckoutEnabled; // example risky path
}

void onAppResumed(FirebaseRemoteConfig rc) {
  // Re-fetch so a flipped kill switch reaches the user quickly.
  refreshConfig(rc);
}

Listening for Real-Time Updates

Newer Firebase Remote Config supports real-time updates: a stream that fires when the server publishes new values, so you do not have to wait for the next scheduled fetch. You still call activate() to make them live.

Use this for kill switches where minutes matter. Combine the listener with setState/provider invalidation to rebuild affected widgets.

import 'package:firebase_remote_config/firebase_remote_config.dart';

void subscribeToUpdates(FirebaseRemoteConfig rc, void Function() onChanged) {
  rc.onConfigUpdated.listen((event) async {
    await rc.activate();
    onChanged(); // e.g. trigger a UI rebuild
  });
}

Quick Check

Test your understanding of safe rollout design.

Recap

You learned how to ship features dark and control them remotely:

  • Model flags as a typed AppConfig with explicit defaults.
  • Initialize Remote Config with setDefaults and tuned RemoteConfigSettings, then fetchAndActivate() defensively.
  • Read typed values and gate UI at a single shallow decision point; carry rich payloads as JSON strings.
  • Run staged rollouts with stable percentage bucketing so users stay consistently in or out.
  • Make every kill switch default to its safe state, and use real-time updates plus on-resume refresh so flips propagate fast.

Together these let you decouple deploy from release and respond to incidents without an app-store round trip.

Sıkça Sorulan Sorular

“Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar” dersi ücretsiz mi?

Evet — “Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Flutter Mobile Development kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Flutter Mobile Development kursu toplamda 4 dersten oluşur.

“Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar” dersinde ne öğreneceğim?

Özellikleri uzaktan açıp kapatın ve uygulamayı yeniden göndermeden değişiklikleri kademeli olarak yayınlayın. Flutter Mobile Development ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Flutter Mobile Development öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Flutter Mobile Development, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.

“Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Flutter Mobile Development dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Flutter Mobile Development dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Derleme Çeşitleri ve Ortam Yapılandırması
  2. Fastlane ve GitHub Actions ile Otomatik İş Akışları
  3. Çökme Raporlama ve Sembolleri Çözülmüş Yığın İzleri
  4. Uzaktan Yapılandırma, Özellik Bayrakları ve Aşamalı Yayınlar
← Flutter Mobile Development Sayfasına Dön