kezong / fat-aar-android

A gradle plugin that merge dependencies into the final aar file works with AGP 3.+
MIT License
3.14k stars 622 forks source link

Add ability to embed debug versions of aar #145

Open aasitnikov opened 4 years ago

aasitnikov commented 4 years ago

Currently plugin only declares "embed" configuration (and variants like debugEmbed), which can only consume "default" configuration of other projects.

To work around this, user have to write this amount of code:

// In project being consumed

configurations {
    debugEmbedElements {
        attributes {
            attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling, Bundling.EMBEDDED))
            attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named(BuildTypeAttr, "release"))
            // /*for flavors*/ attribute(Attribute.of("pricingDimension", ProductFlavorAttr), project.objects.named(ProductFlavorAttr, "paid"))
        }
        canBeConsumed = true
        canBeResolved = false
    }
    // etc
}

afterEvaluate {
    // instead of afterEvaluate android.libraryVariants.all can be used
    artifacts {
        debugEmbedElements tasks.named("bundleDebugAar")
        releaseEmbedElements tasks.named("bundleReleaseAar")
    }
}

// And in consuming project

dependencies {
    debugEmbed project(path: ":some-feature", configuration: "debugEmbedElements")
    releaseEmbed project(path: ":some-feature", configuration: "releaseEmbedElements")
}

This can be done automatically using variant aware matching, that uses attributes. For example "debugEmbedClasspath" will automatically match to project(":someFeature").debugEmbedElements, because each have the same Buldling and BuildTypeAttr attribute values.

So "embed" should only be used for declaring dependencies, "debugEmbedElements" for consuming and "debugEmbedClasspath" for resolving. For example, in simplest case:

For variant aware matching to work, there are these things must be done to plugin:

  1. Add "EmbedElements" and "EmbedClasspath" configurations with right attributes
  2. Resolve artifacts against "***EmbedClasspath", instead of against "embed"
  3. Somehow add "EmbedElements" configurations to projects, that are being embedded - either create them directly if they are absent, or add some miniature plugin to these project that just adds "EmbedElements" configurations.

I've tested this approach with Gradle 5.6.4 and AGP 3.5.3, and don't know if it will work on versions below that

Legion2 commented 2 years ago

This would also resolve problems with AmbiguousConfigurationSelectionException which happens to me when I try to embed an kotlin multipatform project, it contains so many configurations and the embed configuration must choose between them.

Legion2 commented 2 years ago

@aasitnikov EmbedElements configuration is not needed, because EmbedClasspath should have attributes that match the artifiacts in the existing android variants configurations of the consumed projects (releaseRuntimeElements, debugRuntimeElements). or am I wrong?

aasitnikov commented 2 years ago

EmbedElements could be discarded, if AGP would expose configurations with aar artifacts for every variant. And it looks like starting from AGP 3.6.0 they added a lot of configurations with aar artifacts (runtimePublication and apiPublication to name a few), and components for every variant through which these configurations should probably be consumed. But I'm not sure those will be enough to perform attribute matching, because they lack BuildTypeAttr and VariantAttr attributes.

Legion2 commented 2 years ago

All the new configurations are not accessible, so they cannot be used.

        config.setCanBeResolved(false);
        config.setVisible(false);
        config.setCanBeConsumed(false);