ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Fixing Dependency Metadata in Gradle

Anton Popov
ProAndroidDev
Published in
5 min readNov 10, 2022

--

Hi! 👋 Today I’d like to share a story about discovering an interesting niche Gradle API that allows modifying metadata of dependencies published to a maven repo, for example.

The Problem

Recently I was tasked with adding Airbnb’s Showkase to our project. It was kind of easy, but when testing the app in other build types, I encountered a build error:

WTF!?

And so the research started …

Build Types

In the app, we have declared two custom build types: alpha and beta in addition to two default ones: debug and release. It looks like this:

The app successfully compiled only in debug and release. So seems like Showkase doesn’t support custom build types. There is a corresponding issue on GitHub. But I had no time to wait for the fix, so I needed a solution.

The Cause

To understand the root of the problem, we need some background on how Gradle deals with dependencies.

Android Dependency’s Metadata

When an Android library is published to a remote maven repository (e.g. MavenCentral), in addition to .aar files, the Gradle Metadata file is published. It looks like this:

Taken from LeakCanary (source)

Today we will focus on variants and attributes.

Attributes

Some libraries declare special attributes on their versions. In Showkase’s case (no pun intended), two groups of versions were declared (as opposed to LeakCanary’s metadata file):

  • Debug:
debugVariantMavenApiPublication
debugVariantMavenRuntimePublication
debugVariantMavenSourcePublication
debugVariantMavenJavaDocPublication
  • Release
releaseVariantMavenApiPublication
releaseVariantMavenRuntimePublication
releaseVariantMavenSourcePublication
releaseVariantMavenJavaDocPublication

And each of the versions declared an attribute:

This is the cause of the problem. You see, Gradle has a special algorithm called variant aware matching (AGP has it too), that chooses a variant that will be used to build an app by matching attribute values, requested by the AGP with the above-mentioned list of variants.

In our case, the app needs an attribute BuildTypeAttr to have the value alpha, but Showkase’s metadata provides only variants with debug and release values.

If there are no matching variants, the following error occurs:

Execution failed for task ':app:mergeAlphaAssets'.
> Could not resolve all files for configuration ':app:alphaRuntimeClasspath'.
> Could not resolve com.airbnb.android:showkase:1.0.0-beta14.
Required by:
project :app > project :5d-android-sdk:community > project :5d-android-sdk:design-system
> No matching variant of com.airbnb.android:showkase:1.0.0-beta14 was found. The consumer was configured to find a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.1', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' but:
- Variant 'debugVariantMavenApiPublication' capability com.airbnb.android:showkase:1.0.0-beta14:
- Incompatible because this component declares an API of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'debugVariantMavenJavaDocPublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'debugVariantMavenRuntimePublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'debugVariantMavenSourcePublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'releaseVariantMavenApiPublication' capability com.airbnb.android:showkase:1.0.0-beta14:
- Incompatible because this component declares an API of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'releaseVariantMavenJavaDocPublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'releaseVariantMavenRuntimePublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
- Variant 'releaseVariantMavenSourcePublication' capability com.airbnb.android:showkase:1.0.0-beta14 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'alpha'
- Other compatible attributes:
- Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.3.1')
- Doesn't say anything about its target Java environment (preferred optimized for Android)
- Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')

The Solution

The Easy Way

After a lot of googling, I found this article. It suggests doing this:

Using this field, you:

provide matching fallbacks for instances where a direct match is not possible

to the AGP.

That’s it, right? Well, in my case, there was a catch.

The Catch 😭

Schematic module diagram of the project

It turns out, that in a project structure similar to this, you need (not entirely sure why) to specify matchingFallbacks in all build.gradle files. I did this using a root file that we apply to all modules in the project.

Unfortunately, I haven’t realized that need in time, so I went

The Hard Way

We need to somehow modify that metadata JSON file and either:

  1. Add additional variants for each of our build types
  2. Remove an attribute from existing variants

The second option is not possible, because then there will be multiple matching versions, and Gradle will spill out an error.

Metadata Rules

Gradle has an API precisely for that task: Component metadata rules.

In short, we need to declare a class like that:

And then, we can use Showkase in our modules:

Source code of the whole solution:

And….

The build works!! 🎉

That’s all for today, I hope it helps! Feel free to leave a comment if something is not clear or if you have questions. Thank you for reading!

--

--

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Anton Popov

Android Developer who ❤️ Jetpack Compose

Responses (2)

Write a response