16 - Android / Flutter Troubleshooting

Every Windows-specific Gradle and Android build issue we hit while bringing up the eKYC Flutter app, documented with the exact error, the root cause, and the fix. If you're seeing anything weird — search this page first before reaching for Stack Overflow.

Legend

Build build-time error during flutter build or flutter run · Runtime app installs but crashes or misbehaves · Windows Windows-host specific (works fine on macOS/Linux) · Env environment / network configuration issue

1. Gradle "Could not move temporary workspace" Build Windows

SymptomFAILURE: Build failed with an exception. * What went wrong: A problem occurred configuring project ':geolocator_android'. > A build operation failed. Could not move temporary workspace (C:\Users\MAHESH\.gradle\caches\8.11.1\transforms\38fa80aae5a1a7cc09bc90b4e8b70564-c6c798fb-d467-4af2-91b6-2351d4763aac) to immutable location (C:\Users\MAHESH\.gradle\caches\8.11.1\transforms\38fa80aae5a1a7cc09bc90b4e8b70564) > Could not move temporary workspace ... > Failed to notify project evaluation listener. > Could not get unknown property 'android' for project ':geolocator_android' of type org.gradle.api.Project.
Root cause Gradle writes every transformed dependency into a temporary folder first, then renames it to its final location (an atomic move). On Windows, if any process is holding a file handle inside the temporary folder — even for a moment — the rename fails. The "unknown property 'android'" error underneath is a red herring: it happens because the plugin's build.gradle partially executed before the transform exploded, so the android { } DSL extension never got registered.
Fix Clear the broken transform cache and retry.
cd D:\MO_Project\ekyc\flutter_app\android
.\gradlew --stop
cd ..
rmdir /s /q "%USERPROFILE%\.gradle\caches\8.11.1\transforms"
rmdir /s /q "%USERPROFILE%\.gradle\caches\transforms-4"
C:\flutter\bin\flutter clean
C:\flutter\bin\flutter pub get
C:\flutter\bin\flutter build apk --release --dart-define=ENV=prod
If it fails again with the same error, jump to issue #3 below.

2. Cached JARs locked by another Java process Build Windows

Symptomrmdir /s /q "%USERPROFILE%\.gradle\caches\8.11.1\transforms" C:\Users\MAHESH\.gradle\caches\8.11.1\transforms\56FADD~1\TRANSF~1\original\android-gradle.jar - The process cannot access the file because it is being used by another process. rmdir /s /q "%USERPROFILE%\.gradle\caches\transforms-4" C:\Users\MAHESH\.gradle\caches\transforms-4\474042~1\TRANSF~1\original\kotlin-gradle-tooling.jar - The process cannot access the file because it is being used by another process. C:\Users\MAHESH\.gradle\caches\transforms-4\5BA352~1\TRANSF~1\original\android-extensions-ide.jar - The process cannot access the file because it is being used by another process.
Root cause

The file names are the giveaway: kotlin-gradle-tooling.jar, android-extensions-ide.jar, util_rt.jar — these are all used by IDE integration, not a plain CLI build. That means an IDE (Android Studio / IntelliJ / VS Code with the Dart-Flutter plugin) is running in the background and holding the JARs via its own long-lived Gradle daemon and Kotlin daemon.

These IDE-spawned daemons do NOT respond to gradlew --stop because they belong to a different Gradle user directory / different Java process tree.

Fix

Close the IDE fully (File → Exit, not just close the window), then nuke all Java processes.

REM See what Java processes are still alive
tasklist /v /fi "imagename eq java.exe"
tasklist /v /fi "imagename eq javaw.exe"

REM Kill them all (safe if you're not running another Java app)
taskkill /f /im java.exe
taskkill /f /im javaw.exe

REM Now the rmdir from issue #1 will succeed
rmdir /s /q "%USERPROFILE%\.gradle\caches\8.11.1\transforms"

Prevention: don't run flutter build from CLI while Android Studio is open on the same project. Pick one — either use Android Studio's built-in Build → Flutter → Build APK (reuses the running daemon), or fully close the IDE before building from CLI.

3. Cache-corruption error keeps coming back even after clean Build Windows

SymptomBUILD FAILED in 8s * What went wrong: Error resolving plugin [id: 'dev.flutter.flutter-plugin-loader', version: '1.0.0'] > A problem occurred configuring project ':gradle'. > A build operation failed. Could not move temporary workspace (C:\Users\MAHESH\.gradle\caches\8.11.1\transforms\e4b45ae07bb9287ce19139d29ad65fa0-709397f8-82ea-46a3-92f7-ef2be6b182c2) to immutable location ...
Root cause

Same move-failure as issue #1, but on a fresh transform hash — which rules out stale cache as the cause. Something is interfering with .gradle\caches live while Gradle runs, interrupting the atomic rename. On Windows dev boxes it's almost always one of:

  • OneDrive Known Folder Move syncing your user profile
  • Windows Defender real-time scanning
  • Windows Search indexer opening files briefly
  • Third-party AV (Norton, McAfee, Kaspersky, Sophos)

All of these grab transient file handles that race with Gradle's rename operation.

Fix — diagnose first
REM Is your profile actually on OneDrive?
echo %OneDrive%
echo %USERPROFILE%

If %OneDrive% points at C:\Users\...\OneDrive — yes, it's syncing. Move on to the permanent fix in issue #4. If it doesn't, the problem is Defender or AV — add exclusions (see below) and/or relocate the Gradle cache anyway.

4. Relocate Gradle cache with GRADLE_USER_HOME Build Windows

Why this is the permanent fix

Moving the Gradle cache off C:\Users entirely bypasses OneDrive, Defender profile scans, and any user-profile weirdness in one shot. The cache lives on a plain drive folder where nothing messes with it.

Step-by-step
REM 1. Create the new cache folder on a non-synced drive
mkdir D:\gradle-cache

REM 2. Set GRADLE_USER_HOME permanently (writes to user env,
REM    but does NOT update the CURRENT cmd window)
setx GRADLE_USER_HOME "D:\gradle-cache"

REM 3. Also set it for the current session so you can test immediately
set GRADLE_USER_HOME=D:\gradle-cache

REM 4. Verify
echo %GRADLE_USER_HOME%
Add Defender exclusions

Windows Security → Virus & threat protection → Manage settings → Exclusions → Add or remove exclusions → Add an exclusion → Folder:

  • D:\gradle-cache
  • D:\MO_Project\ekyc\flutter_app
  • C:\flutter
Retry the build in a FRESH cmd window
cd D:\MO_Project\ekyc\flutter_app
C:\flutter\bin\flutter clean
C:\flutter\bin\flutter pub get
C:\flutter\bin\flutter build apk --release --dart-define=ENV=prod

First build takes ~8-12 minutes because Gradle re-downloads everything into the new cache. After that, builds are back to normal speed.

Also relocate pub-cache to the same drive

For best results, move Dart's pub cache off C: too so all three caches (Gradle, pub, project) share one drive. This also fixes issue #6 below.

setx PUB_CACHE "D:\pub-cache"
REM Close cmd and reopen (setx only applies to new windows)
cd D:\MO_Project\ekyc\flutter_app
C:\flutter\bin\flutter clean
C:\flutter\bin\flutter pub get      REM re-downloads everything into D:\pub-cache

5. NDK version mismatch warning Build

SymptomYour project is configured with Android NDK 26.3.11579264, but the following plugin(s) depend on a different Android NDK version: - file_picker requires Android NDK 27.0.12077973 - flutter_plugin_android_lifecycle requires Android NDK 27.0.12077973 - geolocator_android requires Android NDK 27.0.12077973 - google_sign_in_android requires Android NDK 27.0.12077973 - image_picker_android requires Android NDK 27.0.12077973 - path_provider_android requires Android NDK 27.0.12077973 - permission_handler_android requires Android NDK 27.0.12077973 - razorpay_flutter requires Android NDK 27.0.12077973 - shared_preferences_android requires Android NDK 27.0.12077973 - sms_autofill requires Android NDK 27.0.12077973 - url_launcher_android requires Android NDK 27.0.12077973 - webview_flutter_android requires Android NDK 27.0.12077973 Fix this issue by using the highest Android NDK version (they are backward compatible).
Root cause

12 plugins declared they need NDK 27 but our android/app/build.gradle.kts pins NDK 26. NDK versions are backward-compatible per Flutter's guidance, so the build still succeeds — but the warning is persistent and a future Play Store lint check may escalate it.

Fix

Edit android/app/build.gradle.kts and pin the highest version:

android {
    namespace = "com.example.ekyc_app"
    compileSdk = flutter.compileSdkVersion
    ndkVersion = "27.0.12077973"     // <- add this

    // ...
}

Make sure NDK 27 is installed (the first build will auto-download it if not — takes a few minutes):

sdkmanager "ndk;27.0.12077973"

6. Kotlin incremental compiler crash (cross-drive paths) Build Windows

Symptome: Daemon compilation failed: null java.lang.Exception at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69) ... Caused by: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\MAHESH\AppData\Local\Pub\Cache\hosted\pub.dev\shared_preferences_android-2.4.13\android\src\main\kotlin\io\flutter\plugins\sharedpreferences\MessagesAsync.g.kt and D:\MO_Project\ekyc\flutter_app\android. at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:22)
Root cause

Known bug in Kotlin's incremental compilation on Windows. When the project is on one drive (D:) but pub cache is on another (C:), Kotlin IC calls kotlin.io.FilesKt.relativeTo() to compute a relative path between them. Windows File.relativeTo() throws IllegalArgumentException because you can't relativize paths across drive roots — there's no common ancestor.

Fix — disable Kotlin incremental compilation

Open android/gradle.properties and add:

# Workaround for Kotlin IC crash when pub cache and project are on
# different drives (Windows). See frontend/16-android-troubleshooting.
kotlin.incremental=false
kotlin.incremental.multiplatform=false
kotlin.incremental.js=false

This is a targeted workaround — full rebuilds are unaffected, only incremental re-compile is a tiny bit slower.

Better long-term fix

Move PUB_CACHE to the same drive as the project so Kotlin IC can compute paths normally. Then you can re-enable incremental compilation.

setx PUB_CACHE "D:\pub-cache"
REM Close cmd, reopen
cd D:\MO_Project\ekyc\flutter_app
C:\flutter\bin\flutter clean
C:\flutter\bin\flutter pub get

After pub cache is on D:, remove the kotlin.incremental=false line from gradle.properties for snappier rebuilds.

7. "Could not get unknown property 'android' for project ':xyz_android'" Build

Symptom> Failed to notify project evaluation listener. > Could not get unknown property 'android' for project ':geolocator_android' of type org.gradle.api.Project. > Could not get unknown property 'android' for project ':geolocator_android' of type org.gradle.api.Project.
Root cause (usually misleading)

This is almost never about the plugin itself. It's a cascading failure: an earlier build step (usually a transform cache corruption — issue #1) killed the plugin's build.gradle.kts halfway through execution. The apply plugin: 'com.android.library' line runs, but the transform explosion prevents the android { } DSL extension from being registered. The very next reference to android throws "unknown property".

Fix

You don't fix this error directly — fix issue #1 (the transform cache problem) and this error disappears on its own. If you've done the full reset in issue #4 and it still appears, something is very wrong — check that the plugin actually exists in %PUB_CACHE%\hosted\pub.dev\, re-run flutter pub get, and check flutter doctor -v for red flags.

8. FormatException at character 1 <!DOCTYPE...> Runtime Env

Symptom (shown on Stage 0 arrival screen)Get Failed: FormatException: Unexpected character (at character 1) <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> ^
Root cause

The app's ApiService called jsonDecode() on a response body that is HTML, not JSON. The server returned a default 404 page, an nginx welcome page, or an IIS error page — the <!DOCTYPE ... EN> string is the XHTML doctype used by old server error templates.

Most common reason: the URL in lib/config/api_config.dart for the chosen --dart-define=ENV=... value doesn't point at a running eKYC backend.

Diagnosis — probe the URL directly
curl -v https://your-backend-url/api/v1/journey/init?device_type=DESKTOP
  • JSON blob → backend is fine, problem is in the Flutter app
  • HTML / 404 / nginx welcome → backend is wrong, fix the URL
  • Connection refused / timeout → backend is down or unreachable
Fix — point at a real backend

Edit lib/config/api_config.dart and update the URL for your target environment, or build against the correct ENV:

// Local dev
flutter build apk --release --dart-define=ENV=dev

// UAT
flutter build apk --release --dart-define=ENV=uat

// Prod
flutter build apk --release --dart-define=ENV=prod

Cross-link: See 09 - Config & Environments for the full environment flag reference.

9. Emulator can't reach host localhost Runtime Env

Background

Inside the Android emulator, localhost (and 127.0.0.1) means the emulator itself — not your Windows host. If the app's ENV=dev URL is http://localhost:5000 and your backend runs on the Windows host, the emulator's HTTP call goes nowhere and you get a connection error or the HTML 404 from issue #8.

Option A — adb reverse (recommended)

Forward the emulator's port 5000 back to your host. The existing localhost:5000 URL in api_config.dart then just works without any code change.

REM 1. Run backend bound to all interfaces
cd D:\MO_Project\ekyc\backend\src\MO.Ekyc.Api
dotnet run --urls http://0.0.0.0:5000

REM 2. In a second cmd window: forward the port
adb devices
adb reverse tcp:5000 tcp:5000
adb reverse --list

REM 3. In a third cmd window: run the app
cd D:\MO_Project\ekyc\flutter_app
C:\flutter\bin\flutter run --dart-define=ENV=dev
Option B — use the magic 10.0.2.2 IP

The Android emulator reserves 10.0.2.2 as an alias for the host machine's loopback. Change the dev URL in api_config.dart:

case 'dev':
default:
  return 'http://10.0.2.2:5000';
Option C — physical device on LAN

Use the host machine's actual LAN IP (find with ipconfig):

case 'dev':
  return 'http://192.168.1.42:5000';   // your host LAN IP

Make sure the backend binds to 0.0.0.0 (not localhost) and that Windows Firewall allows port 5000 inbound.

10. Release APK blocks cleartext HTTP Runtime

Background

Android 9+ blocks plain HTTP by default in release builds. Debug builds are exempt (via a generated network security config that allows localhost and 10.0.2.2) — release builds are not. If you build with flutter build apk --release --dart-define=ENV=dev and the dev URL is http://..., the app installs but every API call fails silently with a connection error.

Recommended — use flutter run for local testing

For local dev, just don't build release APKs. Debug mode is faster, has hot reload, shows debug logs, and allows cleartext HTTP out of the box:

cd D:\MO_Project\ekyc\flutter_app
C:\flutter\bin\flutter run --dart-define=ENV=dev
If you really need a release APK against a local HTTP backend

Temporarily allow cleartext in android/app/src/main/AndroidManifest.xml:

<application
    android:label="ekyc_app"
    android:usesCleartextTraffic="true"
    android:name="${applicationName}"
    android:icon="@mipmap/ic_launcher">
Remove this before shipping a real release

Never ship a production release build with usesCleartextTraffic="true". It opens the app to man-in-the-middle attacks. Either remove the attribute before building prod, or use a build-variant-scoped network_security_config.xml that only allows cleartext in debug/dev flavours.

11. Prevention checklist for a new Windows dev machine Windows

Do these once when setting up a fresh Windows dev box
  1. Move all build caches off C:\Users:
    setx GRADLE_USER_HOME "D:\gradle-cache"
    setx PUB_CACHE        "D:\pub-cache"
    setx ANDROID_USER_HOME "D:\android"
    setx ANDROID_SDK_ROOT "D:\android-sdk"
    Close and reopen every cmd window to pick up the new values.
  2. Add Windows Defender exclusions for:
    • D:\gradle-cache
    • D:\pub-cache
    • D:\android, D:\android-sdk
    • D:\MO_Project\ekyc (the whole project root)
    • C:\flutter (the Flutter SDK install)
  3. Disable OneDrive Known Folder Move or make sure your C:\Users\<you> isn't redirected into OneDrive. OneDrive + Gradle cache is a disaster combination.
  4. Don't run CLI build + IDE concurrently on the same Flutter project. The IDE spawns its own long-lived Gradle and Kotlin daemons that hold file handles indefinitely.
  5. Never commit .gradle/, build/, .dart_tool/. They're already in .gitignore at the repo root — keep them that way.
  6. Don't install Flutter inside C:\Program Files. It's a protected path and flutter upgrade will fail. Use C:\flutter or D:\flutter.
  7. Stop and restart gradlew --stop before any long operation — clean, pub get, upgrade. This clears any zombie daemon that might hold the cache.

See also