Complete operational, architectural, and internals reference for the Flutter UI toolkit monorepo. Covers the full stack from framework widgets through the Impeller rendering engine to platform embedders, the
flutterCLI, build systems, CI infrastructure, and contribution workflows. Written for administrators, DevOps engineers, platform engineers, architects, and contributors working at the SDK level.
1. Architecture Overview
Flutter is Google's open-source UI toolkit for building natively compiled applications across mobile (Android, iOS), web, desktop (Windows, macOS, Linux), and embedded platforms from a single Dart codebase. The flutter/flutter monorepo (14,714 files, 21.3M characters of source, "massive" complexity tier) contains everything needed to develop, build, test, and deploy Flutter applications: the framework layer, the rendering engine, the flutter CLI tool, platform embedders, testing infrastructure, benchmarks, code generation tools, CI configuration, and example applications.
Flutter's architecture is a layered system where each layer depends only on the layer below it. Applications are written in Dart, compiled to native ARM/x64 code for mobile and desktop (AOT in release) or to JavaScript/Wasm for web. The engine, written primarily in C++, provides low-level rendering via Impeller (the modern rendering backend replacing Skia on most platforms), text layout, Dart runtime hosting, and platform channel communication. Platform embedders are native code (Java/Kotlin for Android, Objective-C/Swift for iOS/macOS, C++ for Windows/Linux, Dart/JS for web) that host the engine within each operating system's windowing and event system.
The key architectural insight is that Flutter does not use platform UI widgets. Instead, it renders every pixel directly via its own rendering pipeline, giving complete control over appearance and behavior across platforms while maintaining native performance through ahead-of-time compilation and GPU-accelerated rendering.
Layered Architecture Diagram
┌─────────────────────────────────────────────────────────┐
│ YOUR DART APP │
│ (StatelessWidget, StatefulWidget) │
├─────────────────────────────────────────────────────────┤
│ FRAMEWORK LAYER │
│ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌─────────┐ │
│ │ Material │ │Cupertino │ │ Widgets │ │Semantics│ │
│ │(150+ w.) │ │ (50+ w.) │ │(core tree) │ │ (a11y) │ │
│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ └────┬────┘ │
│ └─────────────┴─────────────┤ │ │
│ ┌──────────┐ ┌───────────┐ ┌────┴──────┐ ┌────┴────┐ │
│ │Rendering │ │ Animation │ │ Painting │ │Gestures │ │
│ │(RenderObj│ │(Tween, │ │(TextPaint,│ │(tap,drag│ │
│ │ RenderBox│ │ Curves, │ │ BoxDecor, │ │ scale, │ │
│ │ layout) │ │ Contrlr) │ │ borders) │ │ force) │ │
│ └────┬─────┘ └─────┬─────┘ └─────┬─────┘ └────┬────┘ │
│ └──────────────┴─────────────┤ │ │
│ ┌──────────┐ ┌───────────┐ ┌─────┴─────┐ ┌────┴────┐ │
│ │Foundation│ │ Scheduler │ │ Services │ │ Physics │ │
│ │(Key, │ │(FrameCB, │ │(clipboard,│ │(spring, │ │
│ │ Notifier)│ │ Ticker) │ │ keyboard) │ │friction)│ │
│ └────┬─────┘ └─────┬─────┘ └─────┬─────┘ └────┬────┘ │
├───────┴──────────────┴─────────────┴────────────┴───────┤
│ dart:ui BINDINGS │
│ (sky/packages/sky_engine — Dart↔Engine) │
├─────────────────────────────────────────────────────────┤
│ ENGINE LAYER (C++) │
│ ┌────────────┐ ┌───────────┐ ┌────────────────────┐ │
│ │ Impeller │ │Dart VM / │ │ Platform Channels │ │
│ │ Rendering │ │ Runtime │ │ (MethodChannel, │ │
│ │ (GPU, HAL, │ │ (JIT/AOT) │ │ EventChannel, │ │
│ │ tessellator)│ │ │ │ BasicMessage) │ │
│ └──────┬──────┘ └─────┬─────┘ └────────┬───────────┘ │
│ └──────────────┴────────────────┤ │
│ ┌──────────────┐ ┌──────────┐ ┌──────┴──────┐ │
│ │ Text/ICU │ │ GPU │ │ Shell │ │
│ │ (txt/) │ │ Abstract │ │ (common) │ │
│ │ │ │ (lib/gpu)│ │ 37 files │ │
│ └──────────────┘ └──────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ EMBEDDER LAYER (Native) │
│ ┌────────┐ ┌──────┐ ┌──────┐ ┌───────┐ ┌──────┐ │
│ │Android │ │ iOS │ │macOS │ │Windows│ │Linux │ │
│ │Java/ │ │ObjC/ │ │ObjC/ │ │C++/ │ │GTK/ │ │
│ │Kotlin │ │Swift │ │Swift │ │Win32 │ │C++ │ │
│ └────────┘ └──────┘ └──────┘ └───────┘ └──────┘ │
│ ┌──────┐ ┌───────┐ │
│ │ Web │ │Fuchsia│ │
│ │JS/ │ │Zircon │ │
│ │Wasm │ │ │ │
│ └──────┘ └───────┘ │
├─────────────────────────────────────────────────────────┤
│ OPERATING SYSTEM / BROWSER │
│ (Android, iOS, Windows, macOS, Linux, Chrome, etc.) │
└─────────────────────────────────────────────────────────┘
Component Inventory
| Component | Location | Files | Size | Language | Purpose |
|---|---|---|---|---|---|
| Framework | packages/flutter/ |
~430 HIGH | 44K chars (lib) | Dart | Widget tree, rendering, animation, painting, gestures, semantics |
| CLI Tool | packages/flutter_tools/ |
58 (lib/src) | 1.12M chars | Dart | flutter command — build, run, test, doctor, create |
| Engine | engine/src/flutter/ |
~200+ | Multiple dirs | C++ | Impeller, Dart VM hosting, text rendering, GPU abstraction |
| Shell Common | engine/src/flutter/shell/common/ |
37 | 292K chars | C++ | Shared embedding logic across platforms |
| Android Embedder | engine/src/flutter/shell/platform/android/ |
17 (common) | 87K chars | Java/Kotlin | Android platform integration |
| iOS/macOS Embedder | engine/src/flutter/shell/platform/darwin/ |
6 (shared) | 7.5K chars | ObjC/Swift | Apple platform integration |
| Linux Embedder | engine/src/flutter/shell/platform/linux/ |
— | — | C++ (GTK) | Linux desktop integration |
| Web Engine | engine/src/flutter/lib/web_ui/ |
21 (lib) | 212K chars | Dart/JS | Browser-based rendering |
| Web JS Runtime | engine/src/flutter/lib/web_ui/flutter_js/ |
11 | 35K chars | JavaScript | Entrypoint loader, service worker, trusted types |
| Impeller Core | engine/src/flutter/impeller/core/ |
17 | 56K chars | C++ | Modern GPU rendering engine |
| Tessellator | engine/src/flutter/impeller/tessellator/ |
— | 7K chars | Dart FFI | Path tessellation via FFI |
| Test Framework | packages/flutter_test/ |
39 | 896K chars | Dart | Widget testing (WidgetTester, TestWidgetsFlutterBinding) |
| Integration Test | packages/integration_test/ |
— | — | Dart | On-device integration testing |
| Flutter Driver | packages/flutter_driver/ |
— | — | Dart | Legacy integration test driver |
| Golden Tests | packages/flutter_goldens/ |
— | 44K chars | Dart | Pixel-perfect golden file comparison |
| Localizations | packages/flutter_localizations/ |
— | — | Dart | L10n/i18n support |
| Web Plugins | packages/flutter_web_plugins/ |
— | — | Dart | Web plugin registration |
| Gen Defaults | dev/tools/gen_defaults/ |
44 | 193K chars | Dart | Material Design token code generation |
| Gen Keycodes | dev/tools/gen_keycodes/ |
16 | 109K chars | Dart | Keyboard keycode mapping generation |
| Snippets | dev/snippets/ |
6 | 65K chars | Dart | API doc snippet extraction |
| Device Lab | dev/devicelab/ |
— | — | Dart | Automated device testing infrastructure |
| Benchmarks | dev/benchmarks/ |
7+ apps | — | Dart | Performance benchmark applications |
| CI Config | .ci.yaml |
1 | — | YAML | LUCI CI build/test definitions |
| Gradle Plugin | packages/flutter_tools/gradle/ |
— | 12K+22K chars | Kotlin | Android build integration |
| Examples | examples/ |
10+ apps | — | Dart | Sample applications |
Technology Stack
| Technology | Version / Constraint | Usage |
|---|---|---|
| Dart | SDK ^3.10.0-0 | Framework, CLI, app development |
| C++ | C++17 | Engine, Impeller, desktop embedders |
| Java / Kotlin | JDK 21 | Android embedder, Gradle plugin |
| Objective-C / Swift | Xcode latest | iOS and macOS embedders |
| JavaScript / TypeScript | ES6+ | Web engine runtime, service workers |
| CMake | 3.x | Linux and Windows build system |
| Gradle | 8.x+ | Android build system |
| Ninja | Latest | Engine build system |
| GN | Latest | Engine build configuration |
| Python | 3.x | CI scripts, tooling |
| YAML | — | CI configuration, pubspec, analysis options |
Data Flow: Widget Build to Pixels
Widget Tree Element Tree RenderObject Tree
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ MyApp │──build()──▶│MyAppElem │──mount()──▶│ │
│(Widget) │ │(Element) │ │ │
└──┬───────┘ └──┬───────┘ │ │
│ │ │ │
┌──┴───────┐ ┌──┴───────┐ │ RenderView │
│Scaffold │──build()──▶│ScaffoldE │──mount()──▶│ │ │
└──┬───────┘ └──┬───────┘ │ ├─RenderFlex│
│ │ │ │ ├─RenderPa│
┌──┴───────┐ ┌──┴───────┐ │ │ └─RenderBo│
│Column │──build()──▶│ColumnE │──mount()──▶│ └─RenderDec│
└──────────┘ └──────────┘ └──────┬───────┘
│
layout()
│
paint()
▼
Layer Tree
┌──────────┐
│ Transform │
│ ├─Clip │
│ ├─Picture│
│ └─Opacity│
└─────┬────┘
│
composit()
▼
┌──────────────┐
│ Impeller │
│ (GPU cmds) │
└──────┬───────┘
│
▼
┌──────────────┐
│ Screen │
│ (Pixels) │
└──────────────┘
Note
Flutter maintains three parallel trees: the Widget tree (immutable configuration), the Element tree (lifecycle management and identity), and the RenderObject tree (layout and painting). Widgets are lightweight descriptors rebuilt frequently; Elements persist across frames and determine whether to update or replace the corresponding RenderObject. This three-tree architecture is central to Flutter's performance: only the parts of the RenderObject tree that actually changed are re-laid-out and repainted.
Rendering Pipeline Phases
| Phase | Responsibility | Triggered By |
|---|---|---|
| Build | Walk dirty elements, call build(), reconcile child lists |
setState(), markNeedsBuild() |
| Layout | Walk dirty render objects, compute sizes and positions | markNeedsLayout() |
| Compositing Bits | Update needsCompositing flag bottom-up |
Layout changes |
| Paint | Walk dirty render objects, emit display lists into layers | markNeedsPaint() |
| Compositing | Flatten layer tree, upload textures, submit to GPU | Paint changes |
| Semantics | Update accessibility tree for screen readers | markNeedsSemanticsUpdate() |
| Finalize | Dispose unmounted elements, run post-frame callbacks | End of frame |
Key Engine Artifacts
The flutter CLI resolves and manages these engine artifacts during builds and runs:
| Artifact | Purpose |
|---|---|
gen_snapshot |
AOT compiler — compiles Dart to native machine code |
flutter_tester |
Headless test runner for flutter test |
flutter.framework |
iOS framework bundle |
FlutterMacOS.framework |
macOS framework bundle |
flutter_windows.dll |
Windows engine shared library |
libflutter_linux_gtk.so |
Linux engine shared library |
vm_snapshot_data |
Dart VM heap snapshot (release) |
isolate_snapshot_data |
Dart isolate heap snapshot (release) |
icudtl.dat |
ICU internationalization data |
platform_strong.dill |
Platform kernel for compilation |
sky_engine |
dart:ui package implementation |
font-subset |
Font subsetting tool for tree shaking |
const_finder |
Finds const instances for icon tree shaking |
impellerc |
Impeller shader compiler |
libtessellator.so/dylib/dll |
Path tessellation native library |
2. System Requirements
Development Host Requirements
| Platform | Minimum OS | Disk Space | Required Tools |
|---|---|---|---|
| Linux | Ubuntu 20.04+ (64-bit) | 1.6 GB (SDK) + project | bash, curl, file, git 2.x, mkdir, rm, unzip, which, xz-utils, zip |
| macOS | macOS 12 (Monterey)+ | 2.8 GB (SDK) + project | Xcode command line tools, git 2.x |
| Windows | Windows 10 (64-bit) | 1.6 GB (SDK) + project | Git for Windows, PowerShell 5.0+ |
Platform-Specific Build Dependencies
Android Development
| Dependency | Version | Notes |
|---|---|---|
| Android Studio | Latest stable | Provides SDK manager, emulators, Gradle integration |
| Android SDK | API level 36 (v8) | Minimum SDK 21 (Android 5.0) for apps, latest for compilation |
| Android SDK Build-Tools | Latest | Included via SDK manager |
| Android SDK Platform-Tools | Latest | adb, fastboot |
| Android NDK | Latest LTS | Required for plugins with native code |
| JDK | 21 | Required by Gradle — bundled with Android Studio |
| Gradle | 8.x+ | Wrapper included in project templates |
CI-tested device matrix:
| Device / Emulator | API Level | Architecture |
|---|---|---|
| Android Emulator | API 35 | x86_64 |
| Android Emulator | API 36 | x86_64 |
| Pixel 7 Pro | Physical | ARM64 |
| Galaxy S24 | Physical | ARM64 |
iOS / macOS Development
| Dependency | Version | Notes |
|---|---|---|
| Xcode | Latest stable | Includes iOS SDK, simulators, compiler toolchain |
| CocoaPods | 1.16+ | Plugin dependency management (legacy path) |
| Swift Package Manager | Built into Xcode | Plugin dependency management (modern path) |
| iOS Deployment Target | 13.0+ | Minimum for Flutter apps |
| macOS Deployment Target | 10.14+ | Minimum for Flutter desktop |
Important
Xcode 26 introduced Clang dependency scanning changes that can cause build failures (tracked as issue #185210). If you encounter
clang: error: unsupported option '-fdeps-format=p1689'or similar, ensure your Xcode and Flutter SDK are both updated to the latest stable versions.
Web Development
| Dependency | Version | Notes |
|---|---|---|
| Chrome | Latest stable | Required for flutter run -d chrome, DevTools |
| Dart SDK | Bundled with Flutter | Provides dart2js (release) and DDC (debug) compilers |
| Node.js | Optional | Only if using custom service workers or build tooling |
Linux Desktop Development
| Dependency | Package (Ubuntu/Debian) | Purpose |
|---|---|---|
| Clang | clang |
C/C++ compiler |
| CMake | cmake |
Build system |
| Ninja | ninja-build |
Build executor |
| GTK 3.0 | libgtk-3-dev |
Window management, rendering surface |
| GLib 2.0 | libglib2.0-dev |
Core utilities |
| GIO 2.0 | Included with GLib | File/network I/O |
| pkg-config | pkg-config |
Library discovery |
| liblzma | liblzma-dev |
Compression |
| libstdc++ | libstdc++-12-dev |
C++ standard library |
Install all Linux dependencies:
sudo apt update
sudo apt install -y clang cmake ninja-build libgtk-3-dev libglib2.0-dev \
pkg-config liblzma-dev libstdc++-12-dev
Windows Desktop Development
| Dependency | Version | Notes |
|---|---|---|
| Visual Studio 2022 | Latest | "Desktop development with C++" workload required |
| Windows 10 SDK | 10.0.17763.0+ | Included with Visual Studio |
| C++ Build Tools | C++17 support | MSVC v143+ |
| CMake | 3.14+ | Bundled with Visual Studio |
| Ninja | Latest | Bundled with Visual Studio |
Visual Studio workload installation via command line:
vs_installer.exe --add Microsoft.VisualStudio.Workload.NativeDesktop `
--add Microsoft.VisualStudio.Component.VC.CMake.Project `
--includeRecommended
Engine Build Dependencies (Contributor)
Building the Flutter engine from source requires additional dependencies beyond app development:
| Dependency | Purpose |
|---|---|
depot_tools |
Google's build tooling (includes gclient, gn, autoninja) |
| Python 3 | Build scripts, GN wrappers |
| Clang (bundled) | Engine C++ compilation |
| Android NDK r25+ | Android engine builds |
| Xcode | iOS/macOS engine builds |
flutter doctor Validation
Run flutter doctor -v to validate all requirements. The tool checks:
[✓] Flutter (Channel stable, x.y.z, on OS, locale)
[✓] Android toolchain - develop for Android devices (Android SDK x.y)
[✓] Xcode - develop for iOS and macOS (Xcode x.y)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Visual Studio - develop for Windows (Visual Studio x.y)
[✓] Android Studio (version x.y)
[✓] VS Code (version x.y)
[✓] Connected device (N available)
[✓] Network resources
Each checker validates tool presence, version compatibility, and license acceptance. Partial checkmarks ([!]) indicate optional missing components.
3. Configuration Reference
3.1 Flutter SDK Configuration (flutter config)
The flutter config command manages persistent SDK-level settings stored in ~/.flutter_settings (JSON):
| Flag | Type | Default | Purpose |
|---|---|---|---|
--enable-web |
bool | true | Enable web platform |
--enable-linux-desktop |
bool | false | Enable Linux desktop |
--enable-macos-desktop |
bool | false | Enable macOS desktop |
--enable-windows-desktop |
bool | false | Enable Windows desktop |
--enable-fuchsia |
bool | false | Enable Fuchsia platform |
--android-sdk |
path | Auto-detected | Android SDK location |
--android-studio-dir |
path | Auto-detected | Android Studio location |
--jdk-dir |
path | Auto-detected | JDK location |
--build-dir |
path | build/ |
Output directory for builds |
--enable-custom-devices |
bool | false | Enable custom device support |
--clear-ios-signing-cert |
— | — | Remove cached signing cert |
--no-analytics |
bool | false | Disable telemetry |
--suppress-analytics |
bool | false | Suppress analytics prompt |
# Enable desktop platforms
flutter config --enable-linux-desktop
flutter config --enable-macos-desktop
flutter config --enable-windows-desktop
# Set Android SDK path explicitly
flutter config --android-sdk /opt/android-sdk
# Disable analytics
flutter config --no-analytics
Important
Configuration changes via
flutter configare machine-global — they apply to all Flutter projects on that workstation. Per-project overrides are managed throughpubspec.yamland build arguments, notflutter config.
3.2 Project Configuration (pubspec.yaml)
The pubspec.yaml file is the central project manifest. Complete specification:
# Required fields
name: my_app # Package name (lowercase_with_underscores)
description: A Flutter app # Package description
version: 1.0.0+1 # Semantic version + build number
publish_to: 'none' # 'none' for private apps
# Dart/Flutter SDK constraints
environment:
sdk: ^3.10.0 # Minimum Dart SDK
flutter: ">=3.32.0" # Minimum Flutter SDK (optional)
# Dependencies
dependencies:
flutter:
sdk: flutter # Flutter framework
cupertino_icons: ^1.0.8 # Example: pub.dev package
local_pkg:
path: ../packages/local_pkg # Path dependency
git_pkg:
git:
url: https://github.com/user/repo.git
ref: main # Branch, tag, or commit
path: packages/sub # Subdirectory in repo
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
build_runner: ^2.4.0
dependency_overrides: # Force specific versions (dev only)
some_package: ^2.0.0
# Flutter-specific configuration
flutter:
uses-material-design: true # Include Material Icons font
# Asset declarations
assets:
- assets/images/ # Include all files in directory
- assets/data/config.json # Include specific file
- packages/pkg_name/assets/ # Assets from dependency
# Custom fonts
fonts:
- family: Roboto
fonts:
- asset: fonts/Roboto-Regular.ttf
- asset: fonts/Roboto-Bold.ttf
weight: 700
- asset: fonts/Roboto-Italic.ttf
style: italic
# Code generation
generate: true # Enable build_runner code generation
# Plugin platform support declaration (plugins only)
plugin:
platforms:
android:
package: com.example.plugin
pluginClass: MyPlugin
ios:
pluginClass: MyPlugin
web:
pluginClass: MyPluginWeb
fileName: my_plugin_web.dart
linux:
pluginClass: MyPluginLinux
macos:
pluginClass: MyPluginMacOS
windows:
pluginClass: MyPluginWindows
# Deferred components (Android dynamic feature modules)
deferred-components:
- name: feature_module
libraries:
- package:my_app/feature.dart
assets:
- assets/feature/
# Shader compilation (Impeller)
shaders:
- shaders/my_effect.frag
3.3 Analysis Configuration (analysis_options.yaml)
Controls Dart static analysis, linting, and code style enforcement:
# Extend recommended rule sets
include: package:flutter_lints/flutter.yaml
analyzer:
# Treat specific issues as errors or warnings
errors:
missing_return: error
dead_code: warning
unused_import: warning
unused_local_variable: warning
deprecated_member_use: info
invalid_annotation_target: ignore
# Exclude files/directories from analysis
exclude:
- "**/*.g.dart" # Generated files
- "**/*.freezed.dart"
- "build/**"
- "test/.test_coverage.dart"
# Enable experimental language features
language:
strict-casts: true # No implicit casts
strict-inference: true # No implicit dynamic
strict-raw-types: true # No raw generic types
# Plugin configuration
plugins:
- custom_lint # Custom lint rules
linter:
rules:
# Style
prefer_const_constructors: true
prefer_const_declarations: true
prefer_const_literals_to_create_immutables: true
prefer_final_fields: true
prefer_final_locals: true
sort_constructors_first: true
sort_unnamed_constructors_first: true
# Error prevention
avoid_print: true
avoid_relative_lib_imports: true
avoid_returning_null_for_future: true
avoid_slow_async_io: true
avoid_type_to_string: true
cancel_subscriptions: true
close_sinks: true
literal_only_boolean_expressions: true
no_adjacent_strings_in_list: true
test_types_in_equals: true
throw_in_finally: true
unnecessary_statements: true
# Performance
avoid_unnecessary_containers: true
sized_box_for_whitespace: true
# Disable specific rules
always_use_package_imports: false
3.4 Build Modes
Flutter supports three build modes, each with different performance and debugging characteristics:
| Mode | Compilation | Assertions | DevTools | Observatory | Tree Shaking | Optimization | Use Case |
|---|---|---|---|---|---|---|---|
| Debug | JIT (Dart VM) | Enabled | Full | Yes | No | None | Development, hot reload |
| Profile | AOT | Disabled | Performance only | Yes | Yes | Partial | Performance profiling |
| Release | AOT | Disabled | No | No | Yes | Full (-O4) | Production deployment |
# Build mode selection
flutter run # Debug (default)
flutter run --profile # Profile
flutter run --release # Release
flutter build apk --release # Release APK
flutter build ios --profile # Profile iOS
Additional build flags:
# Dart compilation flags
--dart-define=KEY=VALUE # Compile-time constants
--dart-define-from-file=.env # Bulk compile-time constants from file
--enable-experiment=X # Enable Dart language experiments
# Output configuration
--build-number=42 # Override build number
--build-name=1.2.3 # Override version string
--split-debug-info=/path # Extract debug symbols
--obfuscate # Obfuscate Dart code (release only)
--tree-shake-icons # Remove unused Material Icons
--no-tree-shake-icons # Keep all Material Icons
# Performance flags
--enable-impeller # Force Impeller rendering
--no-enable-impeller # Force Skia rendering
3.5 Platform-Specific Configuration
Android: android/app/build.gradle.kts
android {
namespace = "com.example.myapp"
compileSdk = 36 // CI-tested: API 36
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
defaultConfig {
applicationId = "com.example.myapp"
minSdk = 21 // Android 5.0 minimum
targetSdk = 36
versionCode = flutter.versionCode
versionName = flutter.versionName
multiDexEnabled = true
}
signingConfigs {
create("release") {
storeFile = file("keystore.jks")
storePassword = System.getenv("KEYSTORE_PASSWORD")
keyAlias = System.getenv("KEY_ALIAS")
keyPassword = System.getenv("KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true // Enable R8/ProGuard
isShrinkResources = true // Remove unused resources
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
// Flavor dimensions
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
}
create("prod") {
dimension = "environment"
}
}
}
Android: AndroidManifest.xml Key Permissions
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Common permissions -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Network security (API 28+) -->
<application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false">
<!-- ... -->
</application>
</manifest>
iOS: Info.plist Key Entries
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<!-- App Transport Security (require HTTPS) -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
</dict>
<!-- Permission descriptions (required for App Store) -->
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to...</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to...</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to...</string>
<!-- Background modes -->
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
</dict>
</plist>
Web: web/index.html Configuration
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App</title>
<!-- Favicon and PWA manifest -->
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/png" href="favicon.png"/>
<!-- Flutter engine loading -->
<script src="flutter_bootstrap.js" async></script>
</head>
<body>
<!-- Flutter renders here -->
</body>
</html>
The web build output includes the flutter_bootstrap.js loader, which handles:
- Engine initialization via
FlutterEntrypointLoader - Service worker registration via
FlutterServiceWorkerLoader - Trusted Types policy via
FlutterTrustedTypesPolicy - Renderer selection (CanvasKit/Skia vs HTML)
Linux: CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(my_app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Flutter engine
set(BINARY_NAME "my_app")
set(APPLICATION_ID "com.example.my_app")
# Required system dependencies
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
# Flutter integration
add_subdirectory(${FLUTTER_MANAGED_DIR})
Windows: CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(my_app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(BINARY_NAME "my_app")
set(APPLICATION_ID "com.example.my_app")
# Flutter C++ client wrapper
add_subdirectory(${FLUTTER_MANAGED_DIR})
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
3.6 Generated Files
These files are auto-generated and should not be manually edited:
| File | Generated By | Purpose |
|---|---|---|
.flutter-plugins |
flutter pub get |
Plugin name → path mapping (legacy) |
.flutter-plugins-dependencies |
flutter pub get |
Plugin dependency graph (JSON) |
.dart_tool/package_config.json |
dart pub get |
Package resolution |
pubspec.lock |
dart pub get |
Locked dependency versions |
.packages |
dart pub get |
Legacy package resolution (deprecated) |
android/.gradle/ |
Gradle | Build cache |
ios/Pods/ |
CocoaPods | iOS dependencies |
build/ |
flutter build |
Compiled output |
*.g.dart |
build_runner |
Code generation output |
3.7 Environment Variables
| Variable | Purpose | Context |
|---|---|---|
FLUTTER_ROOT |
SDK installation path | Build scripts |
PUB_CACHE |
Package cache directory | ~/.pub-cache default |
PUB_HOSTED_URL |
Custom pub server URL | Enterprise mirrors |
FLUTTER_STORAGE_BASE_URL |
Custom artifact server | Enterprise/China mirrors |
CHROME_EXECUTABLE |
Chrome binary path | Web development |
ANDROID_HOME / ANDROID_SDK_ROOT |
Android SDK path | Android development |
JAVA_HOME |
JDK path | Android/Gradle builds |
FLUTTER_BUILD_DIR |
Custom build output directory | CI/CD |
FLUTTER_SUPPRESS_ANALYTICS |
Disable telemetry | CI environments |
4. Deployment & Scaling
4.1 Android Deployment
APK vs App Bundle
| Format | Extension | Distribution | Size | Dynamic Delivery |
|---|---|---|---|---|
| APK | .apk |
Sideload, third-party stores | Larger (all ABIs) | No |
| App Bundle | .aab |
Google Play Store | Smaller (per-device) | Yes |
# Build APK (all ABIs)
flutter build apk --release
# Build APK per ABI (smaller individual files)
flutter build apk --release --split-per-abi
# Produces: app-armeabi-v7a-release.apk, app-arm64-v8a-release.apk, app-x86_64-release.apk
# Build App Bundle (recommended for Play Store)
flutter build appbundle --release
# With obfuscation and debug symbols
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/debug-info/ \
--dart-define=ENV=production
Signing Configuration
- Generate a keystore:
keytool -genkey -v -keystore ~/upload-keystore.jks \
-storetype JKS -keyalg RSA -keysize 2048 -validity 10000 \
-alias upload
- Create
android/key.properties(gitignored):
storePassword=<password>
keyPassword=<password>
keyAlias=upload
storeFile=<path>/upload-keystore.jks
- Reference in
build.gradle.kts:
val keystoreProperties = Properties()
val keystoreFile = rootProject.file("key.properties")
if (keystoreFile.exists()) {
keystoreProperties.load(FileInputStream(keystoreFile))
}
ProGuard / R8 Rules
For Flutter apps with plugins that use reflection:
# Flutter-specific rules
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-keep class io.flutter.plugin.common.** { *; }
-dontwarn io.flutter.embedding.**
# Gson / JSON serialization (if used)
-keepattributes Signature
-keepattributes *Annotation*
4.2 iOS Deployment
# Build iOS release
flutter build ios --release
# Build IPA for distribution
flutter build ipa --release \
--export-options-plist=ios/ExportOptions.plist
# With obfuscation
flutter build ipa --release \
--obfuscate \
--split-debug-info=build/debug-info/
Signing and Distribution
| Distribution | Signing | Provisioning | Channel |
|---|---|---|---|
| App Store | Distribution certificate | App Store provisioning profile | App Store Connect |
| TestFlight | Distribution certificate | App Store provisioning profile | TestFlight |
| Ad Hoc | Distribution certificate | Ad Hoc profile (device UDIDs) | Direct install |
| Enterprise | Enterprise certificate | Enterprise profile | MDM / direct |
Xcode automatic signing handles most cases. For CI:
# Install provisioning profile
cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
# Export options for CI (ExportOptions.plist)
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>uploadSymbols</key>
<true/>
</dict>
</plist>
4.3 Web Deployment
# Build for web (default: CanvasKit renderer)
flutter build web --release
# Build with HTML renderer (smaller download, less fidelity)
flutter build web --release --web-renderer html
# Build with auto renderer selection (HTML on mobile, CanvasKit on desktop)
flutter build web --release --web-renderer auto
# Build with WebAssembly (experimental)
flutter build web --release --wasm
# Build with custom base URL
flutter build web --release --base-href /my-app/
# Build with source maps
flutter build web --release --source-maps
Build Output Structure
build/web/
├── index.html # Entry point
├── main.dart.js # Compiled Dart application
├── main.dart.js.map # Source maps (if enabled)
├── flutter_bootstrap.js # Engine loader
├── flutter_service_worker.js # Service worker for offline
├── manifest.json # PWA manifest
├── favicon.png
├── icons/ # PWA icons
├── assets/
│ ├── AssetManifest.json # Asset registry
│ ├── FontManifest.json # Font registry
│ ├── fonts/ # Bundled fonts
│ └── packages/ # Package assets
└── canvaskit/ # CanvasKit WASM runtime
├── canvaskit.js
└── canvaskit.wasm
Hosting Configuration
For single-page app (SPA) routing, configure the server to redirect all paths to index.html:
Nginx:
location / {
try_files $uri $uri/ /index.html;
}
# Cache CanvasKit WASM aggressively
location /canvaskit/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Cache fonts and assets
location /assets/ {
expires 30d;
add_header Cache-Control "public";
}
Apache (.htaccess):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]
Service Worker Behavior
The generated flutter_service_worker.js uses FlutterServiceWorkerLoader to:
- Cache all application assets for offline use
- Serve cached assets on subsequent visits
- Update cache when new versions are deployed
- Handle the "Cannot activate a null service worker!" error if registration fails
Tip
For PWA deployment, ensure the
manifest.jsoncontains validstart_url,display, andiconsentries. Theflutter_bootstrap.jsloader will register the service worker automatically. If you need to customize service worker behavior, modify the loading strategy inweb/index.htmlrather than editing the generated worker.
4.4 Desktop Deployment
Linux
flutter build linux --release
# Output: build/linux/x64/release/bundle/
# ├── my_app (executable)
# ├── lib/
# │ ├── libflutter_linux_gtk.so
# │ └── libapp.so
# └── data/
# ├── icudtl.dat
# └── flutter_assets/
Packaging options: .deb (dpkg-deb), .rpm (rpmbuild), Snap, Flatpak, AppImage.
Windows
flutter build windows --release
# Output: build/windows/x64/runner/Release/
# ├── my_app.exe
# ├── flutter_windows.dll
# └── data/
# ├── icudtl.dat
# └── flutter_assets/
Packaging: MSIX (recommended for Microsoft Store), Inno Setup, WiX, NSIS.
macOS
flutter build macos --release
# Output: build/macos/Build/Products/Release/my_app.app
Packaging: .dmg (create-dmg), .pkg (productbuild), notarization required for distribution.
4.5 CI/CD Integration Patterns
GitHub Actions Example
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- run: flutter pub get
- run: flutter test
- run: flutter build appbundle --release
- uses: actions/upload-artifact@v4
with:
name: android-release
path: build/app/outputs/bundle/release/
build-ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- run: flutter pub get
- run: flutter test
- run: flutter build ipa --release --export-options-plist=ios/ExportOptions.plist
build-web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- run: flutter pub get
- run: flutter test
- run: flutter build web --release --base-href /
- name: Deploy to hosting
run: |
# Deploy build/web/ to your hosting provider
Caching Strategy
# Cache Flutter SDK and pub packages
- uses: subosito/flutter-action@v2
with:
cache: true
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:
cache-path: |
${{ runner.tool_cache }}/flutter
$HOME/.pub-cache
4.6 Multi-Flavor / Multi-Environment Builds
# Android flavors
flutter build apk --release --flavor prod -t lib/main_prod.dart
flutter build apk --release --flavor dev -t lib/main_dev.dart
# Compile-time configuration
flutter build apk --release \
--dart-define=API_URL=https://api.example.com \
--dart-define=ENV=production \
--dart-define=SENTRY_DSN=https://...
# Load from file (one KEY=VALUE per line)
flutter build apk --release --dart-define-from-file=config/prod.env
5. Operations
5.1 SDK Channel Management
Flutter distributes via three release channels:
| Channel | Stability | Update Frequency | Use Case |
|---|---|---|---|
stable |
Production-ready | Quarterly (~every 3 months) | Production apps |
beta |
Pre-release | Monthly | Testing upcoming features |
master |
Bleeding edge | Continuous (multiple/day) | Contributing to Flutter, early access |
# View current channel
flutter channel
# Switch channels
flutter channel stable
flutter channel beta
flutter channel master
# Upgrade within current channel
flutter upgrade
# Downgrade to previous version on current channel
flutter downgrade
# Pin to specific version (via git)
cd $FLUTTER_ROOT
git checkout 3.32.0
flutter doctor
Note
Switching channels triggers a full SDK download and Dart SDK update. The
flutter upgradecommand performsgit pullon the SDK repository and rebuilds the Dart snapshot. This can take several minutes depending on network speed.
5.2 Cache Management
# View cache status
flutter precache --help
# Pre-download platform artifacts
flutter precache # All enabled platforms
flutter precache --android # Android only
flutter precache --ios # iOS only
flutter precache --web # Web only
flutter precache --linux # Linux only
flutter precache --windows # Windows only
flutter precache --macos # macOS only
# Clear all caches (build outputs, pub cache, tool snapshots)
flutter clean # Project build cache
flutter pub cache clean # Global package cache
flutter pub cache repair # Redownload cached packages
# Clear entire Flutter tool cache (nuclear option)
rm -rf $FLUTTER_ROOT/bin/cache
flutter doctor # Forces re-download
Cache locations:
| Cache | Path | Contents |
|---|---|---|
| SDK tools | $FLUTTER_ROOT/bin/cache/ |
Engine artifacts, Dart SDK, tool snapshots |
| Pub packages | $PUB_CACHE (~/.pub-cache) |
Downloaded package sources |
| Project build | <project>/build/ |
Compiled output per platform |
| Gradle | ~/.gradle/caches/ |
Android build cache |
| CocoaPods | ~/Library/Caches/CocoaPods/ |
iOS dependency cache |
5.3 Device Management
# List all connected devices
flutter devices
# List available emulators
flutter emulators
# Launch an emulator
flutter emulators --launch <emulator_id>
# Create a new Android emulator
flutter emulators --create --name my_emulator
# Run on specific device
flutter run -d <device_id>
flutter run -d chrome # Web
flutter run -d linux # Linux desktop
flutter run -d windows # Windows desktop
flutter run -d macos # macOS desktop
# Run on all connected devices
flutter run -d all
5.4 Custom Devices
For embedded or non-standard targets, enable and configure custom devices:
flutter config --enable-custom-devices
flutter custom-devices add
Configuration stored in ~/.flutter_custom_devices.json:
{
"custom-devices": [
{
"id": "my-device",
"label": "My Custom Device",
"sdkNameAndVersion": "Custom OS 1.0",
"platform": "linux",
"enabled": true,
"ping": ["ping", "-c", "1", "192.168.1.100"],
"install": ["scp", "${localPath}", "user@192.168.1.100:~/app"],
"uninstall": ["ssh", "user@192.168.1.100", "rm", "-rf", "~/app"],
"run": ["ssh", "user@192.168.1.100", "./app/my_app"],
"stop": ["ssh", "user@192.168.1.100", "pkill", "my_app"]
}
]
}
5.5 Logging and Diagnostics
# System diagnostics (comprehensive)
flutter doctor -v
# Device logs (real-time)
flutter logs
# Verbose CLI output
flutter run -v # Verbose
flutter run -vv # Very verbose (includes engine logs)
# Analyze project for issues
flutter analyze
flutter analyze --no-fatal-infos # Don't fail on info-level issues
flutter analyze --fatal-warnings # Fail on warnings
# Package dependency audit
flutter pub deps # Dependency tree
flutter pub outdated # Available updates
flutter pub audit # Security audit (CVE check)
Tip
The
flutter doctorcommand runs platform-specific validators. Useflutter doctor -vfor detailed output that includes exact paths, versions, and license status. This is the first debugging step for any build environment issue. Its output is also required when filing Flutter bug reports.
5.6 Daemon Management
The Flutter daemon runs as a persistent background process to speed up device detection and build operations:
# Start daemon
flutter daemon
# Check daemon status
flutter daemon --status
# Stop daemon
flutter daemon --shutdown
# The daemon listens on a domain socket and communicates via JSON-RPC
# Useful for IDE integration (VS Code, Android Studio, IntelliJ)
5.7 Hot Reload and Hot Restart
During debug mode development:
| Operation | Shortcut (terminal) | What It Does | State Preserved |
|---|---|---|---|
| Hot Reload | r |
Injects updated source, preserves state | Yes |
| Hot Restart | R |
Restarts app, resets state | No |
| Quit | q |
Stop the app | N/A |
| Detach | d |
Detach debugger, leave app running | N/A |
Hot reload limitations:
- Changes to
main()or global initializers require hot restart - Changes to enum values require hot restart
- Changes to generic type declarations require hot restart
- Adding/removing fields on native classes requires full restart
5.8 Attach to Running App
# Attach to a running Flutter app (debug mode)
flutter attach
flutter attach -d <device_id>
flutter attach --debug-url=<observatory_url>
# Attach with specific Dart define
flutter attach --dart-define=KEY=VALUE
5.9 Screenshot and Recording
# Take a screenshot of the running app
flutter screenshot
flutter screenshot --out=screenshot.png
flutter screenshot --type=rasterizer # Render tree screenshot
flutter screenshot --type=skia # Skia picture screenshot
# Screen recording (Android)
adb shell screenrecord /sdcard/recording.mp4
6. Performance
6.1 Build Mode Performance Characteristics
| Characteristic | Debug | Profile | Release |
|---|---|---|---|
| Compilation | JIT (Dart VM) | AOT | AOT |
| App size (Android) | 40-60 MB | 15-25 MB | 8-20 MB |
| Startup time | 2-5s | 0.5-1.5s | 0.3-1s |
| Frame budget (60fps) | Often missed | 16.67ms target | 16.67ms target |
| Hot reload | Yes | No | No |
| Assertions | On | Off | Off |
debugPrint |
Active | Active | Compiled out |
| Tree shaking | No | Yes | Yes |
| Optimization level | O0 | O2 | O4 |
Warning
Never benchmark performance in debug mode. The JIT compiler, enabled assertions, and disabled tree shaking make debug builds 5-20x slower than release builds. Always use
--profileor--releasefor meaningful performance measurements.
6.2 Impeller vs Skia Rendering
Impeller is Flutter's modern rendering backend, designed to eliminate shader compilation jank:
| Aspect | Impeller | Skia |
|---|---|---|
| Shader compilation | Pre-compiled at build time | Runtime compilation (causes jank) |
| First-frame performance | Consistent | May stutter (shader cache cold) |
| GPU utilization | Modern HAL (Metal, Vulkan) | OpenGL ES / Metal |
| Text rendering | Custom tessellation | Skia text engine |
| Platform support | iOS (default), Android (default), macOS | All platforms (fallback) |
| Known issues | Non-SDF stroked circles hairline rendering (#185222) | OpenGL crashes on MediaTek GPUs (#166248) |
# Force Impeller on Android (if not default)
flutter run --enable-impeller
# Force Skia fallback
flutter run --no-enable-impeller
# Check active renderer at runtime (in Dart)
# import 'dart:ui' as ui;
# print(ui.PlatformDispatcher.instance.implicitView?.display.toString());
6.3 Performance Profiling with DevTools
# Launch DevTools
flutter run --profile
# Press 'v' to open DevTools in browser, or:
dart devtools
# Connect to running app
dart devtools --connect=<vm-service-url>
DevTools panels:
| Panel | Purpose |
|---|---|
| Flutter Inspector | Widget tree, render tree, layer tree visualization |
| Performance | Frame timeline, build/layout/paint/raster phases |
| CPU Profiler | Call tree, bottom-up, flame chart |
| Memory | Heap snapshot, allocation tracking, leak detection |
| Network | HTTP request/response inspection |
| Logging | Dart log output, framework events |
| App Size | Treemap of compiled output |
6.4 Common Performance Optimizations
Widget Build Optimization
// Use const constructors to enable widget caching
const Padding(padding: EdgeInsets.all(8.0), child: Icon(Icons.star));
// Avoid rebuilding expensive subtrees
class _OptimizedState extends State<Optimized> {
late final Widget _expensiveChild = ExpensiveWidget();
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Changes: ${widget.counter}'),
_expensiveChild, // Not rebuilt when counter changes
],
);
}
}
// Use RepaintBoundary to isolate repaint regions
RepaintBoundary(
child: AnimatedWidget(), // Repaints don't propagate up
)
List Performance
// For long lists, use ListView.builder (lazy rendering)
ListView.builder(
itemCount: 10000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
);
// For very long lists with fixed-height items
ListView.builder(
itemCount: 100000,
itemExtent: 56.0, // Enables O(1) scroll offset calculation
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
);
// Avoid: ListView with children parameter for large lists
// This builds all children immediately, defeating lazy rendering
Image Optimization
// Decode images at display size, not original resolution
Image.network(
url,
cacheWidth: 200, // Decode at this width (pixels)
cacheHeight: 200, // Decode at this height (pixels)
);
// Use FadeInImage for network images
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: url,
);
6.5 Tree Shaking
Flutter's release builds aggressively tree-shake unused code:
| What's Tree-Shaken | Flag | Savings |
|---|---|---|
| Unused Dart code | Automatic (release) | Varies |
| Unused Material Icons | --tree-shake-icons (default on) |
Up to 1.5 MB |
| Unused font glyphs | font-subset tool (automatic) |
Significant for CJK |
| Unused native code | R8/ProGuard (Android) | Varies |
# Analyze app size to find optimization opportunities
flutter build apk --release --analyze-size
# Opens DevTools App Size panel with treemap
6.6 Deferred Loading (Lazy Loading)
// Split code into deferred libraries
import 'package:my_app/heavy_feature.dart' deferred as heavy;
Future<void> loadFeature() async {
await heavy.loadLibrary();
// Now safe to use heavy.HeavyWidget()
}
On Android, this maps to dynamic feature modules when deferred-components is configured in pubspec.yaml.
6.7 Platform Views Performance
Platform views (embedding native Android/iOS views in Flutter) have significant performance implications:
| Approach | Performance | Compatibility | Use Case |
|---|---|---|---|
| Virtual Display (Android) | Better (composited off-screen) | Some gesture issues | Maps, WebView |
| Hybrid Composition (Android) | Worse (thread sync) | Better gesture handling | When virtual display fails |
| Texture Layer (iOS) | Good | Good | Maps, WebView |
// Minimize platform view usage in scrollable lists
// Each platform view creates a native view hierarchy
// Prefer Flutter-native alternatives when available
6.8 Benchmark Infrastructure
The Flutter monorepo includes extensive benchmark infrastructure in dev/benchmarks/:
| Benchmark | Directory | Measures |
|---|---|---|
| complex_layout | dev/benchmarks/complex_layout/ |
Nested widget tree build/layout |
| macrobenchmarks | dev/benchmarks/macrobenchmarks/ |
Full-app scenarios (scrolling, animation, transitions) |
| microbenchmarks | dev/benchmarks/microbenchmarks/ |
Individual operation timing |
| platform_channels | dev/benchmarks/platform_channels/ |
Platform channel throughput |
| platform_views | dev/benchmarks/platform_views/ |
Platform view creation/rendering |
| stocks | dev/benchmarks/stocks/ |
Stock app scrolling benchmark |
| multiple_flutters | dev/benchmarks/multiple_flutters/ |
Multiple engine instance overhead |
# Run microbenchmarks
cd dev/benchmarks/microbenchmarks
flutter run --release --no-start-paused
# Run macrobenchmarks on device
cd dev/benchmarks/macrobenchmarks
flutter drive --profile --driver test_driver/run_app.dart --target test/benchmarks.dart
7. Security
7.1 Code Signing
Android Signing
| Component | Purpose | Protection |
|---|---|---|
| Upload keystore | Signs uploads to Play Store | Must never be committed to source control |
| App signing key | Google manages (Play App Signing) | Google Cloud HSM |
| Debug keystore | Auto-generated for development | ~/.android/debug.keystore |
Warning
Never commit keystore files (
.jks,.keystore), signing passwords, orkey.propertiesto version control. Use environment variables or CI secrets for automated signing. Losing the upload key requires contacting Google Play support for key reset.
# Verify APK signing
apksigner verify --print-certs app-release.apk
# Verify key fingerprints
keytool -list -v -keystore upload-keystore.jks
iOS Signing
| Component | Purpose | Management |
|---|---|---|
| Development certificate | Debug builds on physical devices | Apple Developer Portal |
| Distribution certificate | App Store / Ad Hoc | Apple Developer Portal |
| Provisioning profile | Links app ID + certificate + devices | Apple Developer Portal |
For CI, use match (Fastlane) or manual certificate management:
# Export certificates for CI
security find-identity -v -p codesigning
# Fastlane match (recommended for teams)
fastlane match appstore
fastlane match development
7.2 Code Obfuscation
Dart code obfuscation renames classes, methods, and fields to hinder reverse engineering:
# Build with obfuscation (release only)
flutter build apk --release --obfuscate --split-debug-info=build/symbols/
flutter build ipa --release --obfuscate --split-debug-info=build/symbols/
# The --split-debug-info flag is REQUIRED with --obfuscate
# It extracts debug symbols needed for crash report symbolication
Caution
The
--split-debug-infodirectory must be archived and stored securely alongside each release. Without these symbol files, crash reports from obfuscated builds are unreadable. Upload them to your crash reporting service (Firebase Crashlytics, Sentry) for each release.
Symbolicate crash reports:
flutter symbolize -i crash_report.txt -d build/symbols/
7.3 Network Security
Android Network Security Configuration
Create android/app/src/main/res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Enforce HTTPS for all domains -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</base-config>
<!-- Allow cleartext for local development only -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
<!-- Certificate pinning (optional, advanced) -->
<domain-config>
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2027-01-01">
<pin digest="SHA-256">AAAAAA...=</pin>
<pin digest="SHA-256">BBBBBB...=</pin>
</pin-set>
</domain-config>
</network-security-config>
iOS App Transport Security
iOS enforces HTTPS by default via ATS. Exceptions must be declared in Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<!-- DO NOT set NSAllowsArbitraryLoads to true in production -->
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
7.4 Platform Channel Security
Platform channels are the bridge between Dart and native code. Security considerations:
| Channel Type | Direction | Data Format | Risk |
|---|---|---|---|
MethodChannel |
Bidirectional | Structured (StandardMessageCodec) | Arbitrary method invocation |
EventChannel |
Native → Dart | Stream of values | Data exposure |
BasicMessageChannel |
Bidirectional | Raw bytes or codec-encoded | Data integrity |
Security best practices:
// Validate channel inputs on the native side
// Android (Kotlin)
class SecurePlugin : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"getSecureData" -> {
val token = call.argument<String>("token")
if (!isValidToken(token)) {
result.error("AUTH_ERROR", "Invalid token", null)
return
}
result.success(secureData)
}
else -> result.notImplemented()
}
}
}
Caution
Platform channels transmit data in cleartext within the process. Sensitive data (tokens, keys, biometric data) should be processed on the native side and never round-tripped through Dart if possible. Use platform-specific secure storage (Android Keystore, iOS Keychain) for sensitive credentials.
7.5 Dependency Security
# Audit dependencies for known vulnerabilities
flutter pub audit
# Check for outdated dependencies
flutter pub outdated
# View full dependency tree
flutter pub deps
# Lock specific versions to prevent supply chain attacks
# Use pubspec.lock (always commit to version control for apps)
Supply Chain Hardening
| Practice | Implementation |
|---|---|
| Lock dependencies | Commit pubspec.lock for applications |
| Verify packages | Check pub.dev verification badges |
| Pin versions | Use exact versions for critical dependencies |
| Audit transitive deps | Review flutter pub deps --no-dev |
Use dependency_overrides sparingly |
Only for testing, never in production |
| Review plugin native code | Platform code can access full OS API |
7.6 Web Security
// Content Security Policy for Flutter web apps
// Serve with these headers:
// Content-Security-Policy:
// default-src 'self';
// script-src 'self' 'wasm-unsafe-eval'; // Required for CanvasKit WASM
// style-src 'self' 'unsafe-inline'; // Required for Flutter
// font-src 'self';
// img-src 'self' data: blob:;
// connect-src 'self' https://api.example.com;
Flutter web uses FlutterTrustedTypesPolicy for Trusted Types compliance when the browser enforces the require-trusted-types-for 'script' CSP directive.
7.7 Sensitive Data Storage
| Platform | Secure Storage | Flutter Package |
|---|---|---|
| Android | EncryptedSharedPreferences / Keystore | flutter_secure_storage |
| iOS | Keychain | flutter_secure_storage |
| Web | — (no truly secure client storage) | Consider server-side sessions |
| Linux | libsecret | flutter_secure_storage |
| macOS | Keychain | flutter_secure_storage |
| Windows | Windows Credential Manager | flutter_secure_storage |
8. Developer Internals
8.1 Repository Structure Deep Dive
flutter/flutter/ (14,714 files, 21.3M chars)
├── .ci.yaml CI build/test configuration (LUCI)
├── .autoroller-preupload.sh Pre-upload hook for auto-roller
├── CONTRIBUTING.md Contribution guidelines
├── packages/ Core Dart packages
│ ├── flutter/ THE framework
│ │ ├── lib/
│ │ │ ├── animation.dart Animation library (barrel export)
│ │ │ ├── cupertino.dart iOS-style widgets (50+ exports)
│ │ │ ├── foundation.dart Core primitives
│ │ │ ├── gestures.dart Gesture recognition
│ │ │ ├── material.dart Material Design (150+ exports)
│ │ │ ├── painting.dart Painting utilities
│ │ │ ├── physics.dart Physics simulations
│ │ │ ├── rendering.dart Render tree
│ │ │ ├── scheduler.dart Frame scheduling
│ │ │ ├── semantics.dart Accessibility
│ │ │ ├── services.dart Platform services
│ │ │ └── widgets.dart Widget framework
│ │ ├── lib/src/ Implementation (private)
│ │ │ ├── animation/
│ │ │ ├── cupertino/
│ │ │ ├── foundation/
│ │ │ ├── gestures/
│ │ │ ├── material/
│ │ │ ├── painting/
│ │ │ ├── physics/
│ │ │ ├── rendering/
│ │ │ ├── scheduler/
│ │ │ ├── semantics/
│ │ │ ├── services/
│ │ │ └── widgets/
│ │ └── test/ Unit + widget tests
│ ├── flutter_tools/ CLI tool (58 files, 1.12M chars)
│ │ ├── lib/executable.dart CLI entry point
│ │ ├── lib/src/ Implementation
│ │ │ ├── commands/ All CLI commands
│ │ │ ├── android/ Android build logic
│ │ │ ├── ios/ iOS build logic
│ │ │ ├── web/ Web build logic
│ │ │ ├── linux/ Linux build logic
│ │ │ ├── windows/ Windows build logic
│ │ │ ├── macos/ macOS build logic
│ │ │ ├── build_system/ Build graph/targets
│ │ │ ├── dart/ Dart SDK integration
│ │ │ ├── runner/ App runner
│ │ │ └── ...
│ │ └── gradle/ Android Gradle plugin (Kotlin)
│ ├── flutter_test/ Test framework (39 files, 896K chars)
│ ├── flutter_driver/ Integration test driver
│ ├── flutter_goldens/ Golden file testing (44K chars)
│ ├── flutter_localizations/ i18n support
│ ├── flutter_web_plugins/ Web plugin registration
│ ├── integration_test/ On-device integration testing
│ └── fuchsia_remote_debug_protocol/ Fuchsia debugging
├── engine/ Flutter engine
│ └── src/flutter/
│ ├── common/ Shared engine code
│ ├── impeller/ Impeller rendering engine
│ │ ├── core/ Core abstractions (17 files, 56K chars)
│ │ └── tessellator/ Path tessellation (Dart FFI, 7K chars)
│ ├── shell/
│ │ ├── common/ Shared shell (37 files, 292K chars)
│ │ └── platform/
│ │ ├── android/ Android embedder
│ │ │ └── io/flutter/plugin/common/ (17 files, 87K chars)
│ │ ├── common/ Shared platform (16 files, 52K chars)
│ │ ├── darwin/ iOS/macOS shared (6 files, 7.5K chars)
│ │ ├── fuchsia/ Fuchsia embedder
│ │ └── linux/ Linux embedder
│ ├── lib/
│ │ ├── web_ui/ Web engine (21 files, 212K chars)
│ │ │ └── flutter_js/ JS runtime (11 files, 35K chars)
│ │ └── gpu/ GPU abstraction (9 files, 49K chars)
│ ├── tools/
│ │ ├── engine_tool/ Engine build tool
│ │ ├── api_check/ API compatibility checker
│ │ ├── golden_tests_harvester/ Golden test collection
│ │ ├── header_guard_check/ Header include guard linter
│ │ └── mcp/ MCP server (4.7K chars)
│ ├── sky/packages/sky_engine/ dart:ui implementation
│ ├── txt/ Text rendering (ICU, HarfBuzz)
│ └── testing/ Engine test infrastructure
├── dev/ Development tools and tests
│ ├── devicelab/ Device lab testing
│ ├── benchmarks/ Performance benchmarks
│ │ ├── complex_layout/
│ │ ├── macrobenchmarks/
│ │ ├── microbenchmarks/
│ │ ├── platform_channels/
│ │ ├── platform_views/
│ │ ├── stocks/
│ │ └── multiple_flutters/
│ ├── integration_tests/ Integration tests (40+ apps)
│ ├── tools/
│ │ ├── gen_defaults/ Material Design tokens (44 files, 193K)
│ │ ├── gen_keycodes/ Keyboard keycodes (16 files, 109K)
│ │ └── vitool/ Visual inspection tool
│ ├── snippets/ API doc snippets (6 files, 65K chars)
│ ├── bots/ CI bot scripts
│ ├── a11y_assessments/ Accessibility testing
│ ├── manual_tests/ Manual test apps
│ ├── customer_testing/ Customer app testing
│ └── packages_autoroller/ Dependency auto-roller
├── examples/ Example applications
│ ├── api/ Widget API examples
│ ├── hello_world/ Minimal app
│ ├── layers/ Low-level rendering examples
│ ├── platform_channel/ Platform channel examples
│ ├── platform_view/ Platform view examples
│ ├── multiple_windows/ Multi-window demo
│ ├── texture/ Texture rendering
│ ├── splash/ Splash screen
│ ├── image_list/ Image loading
│ └── flutter_view/ FlutterView embedding
├── docs/ Project documentation
│ ├── wiki_archive/
│ ├── contributing/
│ ├── engine/
│ ├── infra/
│ ├── platforms/
│ ├── rules/
│ └── tool/
└── buildtools/ Build toolchain
8.2 Framework Architecture Deep Dive
Layer Dependencies
material.dart / cupertino.dart
│ depends on
widgets.dart
│ depends on
rendering.dart
│ depends on
painting.dart + animation.dart + semantics.dart + gestures.dart
│ depends on
foundation.dart + scheduler.dart + services.dart + physics.dart
│ depends on
dart:ui (sky_engine)
Each layer provides abstractions used by the layer above. The strict layering means you can use rendering.dart directly without material.dart — the examples/layers/ apps demonstrate this.
Foundation Layer (foundation.dart)
Core primitives used throughout the framework:
| Class / Utility | Purpose |
|---|---|
ChangeNotifier |
Observable object with listener list |
ValueNotifier<T> |
ChangeNotifier holding a single value |
Key / ValueKey / ObjectKey / UniqueKey / GlobalKey |
Widget identity for reconciliation |
DiagnosticableTree |
Debug toString/inspection infrastructure |
BindingBase |
Base class for framework initialization |
kDebugMode / kProfileMode / kReleaseMode |
Compile-time mode constants |
debugPrint |
Debug-safe print (throttled) |
compute() |
Run function in isolate |
SynchronousFuture |
Future that completes synchronously |
Widget Layer (widgets.dart)
| Concept | Class | Purpose |
|---|---|---|
| Configuration | Widget |
Immutable description of UI element |
| Identity | Element |
Mutable, manages lifecycle and tree position |
| Stateless | StatelessWidget |
Widget that builds once from config |
| Stateful | StatefulWidget + State<T> |
Widget with mutable state and lifecycle |
| Inheritance | InheritedWidget |
Efficient data propagation down the tree |
| Layout | Row, Column, Stack, Flex, Wrap, Flow |
Arrangement strategies |
| Scrolling | ListView, GridView, CustomScrollView, Sliver* |
Scrollable containers |
| Navigation | Navigator, Route, Router |
Screen navigation |
| Overlay | Overlay, OverlayEntry |
Above-tree rendering (tooltips, menus) |
| Focus | FocusNode, FocusScope |
Keyboard focus management |
| Shortcuts | Shortcuts, Actions |
Keyboard shortcut binding |
Rendering Layer (rendering.dart)
| Class | Purpose |
|---|---|
RenderObject |
Base class for all render objects (layout + paint protocol) |
RenderBox |
Box-model render object (width/height constraints) |
RenderSliver |
Sliver-model render object (scrollable lazy children) |
RenderView |
Root render object, represents the viewport |
PipelineOwner |
Manages dirty lists for layout, paint, compositing, semantics |
BoxConstraints |
Min/max width/height constraints (tight, loose, infinite) |
Offset / Size / Rect |
Geometry primitives |
PaintingContext |
Canvas abstraction for paint methods |
Layout Protocol
Parent sends constraints DOWN → Child returns size UP → Parent positions child
BoxConstraints(
minWidth: 0, maxWidth: 300, // Child must be 0-300px wide
minHeight: 0, maxHeight: 400 // Child must be 0-400px tall
)
│
▼
Child.performLayout() // Child computes its size
│
▼
Child.size = Size(200, 150) // Child reports: "I'm 200x150"
│
▼
Parent.parentData.offset = Offset(50, 25) // Parent: "You go at (50, 25)"
8.3 Widget Lifecycle
StatefulWidget Lifecycle
createState() ① Framework creates State object
│
initState() ② One-time initialization (subscribe, init controllers)
│
didChangeDependencies() ③ Called after initState and when InheritedWidget changes
│
build(context) ④ Build the widget tree (called many times)
│
┌──┴──────────────────┐
│ setState(() { ... }) │ ⑤ Schedule rebuild
└──┬──────────────────┘
│
didUpdateWidget(old) ⑥ When parent rebuilds with same key but new config
│
deactivate() ⑦ When removed from tree (may reactivate)
│
dispose() ⑧ Permanent removal — clean up controllers, subscriptions
Key Types and Reconciliation
// ValueKey — identity by value
ListView(children: items.map((item) => ListTile(key: ValueKey(item.id))));
// ObjectKey — identity by object reference
ObjectKey(myObject)
// UniqueKey — always unique (forces rebuild)
UniqueKey()
// GlobalKey — unique across the entire tree (expensive, use sparingly)
final formKey = GlobalKey<FormState>();
Form(key: formKey, child: ...);
formKey.currentState?.validate();
8.4 InheritedWidget and Data Propagation
// Pattern: InheritedWidget for O(1) dependency lookup
class ThemeData extends InheritedWidget {
final Color primaryColor;
const ThemeData({required this.primaryColor, required Widget child})
: super(child: child);
static ThemeData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<ThemeData>()!;
}
@override
bool updateShouldNotify(ThemeData old) => primaryColor != old.primaryColor;
}
// Usage: Theme.of(context) — O(1) lookup via Element hash map
// Only Elements that called dependOn... are rebuilt when the InheritedWidget changes
8.5 Platform Channel Protocol
Platform channels bridge Dart and native code using message passing over a binary protocol:
StandardMessageCodec Type Mapping
| Dart Type | Android (Java) | iOS (Objective-C) | Encoding |
|---|---|---|---|
null |
null |
NSNull / nil |
0x00 |
bool |
Boolean |
NSNumber(bool) |
0x01/0x02 |
int (≤32-bit) |
Integer |
NSNumber(int) |
0x03 |
int (≤64-bit) |
Long |
NSNumber(long) |
0x04 |
int (>64-bit) |
BigInteger |
— | 0x05 |
double |
Double |
NSNumber(double) |
0x06 |
String |
String |
NSString |
0x07 |
Uint8List |
byte[] |
FlutterStandardTypedData |
0x08 |
Int32List |
int[] |
FlutterStandardTypedData |
0x09 |
Int64List |
long[] |
FlutterStandardTypedData |
0x0a |
Float32List |
— | — | 0x0b |
Float64List |
double[] |
FlutterStandardTypedData |
0x0c |
List |
ArrayList |
NSArray |
0x0d |
Map |
HashMap |
NSDictionary |
0x0e |
Channel Types
// MethodChannel: Request-response pattern
const channel = MethodChannel('com.example/battery');
final int level = await channel.invokeMethod('getBatteryLevel');
// EventChannel: Stream pattern (native → Dart)
const eventChannel = EventChannel('com.example/sensor');
eventChannel.receiveBroadcastStream().listen((event) {
print('Sensor: $event');
});
// BasicMessageChannel: Raw message passing
const msgChannel = BasicMessageChannel<String>(
'com.example/messages',
StringCodec(),
);
msgChannel.send('hello');
msgChannel.setMessageHandler((message) async {
return 'response: $message';
});
Android Embedder Classes (io.flutter.plugin.common)
| Class | Purpose |
|---|---|
StandardMessageCodec |
Default binary codec for MethodChannel |
MethodChannel |
Java/Kotlin side of method channel |
BasicMessageChannel |
Java/Kotlin side of basic message channel |
EventChannel |
Java/Kotlin side of event channel |
BinaryMessenger |
Low-level binary message transport |
MethodCall |
Incoming method call (name + arguments) |
MethodChannel.Result |
Response callback (success/error/notImplemented) |
8.6 Engine Tools
| Tool | Location | Purpose |
|---|---|---|
engine_tool |
engine/src/flutter/tools/engine_tool/ |
Build, test, and manage engine artifacts |
api_check |
engine/src/flutter/tools/api_check/ |
Check API compatibility between versions |
golden_tests_harvester |
engine/src/flutter/tools/golden_tests_harvester/ |
Collect golden test images from CI |
header_guard_check |
engine/src/flutter/tools/header_guard_check/ |
Lint C++ header include guards |
mcp |
engine/src/flutter/tools/mcp/ |
MCP server for engine tooling (4.7K chars) |
8.7 Code Generation
Material Design Token Generation (dev/tools/gen_defaults/)
This tool (44 files, 193K chars) generates Dart source from Material Design 3 token files. It reads the Material Design token JSON spec and produces widget-level defaults (colors, typography, elevation, shapes) for the material.dart library.
# Run token generation
cd dev/tools/gen_defaults
dart run generate.dart
Generated files land in packages/flutter/lib/src/material/ as *_defaults.dart files containing const values derived from the Material Design spec.
Keyboard Keycode Generation (dev/tools/gen_keycodes/)
This tool (16 files, 109K chars) generates platform-specific keyboard key mappings from a canonical definition. It produces:
LogicalKeyboardKeyconstants (Dart)PhysicalKeyboardKeyconstants (Dart)- Platform-specific keycode mappings (Android, iOS, web, Windows, Linux, macOS, Fuchsia)
cd dev/tools/gen_keycodes
dart run gen_keycodes.dart
API Documentation Snippets (dev/snippets/)
The snippet extraction tool (6 files, 65K chars) processes /// {@tool snippet} and /// {@tool sample} annotations in framework source to:
- Extract code snippets from API docs
- Compile and verify snippet validity
- Generate runnable sample applications
8.8 CLI Commands Reference
The flutter CLI (packages/flutter_tools/lib/executable.dart) provides these commands:
| Command | Purpose | Key Flags |
|---|---|---|
analyze |
Static analysis | --fatal-infos, --fatal-warnings |
assemble |
Low-level build step execution | --define, --output |
attach |
Attach to running app | --debug-url, -d |
build |
Build application | apk, appbundle, ipa, web, linux, windows, macos |
channel |
Switch/list SDK channels | stable, beta, master |
clean |
Delete build outputs | — |
config |
Manage SDK configuration | --enable-*, --android-sdk |
create |
Create new project | --template, --platforms, --org |
custom_devices |
Manage custom devices | add, list, delete |
daemon |
Background service | --status, --shutdown |
debug_adapter |
DAP for IDE debugging | — |
devices |
List connected devices | -d |
doctor |
Validate environment | -v |
downgrade |
Revert SDK to previous version | — |
drive |
Integration test runner | --driver, --target |
emulators |
Manage emulators | --launch, --create |
generate |
Run code generation | — |
generate_localizations |
Generate L10n code | --arb-dir, --output-localization-file |
ide_config |
Generate IDE configuration | — |
install |
Install app on device | -d |
logs |
Stream device logs | — |
packages (pub) |
Package management | get, upgrade, outdated, audit |
precache |
Download platform artifacts | --android, --ios, --web, etc. |
run |
Build and run app | -d, --release, --profile |
screenshot |
Capture app screenshot | --type, --out |
shell_completion |
Generate shell completions | bash, zsh |
symbolize |
Symbolicate stack traces | -i, -d |
test |
Run tests | --coverage, --platform, --reporter |
update_packages |
Update tool dependencies | — |
upgrade |
Upgrade SDK | --force |
widget_preview |
Widget preview server | — |
Implementation: each command is a class in packages/flutter_tools/lib/src/commands/ inheriting from FlutterCommand. The tool depends on 80+ packages including analyzer, archive, args, coverage, crypto, dwds, http, yaml, xml, unified_analytics, and vm_service.
8.9 Testing Strategy
Test Types and Tools
| Level | Tool | Location | What It Tests |
|---|---|---|---|
| Unit | package:test |
test/ |
Pure Dart logic, models, utilities |
| Widget | package:flutter_test |
test/ |
Individual widgets in isolation |
| Integration | package:integration_test |
integration_test/ |
Full app on real device/emulator |
| Golden | package:flutter_goldens |
test/ |
Pixel-perfect rendering comparison |
| Driver | package:flutter_driver |
test_driver/ |
Legacy integration testing |
| Benchmark | Custom | dev/benchmarks/ |
Performance regression detection |
| Device Lab | Custom | dev/devicelab/ |
Hardware-specific testing |
Widget Testing with flutter_test
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments', (WidgetTester tester) async {
// Build the widget
await tester.pumpWidget(const MyApp());
// Verify initial state
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the button
await tester.tap(find.byIcon(Icons.add));
await tester.pump(); // Rebuild
// Verify updated state
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
# Run all tests
flutter test
# Run with coverage
flutter test --coverage
# Run specific test file
flutter test test/widget_test.dart
# Run with specific reporter
flutter test --reporter expanded
# Run golden tests
flutter test --update-goldens # Update golden files
flutter test # Compare against goldens
Integration Testing
// integration_test/app_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Full app flow', (tester) async {
app.main();
await tester.pumpAndSettle();
// Test real app behavior on device
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget);
});
}
# Run integration tests
flutter test integration_test/
# Run on specific device
flutter test integration_test/ -d <device_id>
Golden File Testing
testWidgets('Widget renders correctly', (tester) async {
await tester.pumpWidget(const MyWidget());
await expectLater(
find.byType(MyWidget),
matchesGoldenFile('goldens/my_widget.png'),
);
});
The flutter_goldens package (44K chars) provides infrastructure for comparing rendered widgets against known-good reference images. On CI, it integrates with golden_tests_harvester to collect and manage golden images across platforms.
CI Test Shards (from .ci.yaml)
The CI runs tests across multiple platforms with these configurations:
| Platform | Device Types | Test Scope |
|---|---|---|
| Linux | x64 (no device) | Framework tests, analysis, web tests |
| macOS | x64, arm64, iOS Simulator | Framework + iOS integration tests |
| Windows | x64 | Framework + Windows desktop tests |
| Android | Emulator API 35/36, Pixel 7 Pro, Galaxy S24 | Integration tests, device lab |
8.10 CI Infrastructure
The .ci.yaml file defines LUCI (Layered Universal Continuous Integration) build targets:
# Simplified structure
enabled_branches:
- main
- master
- flutter-\d+\.\d+-candidate\.\d+
platform_properties:
linux:
properties:
os: Linux
mac:
properties:
os: Mac-13
windows:
properties:
os: Windows-11
targets:
- name: Linux framework_tests
recipe: flutter/flutter
properties:
shard: framework_tests
subshard: "0"
scheduler: luci
- name: Linux web_tests
recipe: flutter/flutter
properties:
shard: web_tests
- name: Mac ios_build_test
recipe: flutter/flutter
properties:
shard: ios_build_test
CI bot scripts in dev/bots/ handle:
- Test shard distribution
- Framework test execution
- Analysis enforcement
- Customer testing (building real customer apps against HEAD)
- Auto-rolling dependencies
8.11 Contributing Workflow
Setting Up the Development Environment
# Fork and clone
git clone https://github.com/YOUR_USERNAME/flutter.git
cd flutter
# Add upstream
git remote add upstream https://github.com/flutter/flutter.git
# Set up the tool
export PATH="$PWD/bin:$PATH"
flutter doctor
# Run framework tests
cd packages/flutter
flutter test
# Run tool tests
cd packages/flutter_tools
dart test
Code Style and Analysis
The monorepo enforces strict analysis rules:
# Run analysis (must pass before PR)
flutter analyze --flutter-repo
# Format code
dart format .
# Check formatting
dart format --output=none --set-exit-if-changed .
Commit and PR Requirements
- Every PR must have tests (unit, widget, or integration)
- No analyzer warnings or errors
- All existing tests must pass
- PR description must explain the "why"
- Breaking changes require a migration guide
- API changes require dartdoc updates
- Material/Cupertino changes may need golden updates
8.12 Gradle Plugin (packages/flutter_tools/gradle/)
The Flutter Gradle plugin (Kotlin, 12K chars production + 22K chars tests) integrates Flutter builds into the Android Gradle build system:
| Class | Purpose |
|---|---|
FlutterPlugin |
Main Gradle plugin entry point |
FlutterExtension |
DSL for Flutter-specific Gradle config |
FlutterTask |
Gradle task that invokes flutter assemble |
The plugin handles:
- Embedding Flutter engine (
libflutter.so) into the APK - AOT compilation of Dart code into native libraries
- Asset bundling into
flutter_assets/ - Plugin dependency resolution from
.flutter-plugins-dependencies - Flavor and build type mapping
- Deferred component splitting
Note
AGP (Android Gradle Plugin) version 9 introduces changes to built-in Kotlin support that may require configuration updates (tracked as issue #183910). If you encounter Kotlin compilation issues after upgrading AGP, check whether the
kotlin-androidplugin is explicitly applied alongside the Flutter plugin.
9. Integration Points
9.1 Plugin System
Flutter plugins bridge Dart code with platform-specific native APIs using the federated plugin architecture:
┌─────────────────────────────────────────────┐
│ App-Facing Package │
│ (my_plugin) │
│ Dart API that apps import │
├─────────────────────────────────────────────┤
│ Platform Interface Package │
│ (my_plugin_platform_interface) │
│ Abstract class defining the contract │
├──────────┬──────────┬──────────┬────────────┤
│ Android │ iOS │ Web │ Linux/etc │
│(my_plug_ │(my_plug_ │(my_plug_ │(my_plug_ │
│ android) │ ios) │ web) │ linux) │
│ │ │ │ │
│ Kotlin/ │ Swift/ │ Dart/JS │ C++/FFI │
│ Java │ ObjC │ │ │
└──────────┴──────────┴──────────┴────────────┘
Plugin Registration
Plugins are registered differently per platform:
Android (GeneratedPluginRegistrant.java — auto-generated):
public final class GeneratedPluginRegistrant {
public static void registerWith(FlutterEngine flutterEngine) {
CameraPlugin.registerWith(flutterEngine);
PathProviderPlugin.registerWith(flutterEngine);
// ... auto-generated from .flutter-plugins-dependencies
}
}
iOS (GeneratedPluginRegistrant.m — auto-generated):
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]];
[PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];
}
Web (flutter_web_plugins package):
// Registered via generated_plugin_registrant.dart
registerWith(Registrar registrar) {
MyPluginWeb.registerWith(registrar);
}
9.2 FFI (Foreign Function Interface)
Dart FFI enables direct C/C++ interop without platform channels:
import 'dart:ffi';
import 'dart:io' show Platform;
// Load native library
final DynamicLibrary nativeLib = Platform.isAndroid
? DynamicLibrary.open('libnative.so')
: DynamicLibrary.open('native.framework/native');
// Bind C function: int add(int a, int b)
typedef AddFunc = Int32 Function(Int32 a, Int32 b);
typedef AddDart = int Function(int a, int b);
final add = nativeLib.lookupFunction<AddFunc, AddDart>('add');
// Call it
final result = add(3, 4); // 7
The engine's tessellator uses this pattern: engine/src/flutter/impeller/tessellator/ provides Dart FFI bindings (7K chars) to the native tessellation library (libtessellator).
ffigen for Automatic Binding Generation
# pubspec.yaml
dev_dependencies:
ffigen: ^14.0.0
# ffigen.yaml
output: 'lib/src/bindings.dart'
headers:
entry-points:
- 'src/native/api.h'
include-directives:
- 'src/native/api.h'
dart run ffigen
9.3 Web Interop
import 'dart:js_interop';
// Call JavaScript from Dart
@JS('console.log')
external void consoleLog(JSString message);
// Expose Dart to JavaScript
@JS('myDartFunction')
external set myDartFunction(JSFunction value);
// Use JavaScript objects
@JS('document')
external JSObject get document;
extension on JSObject {
external JSString get title;
external void getElementById(JSString id);
}
Web Engine Classes (flutter_js/)
| Class | Purpose |
|---|---|
FlutterEntrypointLoader |
Manages loading and initializing the Flutter engine in browsers |
FlutterLoader |
Downloads and initializes engine artifacts (CanvasKit WASM, Dart app) |
FlutterServiceWorkerLoader |
Registers and manages the PWA service worker |
FlutterTrustedTypesPolicy |
Implements W3C Trusted Types for XSS prevention |
9.4 Add-to-App Embedding
Embed Flutter into existing native applications:
Android Add-to-App
// Option 1: FlutterActivity (full-screen)
startActivity(FlutterActivity.createDefaultIntent(context))
// Option 2: FlutterFragment (fragment-based)
val fragment = FlutterFragment.createDefault()
supportFragmentManager.beginTransaction()
.add(R.id.container, fragment)
.commit()
// Option 3: FlutterView (view-level, most control)
val flutterEngine = FlutterEngine(context)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
val flutterView = FlutterView(context)
flutterView.attachToFlutterEngine(flutterEngine)
iOS Add-to-App
// Option 1: FlutterViewController (full-screen)
let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterVC, animated: true)
// Option 2: FlutterView (view-level)
let flutterView = flutterEngine.viewController!.view!
addSubview(flutterView)
9.5 Multiple Flutter Instances
Running multiple Flutter engine instances within a single app (demonstrated in examples/multiple_windows/ and dev/benchmarks/multiple_flutters/):
// Each FlutterEngine runs its own Dart isolate
// Considerations:
// - Each engine uses ~40-60 MB additional memory
// - Engines do not share Dart heap or state
// - Communication between engines must use platform channels
// - Prefer FlutterEngineGroup for memory-efficient multi-engine
// Android: FlutterEngineGroup shares resources between engines
val engineGroup = FlutterEngineGroup(context)
val engine1 = engineGroup.createAndRunDefaultEngine(context)
val engine2 = engineGroup.createAndRunEngine(context, DartEntrypoint(
"package:my_app/secondary.dart", "main"
))
// engine2 shares GPU context, Dart VM, and font data with engine1
Note
FlutterEngineGroupsignificantly reduces the memory overhead of multiple engines by sharing the Dart VM, GPU context, and platform resources. Without it, each engine is fully independent and duplicates these resources. Theexamples/multiple_windows/anddev/benchmarks/multiple_flutters/directories contain reference implementations.
9.6 Custom Embedder Creation
For unsupported platforms, create a custom embedder by implementing the embedder API:
// Minimal custom embedder (C API)
#include "flutter_embedder.h"
FlutterProjectArgs args = {
.struct_size = sizeof(FlutterProjectArgs),
.assets_path = "flutter_assets",
.icu_data_path = "icudtl.dat",
};
FlutterEngine engine;
FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args, NULL, &engine);
// Provide:
// 1. OpenGL/Vulkan/Metal rendering surface
// 2. Input event forwarding (touch, mouse, keyboard)
// 3. Platform message handling (for channels)
// 4. Vsync callback
// 5. Task runner integration
The engine/src/flutter/shell/platform/ directory contains reference embedder implementations for each platform. The shell common layer (37 files, 292K chars) provides shared logic that all embedders build upon.
9.7 Platform View Integration
Embed native platform views (maps, webviews, camera previews) inside Flutter:
// Android
AndroidView(
viewType: 'native-map',
onPlatformViewCreated: (id) {
// Platform view created with id
},
creationParams: {'apiKey': 'xxx'},
creationParamsCodec: const StandardMessageCodec(),
);
// iOS
UiKitView(
viewType: 'native-map',
onPlatformViewCreated: (id) { /* ... */ },
creationParams: {'apiKey': 'xxx'},
creationParamsCodec: const StandardMessageCodec(),
);
// Web
HtmlElementView(
viewType: 'native-map',
);
Register the native view factory on each platform:
// Android
class MapViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
return NativeMapView(context, viewId, args as? Map<*, *>)
}
}
// Register in FlutterPlugin
flutterPluginBinding.platformViewRegistry
.registerViewFactory("native-map", MapViewFactory())
9.8 Known Issues Affecting Integration
| Issue | ID | Impact | Status |
|---|---|---|---|
| Xcode 26 Clang dependency scanning failure | #185210 | iOS/macOS builds may fail | Open |
| OpenGL crashes on MediaTek GPUs | #166248 | Android rendering crashes (132 comments) | Open |
| DartDevelopmentServiceException tool crash | #185234 | DevTools/debug connection failures | Open |
| SystemNavigator.pop doesn't exit on Windows | #66631 | Windows app can't exit programmatically | Open |
--no-hot flag on web-server not working |
#179448 | Web development flag ignored | Open |
| Impeller non-SDF stroked circles hairline | #185222 | Rendering artifacts on thin circles | Open |
| Dart VM GetStack deadlock | #185156 | Debugger hangs | Open |
| AGP 9 disable built-in Kotlin | #183910 | Android build issues with AGP 9 | Open |