Mobiilikehitys Flutterilla · Oppitunti

Build-variantit ja ympäristöasetukset

Määritä dev-, staging- ja prod-variantit ympäristökohtaisilla resursseilla ja Dart-define-asetuksilla.

Oppitunti 1/413 vaihetta

Build-variantit ja ympäristöasetukset on ilmainen Mobiilikehitys Flutterilla-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Mobiilikehitys Flutterilla-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Mobiilikehitys Flutterilla-kurssilla on yhteensä 4 oppituntia.

Miksi build-flavorit ovat tärkeitä

Tuotantokäyttöön tarkoitettu Flutter-sovellus harvoin keskustelee vain yhden taustajärjestelmän kanssa. Tarvitset dev-version, joka osoittaa paikalliseen tai staging-rajapintaan, staging-version laadunvarmistukseen sekä viimeistellyn prod-version sovelluskauppaa varten.

  • Flavorit ovat nimettyjä build-variantteja, jotka voivat poiketa toisistaan sovellustunnisteen, kuvakkeen, nimen ja allekirjoituksen osalta.
  • Ympäristöasetukset ovat tietoja, jotka kukin flavor syöttää sovellukseen: perus-URL-osoitteet, ominaisuusliput ja API-avaimet.

Tavoitteena on asentaa dev-, staging- ja prod-versiot rinnakkain yhdelle laitteelle siten, että ne ovat täysin erillisiä eikä niitä voi sekoittaa keskenään.

Kaksi kerrosta: natiivit flavorit ja Dart-define

Selkeä toteutus erottaa kaksi asiaa:

  • Natiivit flavorit (Androidin productFlavors, iOS:n schemes/xcconfig) hallitsevat sovelluksen identiteettiä: pakettitunnistetta, näyttönimeä ja kuvaketta.
  • Dart-define-arvot hallitsevat suorituksenaikaista määritystä, jonka Dart-koodi lukee: API-URL-osoitetta, ympäristön nimeä ja lokitasoa.

Natiivien flavorien ansiosta dev-, staging- ja prod-versiot voivat olla laitteella rinnakkain erillisillä tunnisteilla, kuten com.acme.app.dev. Dart-define pitää salaisuudet ja URL-osoitteet poissa lähdekoodivarastosta ja kiinnittää niiden arvot käännösaikana.

Tyyppiturvallisen ympäristö-enumin määrittäminen

Aloita Dartissa määrittämällä yksi totuuden lähde olemassa oleville ympäristöille. Enum estää kirjoitusvirheet ja mahdollistaa kaikkien tapausten kattavan switch-käsittelyn.

Tämä koodikatkelma on puhdasta Dartia ilman Flutter-riippuvuutta, joten se toimii kaikkialla.

enum Environment { dev, staging, prod }

String labelFor(Environment env) {
  switch (env) {
    case Environment.dev:
      return 'Development';
    case Environment.staging:
      return 'Staging';
    case Environment.prod:
      return 'Production';
  }
}

void main() {
  for (final env in Environment.values) {
    print('${env.name} -> ${labelFor(env)}');
  }
}

Dart-definen lukeminen käännösaikana

Flutter tarjoaa käännösaikaiset vakiot String.fromEnvironment-, bool.fromEnvironment- ja int.fromEnvironment-metodien kautta. Välität ne komennolla --dart-define koontivaiheessa.

  • Arvot sisällytetään binääriin; niitä EI lueta laitteelta suorituksen aikana.
  • Anna aina defaultValue, jotta puuttuva määritys epäonnistuu ennakoitavasti.

Koska nämä ovat const-arvoja, niitä voidaan arvioida myös const-konteksteissa.

const String apiUrl = String.fromEnvironment(
  'API_URL',
  defaultValue: 'http://localhost:8080',
);

const String envName = String.fromEnvironment(
  'ENV',
  defaultValue: 'dev',
);

const bool analyticsEnabled = bool.fromEnvironment(
  'ANALYTICS',
  defaultValue: false,
);

void main() {
  print('env=$envName url=$apiUrl analytics=$analyticsEnabled');
}

AppConfig-olion muodostaminen

Jos hajautat String.fromEnvironment-kutsuja ympäri koodikantaa, menetät hallinnan. Keskitytä ne yhteen muuttumattomaan AppConfig-olioon, jonka ratkaiset kerran ja välität eteenpäin.

Näin kaikki flavorien väliset erot ovat yhdessä tarkastettavassa paikassa, ja testaaminen on helppoa: muodostat vain AppConfig-olion haluamillasi arvoilla.

class AppConfig {
  final String envName;
  final String apiUrl;
  final bool analyticsEnabled;

  const AppConfig({
    required this.envName,
    required this.apiUrl,
    required this.analyticsEnabled,
  });

  factory AppConfig.fromEnvironment() {
    return const AppConfig(
      envName: String.fromEnvironment('ENV', defaultValue: 'dev'),
      apiUrl: String.fromEnvironment('API_URL',
          defaultValue: 'http://localhost:8080'),
      analyticsEnabled:
          bool.fromEnvironment('ANALYTICS', defaultValue: false),
    );
  }

  bool get isProd => envName == 'prod';
}

void main() {
  final config = AppConfig.fromEnvironment();
  print('Running in ${config.envName} -> ${config.apiUrl}');
}

Dart-definen välittäminen komentorivillä

Syötät määritykset, kun suoritat sovelluksen tai muodostat koontiversion. Jokainen --dart-define asettaa yhden avaimen. Yhdistä se natiivin flavorin kanssa käyttämällä komentoa --flavor.

  • --flavor staging valitsee natiivin variantin (tunnisteen, kuvakkeen ja nimen).
  • --dart-define syöttää arvot AppConfig-oliolle.

Näiden kirjoittaminen joka kerta altistaa virheille, joten tiimit tallentavat ne skripteihin tai tiedostoihin (seuraavassa näkymässä).

flutter run \
  --flavor staging \
  --target lib/main.dart \
  --dart-define=ENV=staging \
  --dart-define=API_URL=https://staging.api.acme.com \
  --dart-define=ANALYTICS=true

flutter build apk \
  --release \
  --flavor prod \
  --dart-define=ENV=prod \
  --dart-define=API_URL=https://api.acme.com \
  --dart-define=ANALYTICS=true

Dart-define-from-file selkeyttää CI:tä

Pitkät --dart-define-ketjut ovat hauraita. Flutter tukee komentoa --dart-define-from-file, joka lukee avain–arvo-parit JSON- tai .env-tyylisestä tiedostosta.

  • Pidä yksi tiedosto ympäristöä kohden: config/dev.json, config/staging.json, config/prod.json.
  • Vie ei-salaiset tiedostot versionhallintaan; syötä salaiset tiedostot CI:ssä suojatusta säilöstä.

Esimerkki tiedostosta config/prod.json ja sen käytöstä näytetään. Avaimet vastaavat yksi yhteen fromEnvironment-hakuja.

// config/prod.json
{
  "ENV": "prod",
  "API_URL": "https://api.acme.com",
  "ANALYTICS": true
}

// Invocation:
// flutter build appbundle --release \
//   --flavor prod \
//   --dart-define-from-file=config/prod.json

Android: productFlavors

Androidilla flavorit määritellään tiedostossa android/app/build.gradle. Kukin flavor ylikirjoittaa sovellustunnisteen päätteen ja nimen, jotta koontiversiot voidaan asentaa rinnakkain.

  • applicationIdSuffix liitetään perustunnisteen perään (esimerkiksi com.acme.app.dev).
  • resValue ylikirjoittaa käynnistyskuvakkeen nimen kunkin flavorin osalta.

flavorDimensions-määritys vaaditaan ennen flavorien luettelointia.

android {
    flavorDimensions "env"
    productFlavors {
        dev {
            dimension "env"
            applicationIdSuffix ".dev"
            resValue "string", "app_name", "Acme Dev"
        }
        staging {
            dimension "env"
            applicationIdSuffix ".staging"
            resValue "string", "app_name", "Acme Staging"
        }
        prod {
            dimension "env"
            resValue "string", "app_name", "Acme"
        }
    }
}

iOS: Schemes ja xcconfig

iOS:llä flavorit yhdistetään Xcoden schemeihin, joiden taustalla ovat build-määritykset ja .xcconfig-tiedostot. Kukin scheme asettaa erillisen PRODUCT_BUNDLE_IDENTIFIER-tunnisteen ja näyttönimen.

  • Luo määritykset, kuten Debug-dev ja Release-prod.
  • Kullekin ympäristölle tarkoitettu .xcconfig ylikirjoittaa pakettitunnisteen ja DISPLAY_NAME-arvon, joka luetaan Info.plist-tiedostossa muodossa $(DISPLAY_NAME).

Flutter yhdistää komennon --flavor prod Xcoden schemeen nimeltä prod.

// ios/Flutter/staging.xcconfig
#include "Generated.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = com.acme.app.staging
DISPLAY_NAME = Acme Staging

// In Info.plist:
// <key>CFBundleDisplayName</key>
// <string>$(DISPLAY_NAME)</string>

Ympäristökohtaiset resurssit

Flavorit tarvitsevat usein erilaisia resursseja: värillisen DEV-bannerin, staging-sovelluksen kuvakkeen tai erilaisen Firebase-määrityksen.

  • Järjestä resurssit kansioihin, kuten assets/dev/ ja assets/prod/, ja valitse polku suorituksen aikana AppConfig-olion perusteella.
  • Natiivien kuvakkeiden tapauksessa Android ratkaisee kansion src/dev/res automaattisesti; iOS käyttää ympäristökohtaisia resurssiluetteloita.
  • Sijoita flavor-kohtainen google-services.json polkuun android/app/src/<flavor>/.

Dart-puolella resurssipolku johdetaan yksinkertaisesti aktiivisesta ympäristöstä.

class AssetPaths {
  final String envName;
  const AssetPaths(this.envName);

  String get logo => 'assets/$envName/logo.png';
  String get configBanner =>
      envName == 'prod' ? '' : 'assets/$envName/banner.png';
}

void main() {
  for (final env in ['dev', 'staging', 'prod']) {
    final paths = AssetPaths(env);
    print('$env logo: ${paths.logo}');
  }
}

AppConfigin yhdistäminen main()-funktioon

Ratkaise määritys kerran käynnistyksen yhteydessä ja aseta se widget-puun saataville (InheritedWidget-olion, providerin tai service locatorin kautta). Vältä fromEnvironment-kutsujen tekemistä syvällä widgeteissä.

  • Muodosta määritys ennen kutsua runApp.
  • Näytä ei-prod-koontiversioissa näkyvä ympäristöbanneri, jotta laadunvarmistuksessa ei synny sekaannuksia.

Alla oleva koodikatkelma käyttää Flutter-kehystä, joten sitä ei voi suorittaa sellaisenaan, mutta se näyttää suositellun käynnistyskohdan.

import 'package:flutter/material.dart';

void main() {
  final config = AppConfig.fromEnvironment();
  runApp(MyApp(config: config));
}

class MyApp extends StatelessWidget {
  final AppConfig config;
  const MyApp({super.key, required this.config});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Acme (${config.envName})',
      debugShowCheckedModeBanner: !config.isProd,
      home: const Scaffold(body: Center(child: Text('Home'))),
    );
  }
}

Pikatarkistus: missä määritys sijaitsee

Olet määrittänyt dev-, staging- ja prod-flavorit. Testaa ymmärryksesi siitä, miten Dart-define-arvot toimivat.

Kertaus

Rakensit täydellisen flavor- ja ympäristömääritysstrategian:

  • Kaksi kerrosta: natiivit flavorit (Androidin productFlavors, iOS:n scheme/xcconfig) määrittävät sovelluksen identiteetin; dart-define määrittää suorituksenaikaiset asetukset.
  • Tyyppiturvallisuus: yksi Environment-enum ja muuttumaton AppConfig, joka ratkaistaan kerran kutsulla AppConfig.fromEnvironment().
  • Syöttäminen: välitä --flavor yhdessä --dart-define-komennon kanssa tai laajenna ratkaisua siististi komennolla --dart-define-from-file=config/<env>.json.
  • Resurssit: ympäristökohtaiset kansiot ja natiivien resurssien ylikirjoitukset kuvakkeille, bannereille ja Firebase-määrityksille.
  • Keskeinen havainto: dart-define käsitellään käännösaikana ja sisällytetään binääriin, joten määrityksen muuttaminen edellyttää aina uutta koontiversiota.

Hyöty on se, että dev-, staging- ja prod-versiot voidaan asentaa rinnakkain, täysin erillisinä ja toisiinsa sekoittumattomina.

Aloita maksutta

Opi Dart tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
22
Oppitunnit
88

Usein kysytyt kysymykset

Onko oppitunti ”Build-variantit ja ympäristöasetukset” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Mobiilikehitys Flutterilla-oppimispolun 3 oppituntia, myös oppitunnin “Build-variantit ja ympäristöasetukset”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Mobiilikehitys Flutterilla-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Build-variantit ja ympäristöasetukset”?

Määritä dev-, staging- ja prod-variantit ympäristökohtaisilla resursseilla ja Dart-define-asetuksilla. Harjoittelet Mobiilikehitys Flutterilla-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Mobiilikehitys Flutterilla-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Mobiilikehitys Flutterilla-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Build-variantit ja ympäristöasetukset”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Mobiilikehitys Flutterilla-oppitunnilla?

Kyllä. Jokainen Mobiilikehitys Flutterilla-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Build-variantit ja ympäristöasetukset
  2. Automaattiset putket Fastlanella ja GitHub Actionsilla
  3. Kaatumisraportointi ja symboloidut pinojäljet
  4. Remote Config, ominaisuusliput ja vaiheistetut julkaisut
← Takaisin: Mobiilikehitys Flutterilla