← Back to home

Flutter Engineering Field Guide

Common Flutter build issues and how I resolve them

A practical checklist for production Flutter delivery: iOS build failures, Android Gradle issues, Firebase setup, signing, dependency conflicts, flavors, CI/CD, release-store blockers, and post-release debugging.

ScopeBuild, release, CI, Firebase, signing
PlatformsiOS, Android, Play Console, App Store
MethodReproduce, isolate, fix, verify
GoalStable builds and predictable releases

Debugging Method

Before changing code, I isolate whether the issue is Flutter, native platform, dependency, signing, or environment

01

Read the first real error

Ignore long log noise and find the first failing task, Pod target, Gradle task, or native compiler message.

02

Check environment

Validate Flutter channel, Xcode, CocoaPods, JDK, Gradle, Android SDK, and local certificates before touching app code.

03

Clean selectively

Use targeted cleanups for Pods, Gradle, derived data, generated files, or build_runner instead of deleting everything blindly.

04

Verify the release path

Test debug, profile, release, flavor, signing, archive, upload, and store review constraints separately.

Possible Cases

Real symptoms I check when a Flutter build, archive, upload, or production release fails

Case 01 · iOS

No profiles found for bundle identifier

Seen when: Xcode archive fails before signing.

Check: bundle ID, Apple team, profile type, capabilities, and whether flavor bundle IDs have their own profiles.

Case 02 · iOS

Provisioning profile does not include entitlement

Seen when: push notification, associated domains, keychain, or Sign in with Apple is added.

Check: Apple portal capability, regenerated profile, Runner.entitlements, and selected Xcode target.

Case 03 · iOS

Command PhaseScriptExecution failed

Seen when: Xcode build fails during Flutter, Crashlytics, or custom script phase.

Check: script path, executable permission, Flutter root, build mode, dSYM script, and CI environment variables.

Case 04 · iOS

Module not found after pod install

Seen when: Swift import or plugin pod cannot be found.

Check: open .xcworkspace, reinstall pods, target membership, Podfile platform, and DerivedData cache.

Case 05 · iOS

Firebase app not configured

Seen when: app starts then crashes or Firebase logs default app missing.

Check: correct GoogleService-Info.plist, bundle ID match, target membership, and Firebase initialization order.

Case 06 · iOS

Build works on simulator but fails on real device

Seen when: native library, signing, or architecture support differs.

Check: certificate/profile, device UDID for development profile, supported architectures, and device-only permissions.

Case 07 · iOS

Archive uploads but App Store rejects metadata

Seen when: Transporter/App Store Connect validation fails.

Check: icons, launch storyboard, privacy strings, encryption answers, bundle version, build number, and privacy manifest requirements.

Case 08 · iOS

Push notification token is not generated

Seen when: FCM/APNs token is null or notifications never arrive.

Check: APNs key/cert, push capability, notification permission, bundle ID, Firebase project, and background modes.

Case 09 · iOS

Sign in with Apple works in debug but fails in release

Seen when: auth callback or credential validation fails only after archive.

Check: service ID/app ID, associated domain, redirect URL, entitlements, and backend Apple client configuration.

Case 10 · iOS

iOS app crashes after permission request

Seen when: camera, photos, location, Bluetooth, tracking, or contacts prompt is triggered.

Check: Info.plist usage key exists and message explains the permission clearly.

Case 11 · Android

Execution failed for task :app:compileFlutterBuildRelease

Seen when: release build fails before native packaging.

Check: Dart compile errors, missing dart-defines, generated code, assets, obfuscation flags, and flavor entrypoint.

Case 12 · Android

Execution failed for task :app:processReleaseGoogleServices

Seen when: Firebase Gradle processing fails.

Check: google-services.json location, package_name, applicationIdSuffix, flavor folder, and google-services plugin.

Case 13 · Android

Manifest merger failed: android:exported missing

Seen when: target SDK 31+ and activities/services/receivers have intent filters.

Check: add android:exported true/false intentionally in app or update the old plugin causing it.

Case 14 · Android

Duplicate class found

Seen when: two dependencies ship the same class or old support libraries conflict with AndroidX.

Check: dependency tree, exclude duplicate transitive dependency, migrate to AndroidX, and align versions.

Case 15 · Android

Could not find method namespace

Seen when: project/plugin Gradle version is too old for the syntax being used.

Check: Android Gradle Plugin version, Gradle wrapper version, and plugin compatibility.

Case 16 · Android

Namespace not specified

Seen when: upgrading to newer Android Gradle Plugin.

Check: namespace in android/app/build.gradle and old plugins that need updates.

Case 17 · Android

minSdk version is lower than plugin requirement

Seen when: Firebase, auth, payment, map, or media plugins require a higher minSdk.

Check: plugin docs, business device support needs, and raise minSdk only after impact review.

Case 18 · Android

R8 missing class or NoSuchMethodError in release

Seen when: debug works but release crashes immediately or specific SDK fails.

Check: proguard keep rules, reflection-based SDKs, JSON serialization, and Crashlytics release stack trace.

Case 19 · Android

Keystore password was incorrect

Seen when: release signing task fails.

Check: store password, key password, alias, key.properties path, CI secret encoding, and signingReport.

Case 20 · Android

Play Console says app signed with wrong key

Seen when: AAB upload is rejected.

Check: upload key certificate, app signing enrollment, debug vs release key, and flavor signing config.

Case 21 · Android

INSTALL_FAILED_VERSION_DOWNGRADE

Seen when: installing local build over a higher version already on device.

Check: uninstall app, increase versionCode, or install matching build track.

Case 22 · Android

App not installed because package conflicts

Seen when: debug/release/flavor package name collides with existing app.

Check: applicationId, applicationIdSuffix, signing certificate, and installed package on the device.

Case 23 · Android

Cleartext HTTP traffic not permitted

Seen when: API works locally but fails on Android device.

Check: use HTTPS, or add a narrow network security config only for allowed debug/internal endpoints.

Case 24 · Android

Notification permission issue on Android 13+

Seen when: notifications work on old devices but not newer ones.

Check: POST_NOTIFICATIONS runtime permission, channel creation, FCM token, and user permission state.

Case 25 · Flutter

Hot reload works but fresh install fails

Seen when: state survives during dev but initialization breaks on cold start.

Check: startup order, async initialization, Firebase init, dependency injection, secure storage, and routing guards.

Case 26 · Flutter

White screen after splash

Seen when: app opens but no UI appears.

Check: uncaught async errors, initial route, missing env config, release-only API failure, and Crashlytics logs.

Case 27 · Flutter

Unable to load asset

Seen when: image/font/json works in one place but not on another machine or release.

Check: pubspec indentation, exact case-sensitive path, asset folder inclusion, and generated asset references.

Case 28 · Flutter

Generated file missing

Seen when: freezed, json_serializable, retrofit, injectable, router, or l10n classes cannot be found.

Check: run build_runner/gen-l10n, resolve generator errors first, and commit generated files if project policy requires it.

Case 29 · Flutter

Dependency override fixes one plugin and breaks another

Seen when: pub get passes but runtime/build breaks later.

Check: remove broad overrides, inspect dependency graph, upgrade compatible package groups together.

Case 30 · Flutter

Flavor builds call wrong API

Seen when: staging build points to production or production points to staging.

Check: dart-define values, flavor entrypoints, CI variables, native app IDs, and runtime environment banner/logs.

Case 31 · Firebase

Analytics events missing in dashboard

Seen when: app logs events but Firebase does not show them quickly.

Check: DebugView, correct Firebase app, analytics collection settings, event names, consent state, and release build config.

Case 32 · Firebase

Crashlytics not receiving crashes

Seen when: test crash happens but dashboard stays empty.

Check: Crashlytics collection enabled, Firebase app config, mapping/dSYM upload, and whether crash is fatal or caught.

Case 33 · IAP

Product not found

Seen when: store returns empty product list.

Check: product ID spelling, app bundle/package, product status, signed build, tester account, store country, and review status.

Case 34 · IAP

Purchase success but premium not unlocked

Seen when: payment completes but app state does not update.

Check: transaction listener, backend validation, restore flow, user identity mapping, and race between login and store account.

Case 35 · CI/CD

Build passes locally but fails in CI

Seen when: CI lacks local setup files or uses different tool versions.

Check: Flutter version, JDK, Xcode, CocoaPods, generated files, Firebase files, signing secrets, and cache keys.

Case 36 · CI/CD

CI build is green but uploaded build is wrong

Seen when: store receives wrong flavor, icon, name, API, or version.

Check: build matrix, lane/script parameters, artifact names, versionCode/build number, and release notes target.

Case 37 · Store

Play Console data safety mismatch

Seen when: release is blocked or rejected for privacy declarations.

Check: analytics, crash reporting, login, location, contacts, payments, data sharing, and SDK privacy behavior.

Case 38 · Store

App Store asks for demo credentials

Seen when: app has login-gated features.

Check: provide working reviewer login, explain paid flows, include test subscription info if needed, and keep backend test data ready.

Case 39 · Store

Release rejected for background behavior

Seen when: VPN, location, notifications, or background fetch is not justified.

Check: permission purpose, user-facing explanation, policy compliance, and whether background mode is actually necessary.

Case 40 · Production

Only some users see crashes after release

Seen when: issue depends on OS version, device model, locale, account state, or network.

Check: Crashlytics filters, custom keys, app version, device/OS segmentation, logs, and rollout percentage.

Case 41 · Production

ANRs increase after new release

Seen when: Play Console reports input dispatching timeout or main-thread blocking.

Check: startup work, database calls, JSON parsing, sync loops, image processing, and platform channel calls on UI thread.

Case 42 · Production

Login loop after update

Seen when: users return to login repeatedly after installing a new version.

Check: token migration, secure storage keys, refresh endpoint, auth guard, app version migration, and clock skew.

Case 43 · Android Maps

App crashes on screens using Google Maps

Seen when: the app opens normally, but crashes when a map widget or location/map screen loads.

Check: google_maps_flutter version, native Google Maps SDK version, Android Gradle/plugin compatibility, Play Services versions, and Crashlytics native stack trace. If the crash starts after a package upgrade, downgrade Google Maps/related Play Services packages to a stable compatible version and retest on real Android devices.

Case 44 · iOS Archive

Xcode refuses to build even when configuration looks correct

Seen when: signing, pods, bundle ID, and capabilities look right, but Xcode build keeps failing because of Xcode-version/tooling behavior.

Check: after trying the normal fixes, build the iOS target through Android Studio/Flutter tooling first, then return to Xcode and archive the already-prepared project. This can bypass some Xcode-only build-state issues while still using Xcode for final archive/export.

iOS Build Issues

Common iOS failures from CocoaPods, Xcode, signing, Firebase, plugins, and App Store delivery

CocoaPods

Pod install fails

Cause: stale Podfile.lock, repo cache, Ruby/CocoaPods mismatch, or plugin podspec conflict.

Fix: update CocoaPods, run pod repo update when needed, remove Pods/Podfile.lock carefully, then reinstall from the ios folder.

CocoaPods

Minimum iOS deployment target mismatch

Cause: a plugin requires a newer iOS target than the app.

Fix: update platform target in Podfile and Xcode deployment settings, then reinstall pods and rebuild.

Xcode

Runner.xcworkspace not used

Cause: opening Runner.xcodeproj skips Pods integration.

Fix: open Runner.xcworkspace for native iOS work and archive builds.

Signing

Provisioning profile does not match bundle ID

Cause: wrong app identifier, flavor bundle ID, team, or profile.

Fix: align Bundle Identifier, Team, capabilities, provisioning profile, and export options.

Signing

Certificate expired or missing private key

Cause: certificate exists in Apple account but private key is missing locally or in CI.

Fix: import the correct .p12, recreate certificate if needed, and sync CI keychain securely.

Capabilities

Push, Sign in with Apple, Associated Domains fail

Cause: capability enabled in code but not in Apple Developer profile or Xcode target.

Fix: enable capability in Apple portal, regenerate profiles, and verify entitlements file.

Firebase

GoogleService-Info.plist not found

Cause: missing file, wrong target membership, wrong flavor file, or incorrect bundle ID.

Fix: add the correct plist per flavor, enable target membership, and verify Firebase iOS app ID.

Firebase

Crashlytics dSYM upload missing

Cause: dSYMs not generated or upload script not configured for archive.

Fix: enable debug symbols, verify Crashlytics run script, and upload dSYMs for release builds.

Plugins

MissingPluginException on iOS

Cause: plugin not registered, app not fully restarted, custom engine setup, or platform code not included.

Fix: stop app fully, run pub get, rebuild, verify GeneratedPluginRegistrant, and check plugin target setup.

Swift

Swift module or bridging header error

Cause: mixed Swift/Objective-C config, missing Swift version, or plugin native code mismatch.

Fix: set Swift version, ensure bridging header references are valid, and clean DerivedData if Xcode caches stale modules.

Simulator

arm64 simulator architecture issue

Cause: older pods/plugins do not support Apple Silicon simulator architecture cleanly.

Fix: update dependencies first; only use excluded architectures as a last resort for simulator builds.

Permissions

App crashes when requesting camera, photo, location, or tracking

Cause: missing Info.plist usage description.

Fix: add precise NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSLocationWhenInUseUsageDescription, or tracking strings.

Networking

API works on Android but fails on iOS

Cause: App Transport Security blocks insecure HTTP or invalid TLS.

Fix: use HTTPS with valid certificates; add narrow ATS exceptions only when unavoidable.

Archive

Debug works, archive fails

Cause: release-only optimization, signing, bitcode-era settings, missing symbols, or script phase issue.

Fix: build release locally, inspect archive log, verify signing/export method, and check build phases.

App Store

Invalid bundle, icons, privacy, or export compliance

Cause: missing icon sizes, privacy manifest issues, encryption answers, or bundle metadata mismatch.

Fix: validate archive in Organizer, fix asset catalog, privacy strings, and App Store Connect metadata before upload.

Android Build Issues

Common Android failures from Gradle, Kotlin, SDK levels, signing, R8, manifests, and Play Console rules

Gradle

Gradle plugin and wrapper mismatch

Cause: Android Gradle Plugin, Gradle wrapper, Kotlin, or JDK versions are incompatible.

Fix: align AGP, Gradle, Kotlin, Java version, and Flutter template expectations before upgrading more packages.

SDK

compileSdk or targetSdk too low

Cause: plugin or Play Console requires newer SDK levels.

Fix: update compileSdk/targetSdk, install SDK platform/build tools, and resolve new permission behavior.

Namespace

Namespace not specified

Cause: newer Android Gradle Plugin requires namespace in module build.gradle.

Fix: add namespace matching applicationId/package and update old plugins where possible.

Kotlin

Kotlin metadata version error

Cause: plugin compiled with a newer Kotlin version than project uses.

Fix: align Kotlin plugin version with dependency requirements and Flutter compatibility.

Java

Unsupported class file major version

Cause: wrong JDK for Gradle/AGP version.

Fix: use the JDK version expected by the Android Gradle Plugin and configure JAVA_HOME/IDE Gradle JDK.

Manifest

Manifest merger failed

Cause: conflicting permissions, activities, providers, exported flags, or authorities from plugins.

Fix: inspect merged manifest report, add exported flags, resolve provider authorities, and use tools:replace only when justified.

Firebase

google-services.json mismatch

Cause: package name or flavor applicationId does not match Firebase Android app.

Fix: place the correct google-services.json per flavor/source set and verify applicationId.

Firebase

Google services plugin not applied

Cause: Firebase config file exists but Gradle plugin is missing or in wrong file.

Fix: apply com.google.gms.google-services in the app module and keep dependency versions aligned.

R8

Release build crashes but debug works

Cause: R8/proguard strips classes used by reflection, SDKs, serialization, or platform channels.

Fix: add minimal keep rules, test release builds locally, and check Crashlytics stack traces.

Multidex

Dex method limit exceeded

Cause: large dependency graph, Firebase modules, ad SDKs, or old minSdk constraints.

Fix: enable multidex if needed, remove unused SDKs, and review dependency bloat.

Signing

Keystore was tampered with or password incorrect

Cause: wrong keystore, alias, key password, or store password in key.properties/CI secret.

Fix: verify keystore alias and secrets, never regenerate a release key unless Play App Signing recovery is planned.

Signing

Upload key rejected by Play Console

Cause: APK/AAB signed with the wrong key.

Fix: use the registered upload key, check signingReport, and keep debug/release/flavor signing separated.

Resources

Duplicate resource or asset conflict

Cause: plugin resources, launcher icons, localization files, or generated assets collide.

Fix: inspect the duplicate path, rename resources, regenerate icons, and avoid copying assets into native folders unnecessarily.

Native libs

Missing native library for ABI

Cause: plugin ships only some architectures or ABI filters exclude required libraries.

Fix: check jniLibs/ABI filters, include required ABIs, and test on real devices.

Play Store

AAB upload blocked by target SDK, permissions, or policy

Cause: Play Console requires updated target SDK, permission declarations, data safety, or policy forms.

Fix: update target SDK, audit permissions, complete Play Console declarations, and test release builds before upload.

Flutter, Firebase, CI & Release

Cross-platform issues that usually appear around dependencies, flavors, generated code, and release automation

Flutter

pub get dependency solving failed

Cause: SDK constraints, transitive package conflicts, or old pinned versions.

Fix: inspect dependency tree, upgrade packages in small batches, and avoid random dependency_overrides in production.

Generated Code

build_runner conflicts or stale files

Cause: generated files out of sync with models, freezed/json_serializable/router changes.

Fix: run build_runner with delete-conflicting-outputs and commit generated files consistently if the project expects them.

Assets

Unable to load asset

Cause: pubspec indentation, wrong path, case-sensitive filename, or asset missing from bundle.

Fix: fix pubspec assets, run pub get, verify exact filename casing, and test on device.

Localization

Missing generated l10n classes

Cause: ARB syntax error, l10n config issue, or generated files not refreshed.

Fix: validate ARB files, run flutter gen-l10n, and keep localization keys consistent.

Flavors

Wrong API, Firebase app, icon, or app name in flavor

Cause: flavor configs not separated across Dart defines, native bundle IDs, Firebase files, and signing.

Fix: create a flavor matrix and verify each appId/bundleId, Firebase file, entrypoint, icon, name, and signing config.

Environment

Works on one machine, fails on another

Cause: different Flutter channel, Xcode, JDK, SDK, CocoaPods, or cached generated files.

Fix: document tool versions, run doctor, pin CI versions, and avoid relying on local-only files.

CI/CD

CI cannot sign iOS build

Cause: certificates, profiles, keychain, or App Store Connect API key missing in CI.

Fix: configure secure certificate import, profiles, keychain unlock, export options, and API key access.

CI/CD

CI cannot sign Android release

Cause: keystore or key.properties not available in CI secrets.

Fix: inject keystore securely, decode it during CI, and verify signingReport before upload.

Crashlytics

Stack traces are obfuscated or unreadable

Cause: missing mapping files or dSYMs for release builds.

Fix: upload Android mapping files and iOS dSYMs for every release build.

IAP

Purchases work in sandbox but fail in production

Cause: product IDs, store configuration, tester accounts, backend validation, or release status mismatch.

Fix: verify product IDs on both stores, test signed release builds, and validate receipts/transactions server-side.

Platform Channel

Native callback works only after full restart

Cause: hot reload does not re-register native code or plugin setup.

Fix: stop app fully after native changes and rebuild from clean state when touching platform code.

Release QA

Debug build is fine, release has blank screen

Cause: missing permissions, R8 stripping, asset issue, environment variable missing, or release-only API endpoint.

Fix: always test release/profile builds on real devices with production-like config before store upload.

Performance

Jank after release

Cause: heavy work on UI isolate, large images, shader compilation, excessive rebuilds, or slow startup initialization.

Fix: profile in release/profile mode, optimize images, reduce rebuilds, defer startup work, and inspect frame timing.

Networking

API fails only in release

Cause: wrong base URL, missing certificate config, Android network security config, ATS, or environment define.

Fix: verify release dart-defines, network security files, ATS, and server TLS chain.

Store Review

Review rejection for privacy or permissions

Cause: requesting sensitive permissions without clear purpose or mismatched privacy declarations.

Fix: remove unused permissions, explain required access in-app, and align App Store/Play data safety forms.

My approach is simple: reproduce the issue, isolate the layer, fix the smallest responsible cause, then verify on the same build path the user or store will receive. Flutter production work is rarely just Dart code; stable delivery depends on native build systems, store rules, signing, analytics, crash visibility, and release discipline.

Flutter doctorXcodeCocoaPodsGradleKotlinJDKFirebaseCrashlyticsCI/CDPlay ConsoleApp Store Connect

Contact

Ready to discuss senior Flutter, mobile architecture, or product engineering roles