Resurrecting a 5-Year-Old Android App: A Developer’s Journey

Siju
3 min readJul 28, 2024

--

Image generated by ChatGPT 4o

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:

  1. 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:

  1. Updating import statements from android.support to androidx packages.
  2. Addressing a change in resource handling in Gradle 8.0+, which required adding android.nonFinalResIds=false to gradle.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:

  1. Start by updating your build tools and Gradle version.
  2. Migrate to AndroidX if you haven’t already.
  3. Pay attention to new Android OS requirements, like explicit exported flags.
  4. 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!

--

--

Siju
Siju

No responses yet