Is your Ionic or Capacitor Android build failing with Gradle errors, “Unsupported class file major version”, “SDK location not found” or a plugin that does not work after sync? This guide shows how to read the error and fix it in 8 steps, with the exact files and commands to check.
Your Ionic app runs perfectly in the browser, but the moment you open the Android project and press Run, the build fails with a wall of red text such as:
FAILURE: Build failed with an exception.
* What went wrong:Execution failed for task ':app:compileDebugJavaWithJavac'.> Unsupported class file major version 65
SDK location not found. Define a valid SDK location with an ANDROID_HOMEenvironment variable or by setting the sdk.dir path in your project's localproperties file.
Minimum supported Gradle version is X. Current version is Y.
These are three different errors, shown together only as examples. Gradle prints the real cause near the line that says What went wrong, so always read that part first. The exact wording changes between Gradle and Android Studio versions.
Step 1: Get the Full Error Message
Android Studio sometimes hides the useful lines. Run the build from a terminal inside the android folder to see everything, with the stack trace if you need it:
cd android./gradlew assembleDebug --stacktrace# Windows: gradlew.bat assembleDebug --stacktrace
Copy the first error under What went wrong and match it with the table at the end of this post, or with the steps below.
Step 2: Build the Web App and Sync Before You Open Android
Capacitor copies your built web app and your plugins into the native project. If you skip this, you get missing files, old code, or plugins that do not exist on Android. Run these from the project root, not from the android folder:
ionic buildnpx cap sync androidnpx cap open android
With a plain Angular project, replace the first line with npm run build. Two classic messages come from this step:
Could not find the web assets directorymeans the build output folder fromwebDirincapacitor.config.tsdoes not exist yet. Run your build first, and check thatwebDirmatches the real folder name (wwwordist/...)."Camera" plugin is not implemented on android(or any other plugin name) usually means you installed the plugin but did not runnpx cap syncafterwards.
Step 3: Fix Java and JDK Version Errors
Messages like Unsupported class file major version or “requires Java 17 to run” mean Gradle runs on a Java version it does not support. Check what your terminal and Gradle use:
java -versioncd android./gradlew --version
Look at the JVM line in the Gradle output. Recent Capacitor and Android Gradle Plugin versions need a newer JDK than older ones, so check the Capacitor Android documentation for the JDK version your Capacitor version requires. Then fix it in one of these places:
- Android Studio: open the Gradle settings (under Build, Execution, Deployment, Build Tools, Gradle) and choose the JDK bundled with Android Studio as the Gradle JDK. Menu names vary a little between versions.
- Terminal builds: point
JAVA_HOMEto the correct JDK, for example on macOS:export JAVA_HOME=$(/usr/libexec/java_home -v 17).
If you have several JDKs installed, an old one earlier in your PATH is a very common hidden cause.
Step 4: Fix “SDK location not found”
Gradle needs to know where the Android SDK is installed. Create or edit the file android/local.properties and add one line for your system:
# macOSsdk.dir=/Users/yourname/Library/Android/sdk
# Linuxsdk.dir=/home/yourname/Android/Sdk
# Windows (note the escaped colon and backslashes)sdk.dir=C\:\\Users\\yourname\\AppData\\Local\\Android\\Sdk
You can find the real path in Android Studio under the SDK Manager settings. The file is machine-specific, so keep it out of Git. Alternatively, set an ANDROID_HOME environment variable that points to the same folder.
Step 5: Fix Gradle and Android Gradle Plugin Mismatches
Errors such as Minimum supported Gradle version is ... or “plugin requires a newer Gradle” mean the Gradle wrapper and the Android Gradle Plugin (AGP) do not match. The two files to look at are:
android/gradle/wrapper/gradle-wrapper.properties, which sets the Gradle version.android/build.gradle, which sets the Android Gradle Plugin version.
# android/gradle/wrapper/gradle-wrapper.propertiesdistributionUrl=https\://services.gradle.org/distributions/gradle-<version>-all.zip
// android/build.gradleclasspath 'com.android.tools.build:gradle:<version>'
Do not guess the numbers. The Android developer documentation has a compatibility table that lists which Gradle version each AGP version needs. If you recently upgraded Capacitor to a new major version, let the CLI update the native project for you, and then review the changes it made:
npx cap migrate
Android Studio can also offer an upgrade assistant for the Gradle plugin from its Tools menu.
Step 6: Raise compileSdk When a Plugin Needs It
A plugin that was built for a newer Android version can fail with errors such as resource android:attr/lStar not found. That means your app compiles against an SDK that is too old for that plugin. Capacitor keeps these values in android/variables.gradle:
ext { minSdkVersion = 23 compileSdkVersion = 34 // example value only targetSdkVersion = 34 // example value only}
Use the values your Capacitor version generated, and raise compileSdkVersion only as far as the failing plugin needs. Make sure the matching SDK platform is installed in the SDK Manager. Also remember that Google Play requires new apps and updates to target a recent API level, so check the current requirement before you publish.
Step 7: Fix “Could not resolve” Dependency Errors
Messages like Could not resolve all files for configuration or Could not resolve com.android.tools.build:gradle mean Gradle could not download something. Check these in order:
- You are online, and not behind a company proxy or VPN that blocks Google and Maven servers. If you use a proxy, Gradle needs its own proxy settings.
- Your
android/build.gradlelists thegoogle()andmavenCentral()repositories in both thebuildscriptandallprojectssections. - A third-party plugin does not need an extra repository, such as JitPack. Read the plugin documentation for the line to add.
After fixing the cause, run the build again with ./gradlew assembleDebug --refresh-dependencies to force Gradle to download again.
Step 8: Give Gradle More Memory, Then Clean the Build
If you see Java heap space or GC overhead limit exceeded, Gradle ran out of memory. Increase it in android/gradle.properties:
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
Use a higher value, such as 4096m, only if your computer has enough free RAM. When nothing else explains the failure, do a clean rebuild:
cd android./gradlew cleancd ..npx cap sync android
Then in Android Studio use File, Sync Project with Gradle Files. If it still behaves strangely, close the project, delete the android/.gradle and android/app/build folders, and open it again. Android Studio also has an option to invalidate caches and restart.
Bonus: The App Builds but API Calls Fail on Android
Many people fix the build and then find that every request to their own server fails. Two Android-specific causes come first:
- localhost points to the wrong place. On the Android emulator,
localhostmeans the emulator itself. The computer that runs your Node.js API is reachable at10.0.2.2. On a real phone, use your computer’s local network IP address, with both devices on the same Wi-Fi. - Plain HTTP is blocked. Modern Android blocks
http://traffic by default, and the error mentionsERR_CLEARTEXT_NOT_PERMITTED. The proper fix is to use HTTPS. For local development only, you can allow it incapacitor.config.ts:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = { appId: 'com.example.app', appName: 'my-app', webDir: 'www', server: { cleartext: true // development only: allows http:// requests on Android }};
export default config;
Run npx cap sync android after changing this file. Remove the setting before you release your app. If the request then fails with a CORS error, check the origin your Android app sends. In recent Capacitor versions the Android app uses an https://localhost origin by default, while older versions used http://localhost, and you can change it with the server.androidScheme setting. My guide on fixing CORS errors in Node.js, Angular and Ionic shows how to allow these origins.
To see the real console errors from your app on a device, open chrome://inspect in Chrome on your computer and inspect the WebView.
Quick Diagnosis Table
| Error message | Likely cause | Go to |
|---|---|---|
Could not find the web assets directory | Web app not built, or wrong webDir | Step 2 |
plugin is not implemented on android | Plugin not synced | Step 2 |
Unsupported class file major version | Wrong JDK for Gradle | Step 3 |
SDK location not found | Missing local.properties or ANDROID_HOME | Step 4 |
Minimum supported Gradle version | Gradle and AGP versions do not match | Step 5 |
android:attr/lStar not found | compileSdkVersion too low for a plugin | Step 6 |
Could not resolve ... | Network, proxy or missing repository | Step 7 |
Java heap space | Not enough Gradle memory | Step 8 |
ERR_CLEARTEXT_NOT_PERMITTED | Plain HTTP blocked on Android | Bonus section |
Best Practices
- Always run
npx cap syncafter installing, removing or updating a plugin, and after every web build you want to test. - Upgrade Capacitor with
npx cap migrateand read the official upgrade guide for your version. - Keep one JDK version on your
PATHand use the one the Capacitor documentation recommends. - Commit the
androidfolder to Git, but notlocal.propertiesor build output folders. - Change one thing at a time, so you know which step fixed the build.
Conclusion
Android build errors look overwhelming, but each one points at a single layer: your web build, the JDK, the SDK path, the Gradle versions, a plugin’s required SDK, the network, or memory. Read the first line under What went wrong, match it in the table, and fix that layer. After that, remember the Android-specific network rules, so your app can reach your API as well.

0 Comments