Header Ads

Fix Ionic and Capacitor Android build errors: Gradle and JDK mismatch, SDK location not found, cap sync problems and cleartext API errors.

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_HOME
environment variable or by setting the sdk.dir path in your project's local
properties 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 build
npx cap sync android
npx 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 directory means the build output folder from webDir in capacitor.config.ts does not exist yet. Run your build first, and check that webDir matches the real folder name (www or dist/...).
  • "Camera" plugin is not implemented on android (or any other plugin name) usually means you installed the plugin but did not run npx cap sync afterwards.


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 -version
cd 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_HOME to 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:

# macOS
sdk.dir=/Users/yourname/Library/Android/sdk

# Linux
sdk.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.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-<version>-all.zip

// android/build.gradle
classpath '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.gradle lists the google() and mavenCentral() repositories in both the buildscript and allprojects sections.
  • 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 clean
cd ..
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, localhost means the emulator itself. The computer that runs your Node.js API is reachable at 10.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 mentions ERR_CLEARTEXT_NOT_PERMITTED. The proper fix is to use HTTPS. For local development only, you can allow it in capacitor.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 messageLikely causeGo to
Could not find the web assets directoryWeb app not built, or wrong webDirStep 2
plugin is not implemented on androidPlugin not syncedStep 2
Unsupported class file major versionWrong JDK for GradleStep 3
SDK location not foundMissing local.properties or ANDROID_HOMEStep 4
Minimum supported Gradle versionGradle and AGP versions do not matchStep 5
android:attr/lStar not foundcompileSdkVersion too low for a pluginStep 6
Could not resolve ...Network, proxy or missing repositoryStep 7
Java heap spaceNot enough Gradle memoryStep 8
ERR_CLEARTEXT_NOT_PERMITTEDPlain HTTP blocked on AndroidBonus section


Best Practices

  • Always run npx cap sync after installing, removing or updating a plugin, and after every web build you want to test.
  • Upgrade Capacitor with npx cap migrate and read the official upgrade guide for your version.
  • Keep one JDK version on your PATH and use the one the Capacitor documentation recommends.
  • Commit the android folder to Git, but not local.properties or 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.

Related Guides

Post a Comment

0 Comments