As developers, we often face the challenge of maintaining or updating legacy code. Recently, I encountered such a task: building and running an Android app created in 2019. The process was far from smooth, but it offered valuable insights into how rapidly the Android ecosystem evolves.
In this article, I’ll walk you through the hurdles I faced and the solutions that worked, hoping to save fellow developers some time and frustration.
The Initial Roadblock: Gradle Incompatibility
My first obstacle was a cryptic Gradle error:
Unable to find method ''void org.gradle.api.internal.DefaultDomainObjectSet.<init>(java.lang.Class)''
'void org.gradle.api.internal.DefaultDomainObjectSet.<init>(java.lang.Class)'
Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)
Re-download dependencies and sync project (requires network)
The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.
Stop Gradle build processes (requires restart)
Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.
In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.
This one was confusing and re-syncing and restarting Android Studio didn’t help. I decided to update the gradle
version since that seemed an obvious first step.
Here’s what I found.
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
}
That’s quite an old version. Let’s update it to the latest and sync gradle.
dependencies {
classpath 'com.android.tools.build:gradle:8.4.2'
}
Gradle Version Mismatch
Minimum supported Gradle version is 8.6. Current version is 8.5.
Please fix the project's Gradle settings.
Change Gradle version in Gradle wrapper to 8.6 and re-import project
Open Gradle wrapper properties
Gradle Settings.
Seems to be an easy fix. I changed my gradle wrapper to 8.6. Sync is successful and if I build the project, it fails with another error.
Modernizing the Project Structure
With Gradle updated, I encountered a series of issues related to the project’s outdated structure:
- Missing Namespace: Android Studio now requires explicit namespace declaration.
Namespace not specified. Specify a namespace in the module's build file:
I added this to the app build.gradle
.
android {
namespace "com.sj.test"
}
2. Support Library to AndroidX: At this point, I decided to update the support library to AndroidX.
implementation 'com.android.support:appcompat-v7:23.4.0'
becomes
implementation 'androidx.appcompat:appcompat:1.6.1'
and I enabled androidX
in gradle.properties
android.useAndroidX= true
3. Updating compileSdk and targetSdk: The app was targeting an old SDK version. Updating to the latest (34 at the time of writing) resolved compatibility issues with newer AndroidX libraries.
15 issues were found when checking AAR metadata:
1. Dependency 'androidx.appcompat:appcompat-resources:1.6.1' requires libraries and applications that
depend on it to compile against version 33 or later of the
Android APIs.
:app is currently compiled against android-28.
Recommended action: Update this project to use a newer compileSdk
of at least 33, for example 34.
Addressing Android 12+ Requirements
With the basics modernized, I faced a new challenge related to Android 12’s security model:
android:exported needs to be explicitly specified for element <activity#com.sj.test.MainActivity>
This required explicitly setting the exported
flag for activities with intent filters, particularly the MainActivity
.
<activity
android:name=".main.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Final Touches
The last few hurdles involved:
- Updating import statements from
android.support
toandroidx
packages. - Addressing a change in resource handling in Gradle 8.0+, which required adding
android.nonFinalResIds=false
togradle.properties
.
Conclusion
After tackling these issues one by one, the build finally succeeded. This experience underscores the importance of regular updates in Android development. It also highlights how quickly best practices and requirements can change in the mobile development landscape.
For developers facing similar challenges, remember:
- Start by updating your build tools and Gradle version.
- Migrate to
AndroidX
if you haven’t already. - Pay attention to new Android OS requirements, like explicit
exported
flags. - Don’t hesitate to consult the latest Android documentation — it’s your best friend in these situations.
Have you faced similar challenges with legacy Android projects? Share your experiences and tips in the comments below!