Skip to content

Commit

Permalink
[fused lib] Add applyFusedLibraryPlugin gradle recipe
Browse files Browse the repository at this point in the history
Gradle recipe intended to demonstrate Fused Library Plugin configuration
and use cases.

Project depends AGP 8.9.0-alpha03, the first version of the plugin that supports
EAP requirements.

Bug: 346984826
Test: recipe_test target added
Change-Id: I95e674aae9e61c42b97d3a6e1b1f8c665ca817f1
  • Loading branch information
lukeedgargoogle committed Nov 19, 2024
1 parent 2a1bf40 commit 51f1fe1
Show file tree
Hide file tree
Showing 40 changed files with 1,058 additions and 0 deletions.
4 changes: 4 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,7 @@ recipe_test(
recipe_test(
name = "disableTests",
)

recipe_test(
name = "applyFusedLibraryPlugin",
)
173 changes: 173 additions & 0 deletions recipes/applyFusedLibraryPlugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Fused Library Plugin

## What is Fused Library Plugin?

An Android Gradle Plugin that helps Android library developers publish multiple Android libraries in a
single Android library artifact i.e. the '.aar' file.

### *IMPORTANT* - State of the Fused Library Plugin
Fused Library Plugin is currently in an early testing phase. Therefore, artifacts published by the
plugin and plugin behaviour may not be stable at this time. Take caution before distributing
published artifacts created by the plugin; there is no guarantee of correctness.

As an early adopter, please be aware that there may be frequent breaking changes that may require
you to make changes to your project.

### This recipe

This project aims to provide a non-exhaustive, but common examples of plugin usage for consumption
by other libraries.
┌─────────────────────────────────────────┐
:app
│ ▲ │
│ │ │
:fusedLibrary
│ ▲ ▲ │
│ │ │ │
:androidLib2* :androidLib1*
│ ▲ ▲ │
│ │ │ │
:androidLib3 com.google.code.gson:gson*
└─────────────────────────────────────────┘

This diagram shows an overview of the relevant project dependency structure.
* include dependency of :fusedLibrary

Example usages of classes, resources and other artifacts are demonstrated in the :app module unit
and instrumentation tests.

## Usage Guide

### Setting up the Fused Library

*This recipe project was set up with the following key steps*

1. Apply the plugin
gradle/libs.versions.toml append
```kts
[plugins]
...
android-fusedlibrary = { id = "com.android.fusedlibrary", version.ref = "agp" }
```
2. Create a new module. `File` > `New Module...` . Then, click `Android Library` and fill out the
required module metadata. Click `Finish`.
3. In the new module (let's call it `:fusedLibrary`) open the `build.gradle.kts` file,
then replace the `plugins` block with
```
plugins {
alias(libs.plugins.android.fusedlibrary)
}
```
to apply the Fused Library Plugin
4. Fused library modules cannot not contain sources such as code or resources, nor does it use
the typical `implementation` or `api` configurations you may expect to declare as dependencies.
Done.

Fused library introduces a new configuration `include`, that declares what dependencies will be
fused in the built/published .aar file.

For example, the :fusedLibrary could define the following in the `dependencies` block:

```kts
dependencies {
include(project(":androidLib1"))
include(project(":androidLib2"))
include("com.google.code.gson:gson:2.11.0")
include(files("libs/simple-jar-with-A_DoIExist-class.jar"))
}
```

### Building the fused library

1. Check what dependencies will be included in the .aar based on the dependencies configuration
by running `./gradlew :fusedLibrary:report`
Take a look at the report output in the :fusedLibrary build directory
`fusedLibrary/build/reports/fused_library_report/single/report.json`. Check the dependencies that
will be included in the library match your expectations.
2. Once you are satisfied, you can proceed to build the library using
`./gradlew :fusedLibrary:assemble`. Assuming dependencies are valid,
this task produces the .aar fused library at `fusedLibrary/build/bundle/bundle.aar`.
3. Resync project ctrl+shift+O
Done.

At this point you can add the fused library as a dependency from other modules.

### Running the consumption tests

In the :app module there are tests that make use of the classes and resource distributed via
:fusedLibrary.

Run unit tests: `./gradlew :app:testDebugUnitTest --tests "com.example.fusedlibrarysample.FusedLibraryConsumptionUnitTest"`
Run instrumentation tests: `./gradlew :app:connectedDebugAndroidTest`

### Publishing the fused library

Fused Library Plugin artifacts can be easily configured for publication with Maven publishing
plugins. The plugin generates it's own POM for distribution that preserves the artifact dependencies.
We'll provide some typical configurations for publishing that may be useful for most use cases,
however if your needs are more complex, consult the Maven documentation.

Generating the fused lib POM
1. Follow the steps of `Building a fused library`
2. `./gradlew :fusedLibrary:generatePomFileForMavenPublication`
3. The POM should be created at `fusedLibrary/build/publications/maven/pom-default.xml`
Done.

Generating a maven repository with the fused library
1. Add configuration to the fused library build file
```
publishing {
publications {
register<MavenPublication>("release") {
// Customize with your own publication metadata
groupId = "com.my-company"
artifactId = "my-fused-library"
version = "1.0"
afterEvaluate {
// fusedLibraryComponent is required for obtaining fused library artifacts
from(components["fusedLibraryComponent"])
}
}
}
repositories {
maven {
name = "myrepo"
url = uri(layout.buildDirectory.dir("repo"))
}
}
}
```
2. Execute the task for creating the repository `./gradlew fusedLibrary:publishReleasePublicationToMyrepoRepository`
3. As androidLib3 is a project dependency of the fused library, that also needs to be published to
the repository`./gradlew androidLib3:publishReleasePublicationToMyrepoRepository`
4. Note: :app has already configured dependency substitution that prefers the published local repo
artifacts over the :fusedLibrary project itself, so :app now automatically depends on the correct
artifacts.
Done.

### Configurations

| Name | Description |
|---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| include | Specifies components to be fused into the final artifact. Included components are resolvable at runtime. This configuration is not transitive, therefore dependencies will not be included in the fused artifact. There is no support for file dependencies excluding libs/jars. Databinding dependencies are prohibited. |

### How can I report issues?

This plugin remains in early stages, and there may be corner cases that have not been fully tested
or developed.

See open public issues at this link [open issues](https://issuetracker.google.com/issues?q=hotlistid:4053459%20status:open)

Follow the below steps and use this [link to **file new bugs**](https://issuetracker.google.com/issues/new?hotlistIds=4053459&component=147324&template=295401)
**or provide suggestions** for the Fused Library Plugin.

When filing an issue, please include the following information:
1. Steps to reproduce
2. A paste of the exception
3. run `\gradle :\<fused library module\>:report\` and paste the contents of
`\<my library module\>build/reports/fused_library_report/single/report.json`
4.Also consider running \`gradle :\<fused library module\>:dependencies\` if dependency information is relevant
5.\[optional\] if the build was successful, provide a copy of the .aar
Done.
1 change: 1 addition & 0 deletions recipes/applyFusedLibraryPlugin/androidLib1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
64 changes: 64 additions & 0 deletions recipes/applyFusedLibraryPlugin/androidLib1/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.jetbrains.kotlin.android)
}

android {
namespace = "com.example.androidlib1"
compileSdk = 34

defaultConfig {
minSdk = 34

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
sourceSets {
named("main") {
resources.srcDirs("src/main/resources")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}

dependencies {
implementation("com.google.code.gson:gson:2.11.0")
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
Empty file.
21 changes: 21 additions & 0 deletions recipes/applyFusedLibraryPlugin/androidLib1/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"info" : "This is an asset from androidLib1"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.androidlib1


class ClassFromAndroidLib1 {

fun foo(): String {
return "foo"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<resources>
<string name="string_from_androidLib_1">androidLib1</string>
</resources>
1 change: 1 addition & 0 deletions recipes/applyFusedLibraryPlugin/androidLib2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
Loading

0 comments on commit 51f1fe1

Please sign in to comment.