Skip to content

Creating an iOS Bitcode enabled app

Jenn Magder edited this page Jul 27, 2022 · 5 revisions

Flutter Wiki


Framework repo

The Flutter CLI Tool

Engine repo



Plugins and packages repos


Release Information

Old documentation

Clone this wiki locally

:warning: 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.

Enabling bitcode on a Flutter app

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.


Xcode settings


Xcode settings

Or with plugins (you can select multiple targets at once by holding shift or cmd while clicking):

Xcode settings with plugins

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:

for development

archive with bitdcode

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).

Building a local engine with bitcode

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.

Additional technical details

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.