当前位置: 首页 > news >正文

如何共享 Android 不同模块的构建配置

最近想重新梳理学习一遍 Android 的各个知识点,于是新建了一个 AndroidStudy 项目仓库,打算每个知识块新建 1 个 module。
类似这样:

AndroidStudy (Root Project)
├─app (Module0)
├─CustomView (Module1)
├─KotlinCoroutines (Module2)
├─...

然后发现每新建 1 个 Android Library Module 都生成 1 个新的 build.gradle.kts 文件

plugins {alias(libs.plugins.com.android.library)alias(libs.plugins.org.jetbrains.kotlin.android)
}android {namespace = "com.bqliang.mylibrary"compileSdk = 33defaultConfig {minSdk = 26testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"consumerProguardFiles("consumer-rules.pro")}buildTypes {release {isMinifyEnabled = falseproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro")}}compileOptions {sourceCompatibility = JavaVersion.VERSION_1_8targetCompatibility = JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = "1.8"}
}dependencies {implementation(libs.core.ktx)...
}

里面的大部分配置都是重复的,像 compileSdk、minSdk、compileOptions、kotlinOptions… 虽然我以后也不会再去改这些配置了,但是代码洁癖还是让我想把这些重复的配置去掉,经过一番搜索,发现 Gradle Convention Plugin 非常适合解决这个问题。

什么是 Gradle Convention Plugin

为了解决上面的问题,我们自然很容易想到要把其中可以共享的配置抽取出来,然后在每个 module 中引用这些配置。我们可以编写 1 个预编译插件 AndroidLibraryPlugin,在其中去处理这些共享的构建逻辑,然后在需要的 module 中引用这个插件。这样就可以避免重复的配置了,这样的插件就叫做 Gradle Convention Plugin,所以 Gradle Convention Plugin 并不是指某个具体的插件(像 com.android.library),而是指一类插件,这类插件的作用就是抽取出一些共享的构建逻辑。

如何编写 Gradle Convention Plugin

提到预编译插件,很多人知道可以写在 buildSrc 目录下,但是这种方式还是有一些缺点的,比如任何更改都会导致整个项目重新编译,更好的方式是使用复合构建(composite build)

我们新建 1 个 build-logic 项目,文件结构如下,我们将在 AndroidLibraryConventionPlugin 中编写我们的要在 Android Library Module 中共享的构建逻辑。

AndroidStudy (Root Project)
├─...
└─build-logic|  settings.gradle.kts└─ convention|  build.gradle.kts└─ src└─ main└─ kotlin└─ AndroidLibraryConventionPlugin.kt

因为复合构建项目里的构建是完全独立的,所以我们需要在 build-logic/settings.gradle.kts 中声明依赖仓库源,也要显式声明 versionCatalogs

dependencyResolutionManagement {repositories {google()mavenCentral()}versionCatalogs {create("libs") {from(files("../gradle/libs.versions.toml"))}}
}rootProject.name = "build-logic"
include(":convention")

build-logic/convention/build.gradle.kts:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompileplugins {`kotlin-dsl`
}group = "com.bqliang.gradleconventionplugins.buildlogic"// Configure the build-logic plugins to target JDK 17
// This matches the JDK used to build the project, and is not related to what is running on device.
java {sourceCompatibility = JavaVersion.VERSION_17targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType<KotlinCompile>().configureEach {kotlinOptions {jvmTarget = JavaVersion.VERSION_17.toString()}
}dependencies {compileOnly(libs.android.gradlePlugin)compileOnly(libs.kotlin.gradlePlugin)
}gradlePlugin {// register the convention pluginplugins {register("androidLibrary") {id = "bqliang.android.library"implementationClass = "AndroidLibraryConventionPlugin"}}
}

这里的 sourceCompatibility、targetCompatibility、kotlinOptions 只是用来指定编译我们的 Gradle Convention Plugin 的 JDK 版本,和共享的构建逻辑没有关系。文件最后注册了我们的 Gradle Convention Plugin,为了后续方便引用,我们可以把 plugin id 写在 libs.versions.toml 里:

...
[plugins]
bqliang-android-library = { id = "bqliang.android.library", version = "unspecified" }
...

build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt:

import com.android.build.api.dsl.CommonExtension
import com.android.build.gradle.LibraryExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileclass AndroidLibraryConventionPlugin : Plugin<Project> {override fun apply(target: Project) {with(target) {with(pluginManager) {// Android Library Module 都需要这 2 个插件apply("com.android.library")apply("org.jetbrains.kotlin.android")}extensions.configure<LibraryExtension> {configureKotlinAndroid(this)defaultConfig.targetSdk = 34}}}private fun Project.configureKotlinAndroid(commonExtension: CommonExtension<*, *, *, *, *>,) {commonExtension.apply {compileSdk = 34defaultConfig {minSdk = 26}compileOptions {sourceCompatibility = JavaVersion.VERSION_11targetCompatibility = JavaVersion.VERSION_11}}configureKotlin()}private fun Project.configureKotlin() {// Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947tasks.withType<KotlinCompile>().configureEach {kotlinOptions {// Set JVM target to 11jvmTarget = JavaVersion.VERSION_11.toString()}}}
}

注意,目前我们还没有在 root project 中 include 这个 build-logic 项目呢,因为复合构建会把项目里的构建配置包含进来,所以我们不能直接使用 include(“:build-logic”),而是要使用 includeBuild(“build-logic”)

AndroidStudy/settings.gradle.kts:

pluginManagement {includeBuild("build-logic") // include build-logic modulerepositories {google()mavenCentral()gradlePluginPortal()}
}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()}
}rootProject.name = "AndroidStudy"
...

现在我们就可以使用我们的预编译约定插件 AndroidLibraryConventionPlugin 了,回到文章一开始那个 Android Library Module 的 build.gradle.kts,我们可以把里面的大部分配置都去掉了,只是简单的引用一下我们的插件就可以了。

plugins {alias(libs.plugins.bqliang.android.library) // apply our convention plugin
}android {namespace = "com.bqliang.mylibrary"defaultConfig {testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"consumerProguardFiles("consumer-rules.pro")}buildTypes {release {isMinifyEnabled = falseproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro")}}
}dependencies {...
}

当然这里只是把 Android Library Module 的构建逻辑抽取出来了,其实像 Application Module、Jetpack Compose、Room 等等构建逻辑都是可以抽取出来的。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

相关文章:

如何共享 Android 不同模块的构建配置

最近想重新梳理学习一遍 Android 的各个知识点&#xff0c;于是新建了一个 AndroidStudy 项目仓库&#xff0c;打算每个知识块新建 1 个 module。 类似这样&#xff1a; AndroidStudy (Root Project) ├─app (Module0) ├─CustomView (Module1) ├─KotlinCoroutines (Modul…...

atlas运维中遇到的问题

1、java.lang.NoClassDefFoundError&#xff1a;javax/ws/rs/core/Link$Builder 主要原因&#xff1a;jsr311-api包中javax.ws.rs.core包中没有Link类&#xff0c;而Atlas以HBase作为元数据存储&#xff0c;HBase本身使用的为javax.ws.rs-api包中的core包&#xff0c;其中有Lin…...

06-React的路由

06-React的路由 1.相关理解 1).SPA的理解 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。…...

虹科方案 | 加州理工学院利用HK-TrueNAS开展地震研究

一、客户背景 加州理工学院(CalTech)是世界顶尖的理工类科学研究型学府之一。加州理工学院地震实验室是加州理工学院地质与行星科学部(GPS)的一个分支机构&#xff0c;成立于1921年&#xff0c;自20年代以来一直是世界地震学研究中心&#xff0c;并且几十年来一直是媒体对大地…...

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目&#xff0c;部署过程一直跑不通接口&#xff0c;特此记录一下。 在部署的时候&#xff0c;建议第一步把数据库MySql给跑通&#xff0c;中间好多原因是由于数据库的原因给引起的。 一.连接数据库 &#xff08;1&#xff09;在宝塔面…...

联盟链学习笔记-网络的创建

联盟链学习笔记 初始网络 下图是初始网络网络N的参考图 排序服务 在定义 网络 N 的时候&#xff0c;第一件事情就是定义一个 排序服务O4。O4 最初被配置并且由组织 R4 的一个管理员来启动&#xff0c;并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初在…...

System.Drawing.Common.Bitmap跨平台的替代方案

使用SkiaSharp SkiaSharp是Skia Graphics Library的.Net跨平台实现&#xff0c;它可以在Windows&#xff0c;macOS&#xff0c;Linux&#xff0c;iOS&#xff0c;Android和其他平台上使用。 例如需要Linux版&#xff0c;则安装第一个和第四个&#xff1a; 以下是使用SkiaShar…...

深入理解 Java 泛型

没有泛型是怎样的 了解点 Java 历史的都知道,泛型是从 JDK 1.5 版本添加的特性,在 JDK1.5 之前,Java 很多特性都是没有的例如:泛型、注解、自动装箱和拆箱、可变参数。在介绍泛型之前,我们先来看看,如果没有泛型的世界是怎么样的。 假设有一个 List,我只想把 String 类…...

【基础篇】七、Flink核心概念

文章目录 1、并行度2、并行度的设置3、算子链4、禁用算子链5、任务槽6、任务槽和并行度的关系 1、并行度 要处理的数据量很多时&#xff0c;可以把一个算子的操作&#xff08;比如前面demo里的flatMap、sum&#xff09;&#xff0c;"复制"多份到多个节点&#xff0c…...

06-Scala面向对象

面向对象编程 ​ Scala是一门完全面向对象的语言&#xff0c;摒弃了Java中很多不是面向对象的语法。 ​ 虽然如此&#xff0c;但其面向对象思想和 Java的面向对象思想还是一致的 Scala包 1&#xff09;基本语法 Scala中基本的package包语法和 Java 完全一致 例如&#xf…...

【设计模式】单例模式、“多例模式”的实现以及对单例的一些思考

文章目录 1.概述2.单例模式实现代码2.1.饿汉式单例2.2.懒汉式单例2.3.双检锁单例2.4.静态内部类单例2.5.枚举单例 3.对单例的一些思考3.1.是否需要严格的禁止单例被破坏&#xff1f;3.2.懒汉式真的比饿汉式更佳吗&#xff1f;3.3.单例存在的问题 4.其他作用范围的单例模式4.1.线…...

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目 如图所示 我导入了一个git项目后&#xff0c;菜单栏出现了一个git按钮 找不到 导入git项目的按钮了 方式1、 通过idea设置 打开全局设置 如下图 把git先改为none&#xff0c;保存 保存后就可以看到 VCS按钮 导入…...

泛在电力物联网的关键技术与未来发展策略-安科瑞黄安南

摘要: 文章分析了泛在电力物联网的内涵及其主要特征&#xff0c;针对泛在电力物联网的建设目标、基本构架以及关键技术与未来发展策略进行综合探讨&#xff0c;期待得到专业人士的指点。 关键词: 泛在电力物联网&#xff0c; 网络规划&#xff0c; 网络发展 随着能源革命的不…...

iWall:支持自定义的Mac动态壁纸软件

iWall Mac是一款动态壁纸软件&#xff0c;它可以使用任何格式的漂亮视频&#xff08;无须转换&#xff09;、图片、动画、Flash、gif、swf、程序、网页、网站做为您的动态壁纸、动态桌面&#xff0c;并且可以进行交互。 这款软件功能多、使用简单、体积小巧、不占用资源、运行…...

【Docker 内核详解】namespace 资源隔离(四):Mount namespace Network namespace

【Docker 内核详解 - namespace 资源隔离】系列包含&#xff1a; namespace 资源隔离&#xff08;一&#xff09;&#xff1a;进行 namespace API 操作的 4 种方式namespace 资源隔离&#xff08;二&#xff09;&#xff1a;UTS namespace & IPC namespacenamespace 资源隔…...

STM32简介

STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器&#xff0c;常应用在嵌入式领域如&#xff1a; 智能车&#xff08;用stm32做寻迹小车&#xff0c;读取光电传感器或者摄像头数据&#xff0c;然后驱动电机前进和转弯&#xff09;&#xff1b; 无人机&#xff08;用stm3…...

Yum安装JDK11

一、安装命令 &#xff1a; yum install java-11-openjdk二、执行以下命令来查看 JDK 11 的安装信息&#xff1a; yum list installed | grep java-11-openjdk三、找到 JDK 11 的软件包名称&#xff08;使用以下命令来查询软件包的安装位置&#xff09;&#xff1a; rpm -ql…...

[HNCTF 2022 WEEK2]ez_ssrf题目解析

这题主要是引入ssrf这个漏洞攻击&#xff0c;本质上没有更深入的考察 本题是需要我们去伪造一个ssrf的请求头去绕过 题目开始给了我们信息让我们去访问index.php fsockopen函数触发ssrf fsockopen() 函数建立与指定主机和端口的 socket 连接。然后&#xff0c;它将传入的 bas…...

OpenFOAM: twoPhaseEulerFoam解读

twoPhaseEulerFoam全解读之一(转载) 本系列将对OpenFOAM-2.1.1 中的 twoPhaseEulerFoam 求解器进行完全解读&#xff0c;共分三部分&#xff1a;方程推导&#xff0c;代码解读&#xff0c;补充说明。本篇进行方程推导&#xff0c;详细介绍如果从双流体模型出发得到 twoPhaseEu…...

ffmpeg跨平台arm编译-ubuntu

目录 1. 安装必要的编译器2. 安装必要的依赖项3. 配置编译选项4. 编译安装 1. 安装必要的编译器 32位系统&#xff1a; sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabihf sudo apt-get install g-arm-linux-gnueabihf64位系统&#xff1a; sudo apt-get u…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...

【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录

#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…...

【Docker 02】Docker 安装

&#x1f308; 一、各版本的平台支持情况 ⭐ 1. Server 版本 Server 版本的 Docker 就只有个命令行&#xff0c;没有界面。 Platformx86_64 / amd64arm64 / aarch64arm(32 - bit)s390xCentOs√√Debian√√√Fedora√√Raspbian√RHEL√SLES√Ubuntu√√√√Binaries√√√ …...

【汇编逆向系列】四、函数调用包含单个参数之Double类型-mmword,movsd,mulsd,addsd指令,总结汇编的数据类型

一、汇编代码 上一节开始&#xff0c;讲到了很多debug编译独有的汇编方式&#xff0c;为了更好的区分release的编译器优化和debug的区别&#xff0c;从本章节开始将会提供debug和release的汇编用作对比 Debugb编译 single_double_param:00000000000000A0: F2 0F 11 44 24 08…...

stm32—ADC和DAC

ADC和DAC 在嵌入式系统中&#xff0c;微控制器经常需要与现实世界的模拟信号进行交互。STM32微控制器内置了模拟数字转换器&#xff08;ADC&#xff09;和数字模拟转换器&#xff08;DAC&#xff09;&#xff0c;它们是实现这种交互的关键模块。 1. 模拟数字转换器&#xff08…...

matlab模糊控制实现路径规划

路径规划是机器人和自动驾驶系统中的重要问题之一&#xff0c;它涉及确定如何在给定环境中找到最优路径以达到特定目标。模糊控制是一种有效的控制方法&#xff0c;可以应用于路径规划问题。 路径规划算法的目标是在避免障碍物的情况下&#xff0c;找到机器人或车辆从起点到终…...

Three.js + Vue3 加载GLB模型项目代码详解

本说明结合 src/App.vue 代码,详细解释如何在 Vue3 项目中用 three.js 加载并显示 glb 模型。 1. 依赖与插件导入 import {onMounted, onUnmounted } from vue import * as THREE from three import Stats from stats.js import {OrbitControls } from three/examples/jsm/co…...