Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn Build

Flutter flavors: one codebase, three apps, zero copy-pasted config

The bad version of environment handling looks like this: const bool isProd = false ; final apiBase = isProd ? 'https://api.example.com' : 'https://staging.api.example.com' ; It works until someone ships with the flag flipped the wrong way, or until QA needs staging and production installed side by side and discovers both have the same bundle id. Flavors fix both problems at the build layer: three separate installable apps, each compiled with its own configuration baked in. The Dart side, first Start here because it is the part that determines everything else. // lib/config/app_config.dart enum Flavor { dev, staging, prod } final class AppConfig { const AppConfig ._({ required this .flavor, required this .apiBase, required this .appName, }); final Flavor flavor; final String apiBase; final String appName; static const _flavorName = String . fromEnvironment ( 'FLAVOR' , defaul...

Shrinking a Flutter app: where the megabytes actually are

The app size conversation usually starts after a stakeholder compares the APK to a competitor’s and asks why a to-do list is 40 MB. The engineering response is often to start deleting packages, which is both the most painful lever and usually not the one that matters. Flutter apps have a size floor: the engine, the Dart runtime, Skia or Impeller, and the ICU data. That floor is real and you cannot remove it. Everything above it is yours, and in most apps I have looked at, the majority of “yours” is assets and shipped-but-unused native code, not Dart. So the first move is not to delete anything. It is to measure. Measure first: --analyze-size flutter build apk --release --analyze-size flutter build appbundle --release --analyze-size flutter build ipa --release --analyze-size This prints a summary and writes a JSON file. Open that file in DevTools’ app size tool — it gives you a treemap where the boxes are proportional to bytes, broken down by package, by asset, and by...

Code generation in Dart: build_runner without the frustration

You add json_serializable , run dart run build_runner build , and get: Conflicting outputs were detected and the build will be terminated. You run it with --delete-conflicting-outputs , it works, and you type that flag forever afterwards without knowing what it deleted. That is the typical relationship developers have with build_runner, and it is worth fixing, because the tool is more predictable than it looks. The model: one asset in, one asset out build_runner is not a script runner. It is a build system over assets — files identified as package:name|path . Every builder declares which extensions it consumes and which it produces, and build_runner constructs a graph from that. json_serializable says: for every .dart , maybe produce a .g.dart . freezed says: for every .dart , maybe produce a .freezed.dart . Because outputs are keyed by path, two builders that claim the same output path conflict — and so does one builder whose previous output is still on disk from a run with d...