Mobilutvikling med Flutter · leksjon

Remote Config, feature flags og trinnvise utrullinger

Slå funksjoner av og på eksternt, og rull ut endringer gradvis uten å sende inn appen på nytt.

Leksjon 4 av 413 trinn

Remote Config, feature flags og trinnvise utrullinger er en gratis leksjon i Mobilutvikling med Flutter på CoddyKit. Dette er leksjon 4 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Mobilutvikling med Flutter, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hvorfor fjernkonfigurasjon

Godkjenningsrunder i appbutikker tar lang tid. Hvis en funksjon sendes ut med feil, kan det ta flere dager før en hurtigreparasjon når brukerne. Fjernkonfigurasjon kobler utrulling av koden fra aktivering av den.

  • Funksjonsflagg sperrer kodebaner bak en boolsk verdi du styrer fra en server.
  • Fjernkonfigurasjon leverer justerbare verdier (strenger, tall og JSON) uten en ny build.
  • Trinnvis utrulling gjør en endring synlig for en stadig større andel brukere.

I Flutter er firebase_remote_config det vanligste verktøyet, men de samme mønstrene gjelder for LaunchDarkly, ConfigCat eller din egen backend.

Modellere et flagg lokalt

Før du kobler til en SDK, bør du modellere flaggene som ren Dart, slik at resten av appen aldri trenger å forholde seg til rå strenger. Et typet konfigurasjonsobjekt gjør standardverdiene tydelige og gjør koden testbar.

Dette er ren Dart med fornuftige standardverdier innebygd — akkurat det du sender ut hvis nettverket ikke er tilgjengelig.

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}');
}

Sette opp Firebase Remote Config

Når Firebase er initialisert, henter du singletonen FirebaseRemoteConfig, angir standardverdier i appen og konfigurerer henteatferden via RemoteConfigSettings.

  • fetchTimeout setter en øvre grense for hvor lenge en henting kan vente.
  • minimumFetchInterval begrenser hvor ofte det hentes, slik at kvotene respekteres. Bruk en liten verdi i debug og flere timer i produksjon.

Standardverdier sikrer at appen oppfører seg fornuftig før den første vellykkede hentingen.

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;
}

Hente og aktivere

Remote Config skiller mellom henting (laste ned verdier til en lokal hurtigbuffer) og aktivering (gjøre de hentede verdiene gjeldende). Hjelpemetoden fetchAndActivate() gjør begge deler og returnerer om nye verdier ble aktivert.

Legg alltid kallet i en omslutning: En nettverksfeil skal falle tilbake til de sist aktiverte verdiene eller standardverdiene i appen — aldri krasje oppstartsforløpet.

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');
  }
}

Lese typede verdier

Remote Config lagrer alt som strenger internt, men tilbyr typede hentere: getBool, getInt, getDouble og getString. Map dem tilbake til AppConfig, slik at resten av appen forblir typet.

Samle denne map­pingen på ett sted. Hvis navnet på en nøkkel endres, trenger du bare å rette det én gang.

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'),
  );
}

Skjule og vise brukergrensesnitt med et flagg

Et funksjonsflagg bør styre ett enkelt beslutningspunkt. Les det én gang nær toppen av widgettreet (eller fra en provider), og velg riktig gren.

Hold sperren grunn: Velg gren basert på flagget, ikke dypt inne i forretningslogikken. Da blir det enkelt å fjerne flagget senere.

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

Parse JSON-basert konfigurasjon

For mer innholdsrike datamengder kan du lagre en JSON-streng i én enkelt nøkkel og dekode den. Da kan ett flagg inneholde et helt strukturert eksperiment — temaer, terskelverdier og sorterte lister — uten at du må legge til dusinvis av nøkler.

Nedenfor finner du frittstående Dart som viser mønsteret for dekoding og tilbakefall, slik du ville brukt det på 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}');
}

Trinnvis utrulling etter prosentandel

Ved trinnvis utrulling gjøres en funksjon tilgjengelig for for eksempel 1 % av brukerne, deretter 10 %, 50 % og til slutt 100 % — mens du følger med på krasj- og metrikkdashbordene på hvert trinn. Firebase Remote Config gjør dette på serversiden med prosentbetingelser basert på en stabil, tilfeldig brukergruppe.

Det viktigste kravet er at gruppeplasseringen må være stabil. En bruker som er tildelt utrullingen, må forbli med i den på tvers av økter. Ellers flimrer brukergrensesnittet, og metrikkene blir meningsløse.

Stabil gruppering på klientsiden

Hvis du lager din egen backend i stedet for å bruke Firebase, implementerer du grupperingen på klientsiden. Hash en stabil bruker-ID til en verdi i [0, 100), og sammenlign den med utrullingsterskelen. Den samme ID-en havner alltid i den samme gruppen.

Denne deterministiske hashing-metoden er selve kjernen i trinnvis utrulling og A/B-splitting.

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)}');
}

Nødbrytere og sikre standardverdier

Det mest verdifulle flagget er en nødbryter: en ekstern boolsk verdi som umiddelbart deaktiverer en risikabel funksjon uten en ny release. To regler gjør nødbrytere pålitelige:

  • Den sikre tilstanden må være standardverdien. En nødbryter bør ha standardverdien false (funksjonen er av), slik at en mislykket henting aldri aktiverer den risikable kodebanen ved et uhell.
  • Les flagget ved beslutningspunktet hver gang, ikke bare én gang ved oppstart. Da trer en endring i kraft ved neste oppdatering av konfigurasjonen.

For Remote Config bør du planlegge en oppdatering når appen gjenopptas, slik at en nødbryter blir spredd i løpet av én syklus i forgrunnen.

// 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);
}

Lytte etter sanntidsoppdateringer

Nyere Firebase Remote Config støtter sanntidsoppdateringer: en strøm som utløses når serveren publiserer nye verdier, slik at du ikke trenger å vente på neste planlagte henting. Du må fortsatt kalle activate() for å gjøre dem gjeldende.

Bruk dette for nødbrytere der minutter betyr noe. Kombiner lytteren med setState/ugyldiggjøring av provider for å bygge de berørte widgetene på nytt.

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
  });
}

Hurtigsjekk

Test forståelsen din av trygg utform­ing av utrullinger.

Oppsummering

Du har lært hvordan du kan sende ut funksjoner deaktivert og styre dem eksternt:

  • Modeller flagg som en typet AppConfig med tydelige standardverdier.
  • Initialiser Remote Config med setDefaults og tilpassede RemoteConfigSettings, og kjør deretter fetchAndActivate() på en robust måte.
  • Les typede verdier og styr brukergrensesnittet ved ett enkelt, grunt beslutningspunkt; send innholdsrike datamengder som JSON-strenger.
  • Gjennomfør trinnvis utrulling med stabil prosentbasert gruppering, slik at brukerne konsekvent er med eller ikke med.
  • La alle nødbrytere ha den sikre tilstanden som standard, og bruk sanntidsoppdateringer samt oppdatering når appen gjenopptas, slik at endringer sprer seg raskt.

Tilsammen lar dette deg koble utrulling fra release og håndtere hendelser uten en ny runde i appbutikken.

Gratis å komme i gang

Lær deg Dart med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
22
Leksjoner
88

Ofte stilte spørsmål

Er leksjonen «Remote Config, feature flags og trinnvise utrullinger» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Mobilutvikling med Flutter, inkludert «Remote Config, feature flags og trinnvise utrullinger», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva lærer jeg i «Remote Config, feature flags og trinnvise utrullinger»?

Slå funksjoner av og på eksternt, og rull ut endringer gradvis uten å sende inn appen på nytt. Du øver på Mobilutvikling med Flutter med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Mobilutvikling med Flutter?

Ingen tidligere erfaring er nødvendig. Mobilutvikling med Flutter på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Remote Config, feature flags og trinnvise utrullinger»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Mobilutvikling med Flutter-leksjonen?

Ja. Alle Mobilutvikling med Flutter-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Build-varianter og miljøkonfigurasjon
  2. Automatiserte pipelines med Fastlane og GitHub Actions
  3. Krasjrapportering og symboliserte stack traces
  4. Remote Config, feature flags og trinnvise utrullinger
← Tilbake til Mobilutvikling med Flutter