在多个应用程序中重复使用 Gradle 模块 在多个应用程序中重复使用 Gradle 模块

2025-06-10

在多个应用程序中重用 Gradle 模块

在多个应用程序中重用 Gradle 模块

在多个应用程序中重用 Gradle 模块

大家好!我从事 Android 开发工作已有一段时间了,不得不说:与十年前相比,如今的应用架构更加清晰,模块化程度也更高。多模块性(或者至少在一个项目中使用几个 Gradle 模块)实际上是现代标准。通常,任何项目都包含主应用模块、多个功能模块以及核心/域/数据模块。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqwe81qbuhtewccjxm3y.png

这些模块以相当标准的方式连接:

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7rn8o6z9szf023fuely.jpg

当你有一个应用程序时,这不是问题:所有模块共存,我们并不真正关心模块之间的连接,当然,我们应该避免循环依赖

事实上,我们当然可以在一个项目中拥有多个应用程序。为此,我们只需要添加另一个:appGradle 模块,android.application在其中声明插件,然后——好了!Android Studio 会显示另一个启动选项。

例如,我们正在开发两个应用:CatsApp,面向猫迷;DogsApp,面向爱狗人士。所有功能均相同(我们有一个显示猫狗列表的屏幕,以及一个显示详细信息的屏幕);只有主要模块有所不同。此外,这些模块中可能声明了不同的网络配置和文件,并且 DI 树的初始化方式也不同。您可以在此处themes.xml找到此类项目的示例

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/euikebi5cbzwz74iqqv9.png

更常见的例子可能是当一个项目有自己的设计系统时,除了主应用程序之外,我们还需要一个演示应用程序来查看我们的 UI 组件。

选项 2

这种情况发生在我们公司内部有两个独立开发的应用程序,业务需求决定将不同的功能整合起来,或者将一个应用程序的所有功能复用到另一个应用程序。
这时,多模块性就能派上用场了,因为我们已经有一段独立的代码,部分代码已准备好复用。同时,这些模块存在于不同的代码库中,彼此之间没有关联,并且各自拥有不同的依赖项列表。
如何整合来自不同项目的模块?首先,我们可以设置一个项目对另一个项目的可见性,只需将它们上传到相邻的目录,并settings.gradle通过将另一个应用程序的模块包含到主项目中来更新主项目即可。

project(':feature-list').projectDir = new File('../app_to_be_reused/feature-list')

include ':feature-details'
project(':feature-details').projectDir = new File('../app_to_be_reused/feature-details')

include ':domain'
project(':domain').projectDir = new File('../app_to_be_reused/domain')

Enter fullscreen mode Exit fullscreen mode

不幸的是,如果我们只需要:feature-list,我们还必须将该模块的依赖项添加到我们的项目中,即拉:domain:feature-details

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9e3e3cbliejsm5ogmb1.jpg

如果我们没有事先准备好重用项目的模块,即使我们只是尝试导入所需的一切并同步主项目,也会导致很多问题。例如,如果我们的可重用:feature-1模块有活动,它们将无法使用主项目中定义的主题:cats-app
此外,这两个项目是不同的 Git 存储库,因此我们必须注意在同步模块时位于正确的分支上。重用项目中的 Gradle 配置很可能已经发生了变化,这就是为什么我们需要始终检查我们是否在正确版本的项目中工作。反过来,这会导致 CI​​ 构建出现问题,现在必须获取两个项目而不是一个,并在同一个管道中构建和测试两个项目。

Git 子模块可以帮我们不少忙。它允许我们将另一个仓库包含到现有仓库中,并使用依赖项标记项目的正确版本。您可以在此处了解更多关于子模块的信息。在这种情况下,依赖关系图将类似于上一个示例中的依赖关系图。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uf4bljovqatrtsp3176r.jpeg

无论如何,作为另一个应用程序的开发者,您将不得不深入研究另一个团队的代码,学习曲线可能相当陡峭。请点击此处查看使用两个项目(其中一个项目链接另一个项目的模块)的示例。

选项 3

此选项基于在单独的 Android 库中发布部分重用应用程序,以便其他应用程序可以链接它并将其用作任何其他第三方 SDK。如果具有依赖项的应用程序相当模块化,则可以尝试导出所需的模块,然后从其他应用程序为它们添加入口点。通常,我们使用 maven -publish Gradle 插件来发布纯 Java/Kotlin 库,但 Android Gradle 插件最近开始支持它,我们现在可以导出 Android 模块,而不仅仅是 Java 库。
这是一个例子。我们的DogsApp由模块appfeature-listfeature-details组成domainFeature-list负责打印有关某只狗的信息和图像。domain包括在所有其他模块中重用的基本信息。

例如,在某个时候,我们公司收购了另一家开发了CatsApp 的初创企业。现在,业务需求决定我们支持新的应用程序并通过添加相同的屏幕来查看猫的详细信息(就像在DogsApp中一样)来更新其功能。由于这些应用程序是分开开发的,它们具有不同的依赖树,我们不能只使用前两种方法,即合并代码库或将我们需要的模块从DogsApp链接到CatsApp中。但我们可以利用库发布。在这种情况下,我们需要发布feature-details
为此,我们将使用maven-publish插件并将以下代码添加到feature-details build.gradle

android {
   ...
   publishing {
       singleVariant('release')
   }
}

afterEvaluate {
   publishing {
       publications {
           release(MavenPublication) {
               from components.release
           }
       }
   }
}
Enter fullscreen mode Exit fullscreen mode

singleVariant指出我们只想发布一个构建选项。为了能够同时使用库的调试版本和发布版本,我们需要使用allVariants()components.default

   ...
   publishing {
      multipleVariants {
         allVariants()
      }
   }
}

afterEvaluate {
   publishing {
       publications {
           allVariants(MavenPublication) {
               from components.default
           }
       }
   }
}
Enter fullscreen mode Exit fullscreen mode

现在我们可以使用命令发布模块了gradle :feature-details:publishToMavenLocal。让我们向CatsApp添加一个本地 Maven 仓库,以便可以使用这个依赖项:

设置.gradle:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
       google()
       mavenCentral()
       mavenLocal()
   }
}
Enter fullscreen mode Exit fullscreen mode

现在,我们可以将依赖项添加到导出的库中cats_app/build.gradle

dependencies {
   ...
   implementation 'com.example:feature-details:1.0.0'
}
Enter fullscreen mode Exit fullscreen mode

但是,当我们尝试构建CatsApp时,由于构建系统找不到该:domain模块,因此会发生构建错误,因此我们也需要发布它。实际上,我们必须递归地发布该:feature-details模块使用的所有依赖项。为此,请删除之前为发布添加的代码,并在根目录build.gradle:feature-details中添加以下内容

subprojects {
   apply plugin: "maven-publish"

   afterEvaluate {
       if (!plugins.hasPlugin("android")) {

           if (plugins.hasPlugin("android-library")) {
               android {
                   publishing {
                       multipleVariants {
                           allVariants()
                       }
                   }
               }
           }

           publishing {
               publications {
                   allVariants(MavenPublication) {
                       afterEvaluate {
                           if (plugins.hasPlugin("java")) {
                               from components.java
                           } else if (plugins.hasPlugin("android-library")) {
                               from components.default
                           }
                       }
                   }
               }
           }
       }
   }
Enter fullscreen mode Exit fullscreen mode

Subprojects {意味着我们要将代码应用到所有子模块。但我们不想发布主模块:dogs-app,因此我们根据 Android 插件的存在将其过滤掉!plugins.hasPlugin("android")。另请注意,它:domain是一个 Java 库,没有构建选项,因此我们不需要向其中添加此信息。我们将仅为 Android 库添加构建选项:

 if (plugins.hasPlugin("android-library")) {
     android {
Enter fullscreen mode Exit fullscreen mode

另外,由于我们同时拥有 Java 和 Android 模块,因此我们必须使用不同的发布方式。如果模块应用了 Java 插件,它将以 Java 库的形式发布;如果应用的是 Android 库插件,我们将发布一组包含相应构建选项的.aar文件。

if (plugins.hasPlugin("java")) {
    from components.java
} else if (plugins.hasPlugin("android-library")) {
    from components.default
}
Enter fullscreen mode Exit fullscreen mode

现在,当我们使用相同的命令发布库时gradle :feature-details:publishToMavenLocal,所有依赖项都将放入本地 Maven 仓库中,客户端应用程序CatsApp将顺利构建。您可以在此处找到完整代码。

你呢?你有没有合并过不同的应用,或者复用过其他团队的 Gradle 依赖?请在评论区分享你公司使用的方法。

鏂囩珷鏉ユ簮锛�https://dev.to/rchugunov/reusing-gradle-modules-in-several-applications-50lk
PREV
300亿及以上
NEXT
Android UI 测试最佳实践 Espresso UI Automator Compose UI 测试 WireMock / MockWebServer OkReplay Barista Kaspresso 结论