Your First Step to Contributing: Building Flutter Engine and Framework Development
This guide walks you through setting up and building the Flutter Engine from source, targeting iOS devices, simulators, and the macOS host environment. It also shows how to integrate the custom engine with Flutter Framework for development and debugging, enabling you to contribute to both Engine and Framework layers.
💡 Want to understand Flutter’s architecture better? Check out my companion article: Demystifying Flutter Architecture: Understanding iOS Menu System Through a Restaurant Metaphor where I use a restaurant metaphor to explain how iOS app, Framework, and Engine interact!
💻 Tested on
This guide was tested on the following device:
- Device: MacBook Air 15” (M2, 2023)
- Chip: Apple M2 (ARM64)
- Memory: 8GB
- macOS: Sequoia 15.5
⚠️ Make sure your macOS version is up-to-date and compatible with the latest Xcode version.
If you are located in mainland China, please read the Appendix before proceeding!!!
Phase 1: Environment Setup and Prerequisites
Step 1: Required System Dependencies
(Reference: Setting-up-the-Engine-development-environment.md)
On macOS: install latest Xcode
Make sure your system includes the following tools:
brew install git python3 ninja
Step 2: Clone Flutter Engine Repository & depot_tools
(Reference: engine/README.md)
Next, clone both the main Flutter repository and Google’s depot_tools
. We are grouping all download steps together for efficiency.
Note: In this guide, all repositories are cloned into the home directory (~
). All subsequent paths in this guide assume this location as their base. Please replace it with your own path.
# Clone the main Flutter repository (contains SDK and engine source)
git clone https://github.com/flutter/flutter
# Clone depot_tools, which contains the gclient script
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
Step 3: PATH Setup
Here is a quick explanation of each path’s role:
depot_tools: This path adds the gclient
command, which is essential for syncing the engine’s dependencies. Flutter Engine relies on depot_tools to fetch Dart SDK and third‑party code via gclient
.
Flutter SDK (flutter/bin
): For Application Development. This path is for the standard flutter
command you use every day. Its purpose is to build, run, and manage your applications.
Flutter Engine Tools (engine/src/flutter/bin
): For Engine Development. This path points to the special toolkit for building the engine itself. It provides a crucial, low-level command called et
(Engine Tool) that the engine’s own compilation scripts depend on to function. Simply put, without this path being set correctly, our compilation will fail later on.
Open shell profile file (~/.zshrc
) in your editor and add the following lines. Adjust each <PATH>
to match where you actually cloned or installed each tool.
# Open ~/.zshrc, add depot_tools to your PATH
export PATH="$HOME/depot_tools:$PATH"
# Flutter CLI (SDK)
export PATH="$HOME/flutter/bin:$PATH"
# Engine tool (et)
export PATH="$HOME/flutter/engine/src/flutter/bin:$PATH"
# Apply the PATH changes immediately
source ~/.zshrc
# Verify that gclient from depot_tools is in your PATH
which gclient
# Verify that the Flutter SDK is in your PATH
which flutter
# Verify that the engine tool (et) is in your PATH
which et
Troubleshooting: If you see a command not found
error, it means your PATH
is incorrect. Double-check the export
lines in your ~/.zshrc
file for typos.
Phase 2: Syncing Engine Dependencies
Step 4: gclient Dependency Bootstrap
Flutter engine uses gclient
to manage dependencies.
Set up the .gclient
file in the repository root (the repository root: ~/flutter
), copy the standard gclient configuration file, and then run gclient sync
# IMPORTANT: Navigate to the root of the flutter repository
cd ~/flutter
# Copy the standard gclient configuration file to the root
cp engine/scripts/standard.gclient .gclient
Run the following to sync dependencies:
gclient sync
Just a fair warning, the first time you run this, it takes forever (think 30-60+ mins) because it’s downloading the whole world. So kick it off, go do something else, and come back later. After this initial one, it gets much faster.
Phase 3: Compiling the Engine
Step 5: Compiling Flutter Engine
(Reference: Compiling-the-engine.md)
Choose Your Platform: Compiling for iOS (from macOS)
Build for iOS Device, iOS Simulator, and macOS Host
Why three builds?
- iOS Device: For running on physical iPhones/iPads
- iOS Simulator: For testing on macOS without a physical device
- Host: Tools that run on your Mac to support the Flutter toolchain
cd ~/flutter/engine/src
# Build iOS device-side executable
./flutter/tools/gn --ios --unoptimized
# Run build for iOS device version
ninja -C out/ios_debug_unopt
# For iOS simulator (on arm64 Mac), add --simulator and --simulator-cpu=arm64
./flutter/tools/gn --ios --simulator --unoptimized --simulator-cpu=arm64
# Run build for iOS simulator version
ninja -C out/ios_debug_sim_unopt_arm64
#Build host-side tools with arm64 architecture to avoid Rosetta emulation
./flutter/tools/gn --unoptimized --mac-cpu arm64
# Run build for host-side tools version
ninja -C out/host_debug_unopt_arm64
Step 6: Verify Engine Build Success
After building, you can verify if the outputs are generated by listing the folders:
ls out/
You should see the following folders:
ios_debug_unopt
ios_debug_sim_unopt_arm64
host_debug_unopt_arm64
Phase 4: Integration and Verification
Step 7: Prepare a Test Flutter App
mkdir ~/flutter-engine-tests
cd ~/flutter-engine-tests
flutter create myapp
cd myapp
Then you can use this app project to configure and run with your custom-built engine.
Step 8: Configure and Run iOS Project via Xcode
To use your locally-built engine with the Flutter tool, pass the following two parameters:
--local-engine-src-path
:Specifies the path to your engine repository.
--local-engine
: Specifies which engine build to use (e.g., ios_debug_unopt, host_debug_unopt
_arm64).
Typical invocation:
#Sets up the iOS project but does not build the app, and test on the real iphone
flutter build ios \
--local-engine-src-path ~/flutter/engine/src \
--local-engine-host=host_debug_unopt_arm64 \
--local-engine=ios_debug_unopt \
--config-only
# Explanation:
# --local-engine-src-path: Specifies the path to your engine repository's 'src' directory.
# --local-engine-host: Specifies the locally-built engine used by the Flutter tool itself (running on your macOS host).
# --local-engine: Specifies the locally-built engine that will be bundled with your app for the target device/simulator.
#Opens the project in Xcode for manual run/debug
open ios/Runner.xcworkspace
#Because --config-only only generates the Xcode project setup,
#and open ios/Runner.xcworkspace lets you build and run manually in Xcode,
#which is useful for debugging or stepping through engine code.
Phase 5: Debugging the Engine
Step 9: Debug with Breakpoints
- Open ios/Runner.xcworkspace in Xcode.
- Set breakpoints in engine source code (e.g., FlutterTextInputPlugin.mm).
- In Xcode, go to Debug > Attach to Process, then choose your app.
- Run your Flutter app via
flutter run
or manually from Xcode.
This lets you step into engine code and inspect runtime behavior.
🛠️ Note: Source Code Shows Assembly?
Sometimes, when a breakpoint is hit, Xcode may show assembly code instead of the actual Flutter engine source file. This usually happens when Xcode cannot locate the correct source path.
To fix this:
- Make sure the source path mapping is active in your
~/.lldbinit
file. - The actual path of your Flutter Engine source should exactly match the mapping.
You can add the following line to your ~/.lldbinit
file (update the path as needed):
settings set target.source-map "flutter/" "/path/to/engine/src/flutter/"
💡 Still seeing assembly even after setting the source-map?
Don’t worry — you’re not alone. This issue can sometimes persist even with correct setup. If that happens, don’t get frustrated!
You can try manual LLDB debugging as a workaround:
- Add a
NSLog()
or print statement in your Flutter engine source file to confirm your custom local engine is actually running. - Use
lldb
in the terminal or via Xcode’s debugger console to step through functions manually, even without full source mapping.
This way, you can still check if your local engine build is working, and see if your changes in the engine code are taking effect.
Appendix
1. Network Proxy for Mainland China
If you are located in mainland China, you may encounter network issues when running gclient sync
or accessing Google-hosted dependencies.
To avoid errors like Connection timed out
or Failed to fetch
, it is recommended to temporarily set a proxy in your terminal session before executing the installation steps.
# Set HTTP/HTTPS proxy for the current terminal session
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export all_proxy=socks5://127.0.0.1:7890
Replace 127.0.0.1:7890
with your local proxy address (from Clash, Shadowsocks, V2Ray, etc.) You can also write this in your shell config (~/.zshrc
) if you need it persistently.
2. (Optional) Flutter China Mirror Settings
For faster downloads of Dart/Flutter packages and SDK binaries in mainland China, you can point Flutter to a trusted mirror:
# Dart / Flutter package mirror
export PUB_HOSTED_URL="https://pub.flutter-io.cn"
# Flutter SDK & engine binary mirror
export FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"
Add these to your shell profile (e.g. ~/.zshrc
) before step8. If you later experience missing-package errors, simply unset PUB_HOSTED_URL
or comment it out and rerun your command
Resources
- Flutter Repository
- GET DEPOT TOOLS
gclient
bootstrap- Setting up the Engine development environment
- Compiling the engine
- The
flutter
tool: Using a locally-built engine - Debugging iOS builds with Xcode
- Flutter China Mirror Settings
Copyright & License
© 2025 Jing Shao. All rights reserved.
This article is licensed under CC BY-NC-ND 4.0
What this means:
- ✅ Share — You can share and redistribute this article
- ❌ Commercial — You may not use this for commercial purposes
- ❌ Derivatives — You may not distribute modified versions
- ✅ Attribution — You must give appropriate credit and link to the original
Original article: https://jingshao-code.github.io/posts/2025/07/flutter-engine-guide/
Author: Jing Shao | GitHub | Website |
💡 Found this helpful? Follow me on GitHub and share this guide with your Flutter community!