How to Upgrade Legacy Android Projects to Target SDK 35 with Gradle 8 and JDK 17
Upgrading an old Android project to meet Google Play's new targetSdk 35 requirement involves moving to AGP 8, Gradle 8, and JDK 17, updating namespace, enabling BuildConfig, fixing non‑final resource IDs, and applying JVM arguments to keep ButterKnife functional despite its deprecation.
Background
Google Play now mandates that new app submissions target targetSdk 35. For projects that have been using targetSdk 33, JDK 8, and Gradle 7.x for many years, this creates a cascade of mandatory upgrades: AGP 8+, Gradle 8+, and JDK 17+.
Current (old) project configuration
targetSdk : 33
Gradle : 7.3.1
Kotlin : 1.9.20
JDK : 8
Target configuration for Google Play
targetSdk : 35
Gradle : 8.2.0
Kotlin : 1.9.20
JDK : 17
Key upgrade pain points
❌ JDK 8 → 17
Gradle 8 and AGP 8 require JDK 17. Continuing to use JDK 8 leads to compilation failures such as Unsupported class file major version 61 or NoSuchFieldException: classFile. All Java toolchains, IDE settings, JAVA_HOME, and command‑line java -version must report JDK 17.
❌ Gradle 7 → 8 (DSL changes)
Gradle 8 introduces breaking DSL changes, notably the mandatory namespace declaration and the default disabling of BuildConfig generation.
Required configuration adjustments after upgrade
🔵 1. Declare namespace
android {
namespace 'com.xxx.yyy'
}If omitted, the build fails with
The namespace not specified. Please specify a namespace in the module's build.gradle file.🔵 2. Enable BuildConfig generation
buildFeatures {
viewBinding true
buildConfig true
}Without this, you encounter error: cannot find symbol class BuildConfig.
🔵 3. Use JDK 17 consistently
Android Studio →
Gradle JDK = 17 JAVA_HOMEenvironment variable set to JDK 17
Command line java -version returns 17
🔵 4. Disable nonFinalResIds
ButterKnife expects final R.id.xxx, but Gradle 8 makes resource IDs non‑final by default. Add the following line to gradle.properties:
nonFinalResIds = false🔵 5. Add JVM arguments to open internal JDK modules (core ButterKnife patch)
tasks.withType(JavaCompile).configureEach {
options.fork = true
options.forkOptions.jvmArgs += [
'--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED',
'--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED'
]
}This forces JDK 17 to expose internal compiler APIs so ButterKnife can continue to operate.
ButterKnife specific steps
🔸 1. Keep the last released ButterKnife version
Remove the ButterKnife Gradle plugin from the root build.gradle:
// classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'In each module, keep the library and annotation processor dependencies:
implementation 'com.jakewharton:butterknife:10.2.3'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'🔸 2. Ensure resource IDs are final
Set nonFinalResIds = false in gradle.properties to avoid errors like error: id cannot be resolved or is not a field.
🔸 3. Apply the add-opens JVM arguments shown above
This resolves errors such as
Invalid argument: --add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMEDand cannot access com.sun.tools.javac.tree.JCTree.
Common error summary (useful for debugging)
JDK8/17 mix‑up : Unsupported class file major version 61 Missing namespace : The namespace not specified... BuildConfig missing : cannot find symbol class BuildConfig ButterKnife internal API access : Invalid argument: --add-opens=… or cannot access com.sun.tools.javac.tree.JCTree Non‑final R.id :
error: id cannot be resolved or is not a fieldFinal checklist for migrating an old Android project to targetSdk 35
Upgrade AGP to 8.x and set JDK 17 globally.
Upgrade Gradle to 8.x and declare namespace in every module.
Enable buildConfig true in buildFeatures.
Set nonFinalResIds = false in gradle.properties.
Add the required --add-opens JVM arguments to the JavaCompile task.
Keep ButterKnife 10.2.3 dependencies and remove the deprecated Gradle plugin.
Verify that Kotlin version is at least 1.7.20.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
