fat-aar-android icon indicating copy to clipboard operation
fat-aar-android copied to clipboard

Add ability to embed debug versions of aar

Open aasitnikov opened this issue 5 years ago • 4 comments

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:

  • (canBeResolved=false, canBeConsumed=false)
    • "embed"
    • "debugEmbed" extendsFrom "embed"
    • "releaseEmbed" extendsFrom "embed"
  • (canBeResolved=false, canBeConsumed=true)
    • "debugEmbedElements" extendsFrom "debugEmbed" (with attributes and artifact)
    • "releaseEmbedElements" extendsFrom "releaseEmbed" (with attributes and artifact)
  • (canBeResolved=true, canBeConsumed=false)
    • "debugEmbedClasspath" extendsFrom "debugEmbed" (with attributes)
    • "releaseEmbedClasspath" extendsFrom "releaseEmbed" (with attributes)

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

aasitnikov avatar May 12 '20 06:05 aasitnikov

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 avatar Dec 21 '21 10:12 Legion2

@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?

Legion2 avatar Dec 21 '21 13:12 Legion2

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.

aasitnikov avatar Dec 21 '21 18:12 aasitnikov

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

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

Legion2 avatar Dec 22 '21 15:12 Legion2