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.
Debugging Method
Before changing code, I isolate whether the issue is Flutter, native platform, dependency, signing, or environment
Read the first real error
Ignore long log noise and find the first failing task, Pod target, Gradle task, or native compiler message.
Check environment
Validate Flutter channel, Xcode, CocoaPods, JDK, Gradle, Android SDK, and local certificates before touching app code.
Clean selectively
Use targeted cleanups for Pods, Gradle, derived data, generated files, or build_runner instead of deleting everything blindly.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Namespace not specified
Seen when: upgrading to newer Android Gradle Plugin.
Check: namespace in android/app/build.gradle and old plugins that need updates.
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.
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.
Keystore password was incorrect
Seen when: release signing task fails.
Check: store password, key password, alias, key.properties path, CI secret encoding, and signingReport.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
Runner.xcworkspace not used
Cause: opening Runner.xcodeproj skips Pods integration.
Fix: open Runner.xcworkspace for native iOS work and archive builds.
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.
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.
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.
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.
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.
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 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.
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.
App crashes when requesting camera, photo, location, or tracking
Cause: missing Info.plist usage description.
Fix: add precise NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSLocationWhenInUseUsageDescription, or tracking strings.
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.
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.
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 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.
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 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 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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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 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 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.
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.
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.
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.
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.
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.
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.
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.
Contact
Ready to discuss senior Flutter, mobile architecture, or product engineering roles
Email: [email protected] · Phone: +91 95672 00188