Creating an iOS Bitcode enabled app
- Home of the Wiki
- API Reference (stable)
- API Reference (master)
- Contributor Guide
- Chat on Discord
- Design documents
- Code of Conduct
- Issue triage reports
- Our Values
- Tree hygiene
- Issue hygiene and Triage
- Style guide for Flutter repo
- Project teams
- Contributor access
- What should I work on?
- Popular issues
- Running and writing tests
- Release process
- Rolling Dart
- Manual Engine Roll with Breaking Commits
- Updating Material Design Fonts & Icons
- Postmortems and Retrospectives
- Hotfix Documentation Best Practices
- Setting up the Framework development environment
- The Framework architecture
- API Docs code block generation
- Running examples
- Using the Dart analyzer
- The flutter run variants
- Test coverage for package:flutter
- Writing a golden-file test for package:flutter
- Managing template image assets
- Setting up the Engine development environment
- Compiling the engine
- Debugging the engine
- Using Sanitizers with the Flutter Engine
- Testing the engine
- The Engine architecture
- Flutter's modes
- Engine disk footprint
- Comparing AOT Snapshot Sizes
- Custom Flutter engine embedders
- Custom Flutter Engine Embedding in AOT Mode
- Flutter engine operation in AOT Mode
- Engine-specific Service Protocol extensions
- Supporting legacy platforms
- Metal on iOS FAQ
- Engine Clang Tidy Linter
- Why we have a separate engine repo
- Reduce Flutter engine size with MLGO
- Setting up the Plugins development environment
- Setting up the Packages development environment
- Plugins and Packages repository structure
- Plugin Tests
- Contributing to Plugins and Packages
- Releasing a Plugin or Package
- Unexpected Plugins and Packages failures
- Infra Ticket Queue
- Flutter's Build Infrastructure
- Flutter Installation Bundles
- GitHub Action Workflows
- Android Fast Start
- Apple Silicon support
- Desktop shells
- Deferred Components
- JIT release builds
- Making animated GIFs of Flutter apps
- Multi-device debugging in VS Code
- Null safety package migration status
- Running Flutter Driver tests with Web
- Data-driven Fixes
- Flutter CLI custom embedder support
- Bad Builds
Clone this wiki locally
Xcode 14 has has deprecated bitcode submissions, and Flutter will remove bitcode support in a future release.
Bitcode requires that all libraries being built have bitcode enabled, and that they're all built with compatible toolchains. If you're building the engine locally, you must specify the
--bitcode flag to the
gn command, and this will result in building with the local Xcode installation's clang for compatibility reasons. You must also ensure that all plugins are built with bitcode - the best way to do so is to simply try to build with bitcode (instructions below) and see if the build succeeds.
The binaries we ship with the framework now have bitcode, as of version 1.9.6 (some commits earlier than this may have bitcode available as well).
Bitcode takes longer to build, and results in much larger intermediate binaries - since they contain the bitcode representation of your code embedded to be recompiled later. Local testing has shown that binaries are smaller when thinned and rebuilt from bitcode - for example, building the Flutter Gallery with bitcode for an iPhone 8+ results in a 39mb IPA.
During the experimental phase of this rollout, bitcode will not be enabled by default in Flutter application templates. It is very unlikely that we will auto-migrate templates to enable bitcode either, as this could potentially break projects that are consuming other libraries that are not bitcode enabled.
In your Xcode project, ensure that
ENABLE_BITCODE is set to
YES for all targets. Open the xcworkspace in Xcode:
my_flutter_app$ open ios/Runner.xcworkspace
Click on Runner, and then build settings. Ensure that all build settings are visible. Search for
bitcode, and change it to
Yes. Ensure this is done for all targets, including any targets created by the Cocoapods for plugins.
Or with plugins (you can select multiple targets at once by holding shift or cmd while clicking):
You should also remove
config.build_settings['ENABLE_BITCODE'] = 'NO' from the Podfile if you have plugins. For example, you can see how this was done for flutter_gallery.
Now, builds of your project will use bitcode. You can validate this by creating an archive for the product in Xcode and creating distribution artifacts for local development that use bitcode recompilation:
to check on the app size. And of course, you can do this to actually distribute your app (in which case you would not want to pre-thin the app).
The following setps will give you a profile engine with bitcode. GOMA cannot be used because bitcode requires using the Xcode toolchain, which is not GOMA aware.
src$ ./flutter/tools/gn --ios --runtime-mode=profile --no-goma --bitcode src$ ./flutter/tools/gn --runtime-mode=profile # The host does not have to be built with bitcode, and can use GOMA src$ autoninja -C out/ios_profile src$ autoninja -C out/host_profile
If you build your local engine without bitcode, make sure to disable bitcode in your consuming app, as it will otherwise fail to build.
Bitcode can be either
marker or "regular". Marker means that there is no actual bitcode in the binary - we use this for debug and profile builds. This makes the build go faster, and since these builds should not be shipped to the store anyway they do not need to have full bitcode. Release builds get actual bitcode, which embeds blobs of structured data into your binary that can later be recompiled.
Bitcode is meant to be platform independent. Flutter and Dart use assembly code on iOS which is platform specific. These sections of code get annotated with a
__LLVM,__asm section to tell the compiler that they should be left as-is.