乐趣区

关于android:Android-重构-|-持续优化统一管理-Gradle-未完待续

我介意着你的不介意。

前言

借着韩哥哥要求重构的机会,正好好好回顾下以前忘记 / 疏忽的知识点。

记录下无关 Gradle 优化之路:

  • Android 重构 | 对立治理 Gradle 依赖版本
  • Android | 模块化摸索抽取 basic 简化子 module 冗余

大略的方向或者说最终目标精简后如下:

  • 一次援用,全文(我的项目)应用,防止团队合作引入反复依赖;
  • 自带依赖更新提醒;
  • 反对跳转等惯例操作。

最重要的,仍然是便于保护。

从最后的创立 config.gradle 到当初的 basic_depend.gradle,虽说明天更比昨天强,然而仍然不是很称心。

ext 形式尽管是 Google 官网目前举荐,并且以后一些支流库也采纳此种形式,理论应用起来,集体还是有局部不不便。比如说不反对跳转,不反对更新等等,人呐,总想得到更多。

在查阅了多个文档后,再次筹备优化 / 降级一波,持续让韩总蒙圈。

一、buildSrc 搞起来

将官网的形容用 Google 翻译了一边,如下:

简单的构建逻辑通常很适宜作为自定义工作或二进制插件进行封装。自定义工作和插件实现不应存在于构建脚本中。buildSrc 只有不须要在多个独立我的项目之间共享代码,就能够十分不便地应用该代码。

该目录 buildSrc 被视为蕴含的构建。发现目录后,Gradle 会主动编译并测试此代码,并将其放入构建脚本的类门路中。对于多我的项目构建,只能有一个 buildSrc 目录,该目录必须位于根我的项目目录中。buildSrc 应该比脚本插件更可取,因为它更易于保护,重构和测试代码。

buildSrc 应用实用于 Java 和 Groovy 我的项目的雷同源代码约定。它还提供对 Gradle API 的间接拜访。其余依赖项能够在专用的 build.gradle 下申明 buildSrc。

考虑许久,集体简略总结下:

  • buildSrc 存在于 Gradle 编译期;
  • 同样 buildSrc 反对(独自我的项目)共享代码,例如一个我的项目中多个 module 都能够间接调用。

buildSrc 实际

形容下操作步骤:

  • 在我的项目根目录下创立 buildSrc 目录,随后新建 build.gradle.kts 文件;
  • 创立 src 目录,以及对应治理版本文件;
  • 替换间接应用原有依赖

build.gradle.kts 内容如下:

// 导入 Kotlin 插件
import org.gradle.kotlin.dsl.`kotlin-dsl`

plugins {`kotlin-dsl`}

repositories {jcenter()
}

/**
 * 禁用测试报告(Gradle 默认会主动创立测试报告)*/
tasks.withType<Test> {
    reports.html.isEnabled = false
    reports.junitXml.isEnabled = false
}

/**
 *  isFork:将编译器作为独自的过程运行。*  该过程在构建期间将被重用,因而分叉开销很小。分叉的益处是,内存密集型编译是在不同的过程中进行的,从而导致主 Gradle 守护程序中的垃圾回收量大大减少。*  守护程序中较少的垃圾收集意味着 Gradle 的基础架构能够运行得更快,尤其是在您还应用的状况下 --parallel。*
 *  isIncremental:增量编译。Gradle 能够剖析直至单个类级别的依赖关系,以便仅从新编译受更改影响的类。自 Gradle 4.10 起,增量编译是默认设置。*/
tasks.withType<JavaCompile> {
    options.isFork = true
    options.isIncremental = true
}

/**
 * 禁用对于应用实验性 Kotlin 编译器性能的正告
 */
kotlinDslPluginOptions {experimentalWarning.set(false)
}

Dependencies.kt,这是我定义的版本治理的文件,局部内容如下:

@file:Suppress("SpellCheckingInspection")

/**
 * @author HLQ_Struggle
 * @date 2020/7/27
 * @desc 对立治理类
 */

// 对立治理我的项目中的版本信息
object Versions {

    // Build Config
    const val compileSDK = 29       // 编译 SDK 版本
    const val buildTools = "29.0.3" // Gradle 编译我的项目工具版本
    const val minSDK = 23           // 最低兼容 Android 版本
    const val targetSDK = 29        // 最高兼容 Android 版本

    // App Version
    const val appVersionCode = 1           // 以后版本编号
    const val appVersionName = "1.0"       // 以后版本信息

    // Plugins
    const val androidGradlePlugin = "4.0.1"

    // Kotlin
    const val kotlin = "1.3.72"
    const val kotlinxCoroutines = "1.3.5"

    // Support Lib
    const val support = "29.0.3"
    const val appcompat = "1.1.0"
    const val constrainLayout = "1.1.3"

    // Testing
    const val junit = "4.12"
    const val extJunit = "1.1.1"
    const val espresso = "3.2.0"
}

// 对立治理我的项目中应用的依赖库
object Deps {

    // Gradle
    const val androidGradle = "com.android.tools.build:gradle:${Versions.androidGradlePlugin}"

    // Kotlin
    const val kotlinStdLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
    const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
    const val kotlinxCoroutines =
        "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinxCoroutines}"

    // Testing
    const val junit = "junit:junit:${Versions.junit}"
    const val extJunit = "androidx.test.ext:junit:${Versions.extJunit}"
    const val espresso = "androidx.test.espresso:espresso-core:${Versions.espresso}"

    // Android

    const val appcompat = "androidx.appcompat:appcompat:${Versions.appcompat}"
    const val coreKtx = "androidx.core:core-ktx:1.2.0"
    const val constraintLayout =
        "androidx.constraintlayout:constraintlayout:${Versions.constrainLayout}"

    // Fix:对于 64K 援用限度
    const val multiDex = "androidx.multidex:multidex:2.0.1"

    // Jetpack
    const val viewPager2 = "androidx.viewpager2:viewpager2:1.0.0"

    // ...
}

举个两个栗子,如何应用:

  • 根目录下 build 如何应用:

间接通过在 Dependencies 文件中定义的分组名去获取对应的属性即可,如下所示:

buildscript {
    // ...
    dependencies {
        classpath Deps.androidGradle

        classpath Deps.kotlinGradlePlugin

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
// ...
  • 其它 module 目录下 build 如何应用:

同理,当然也能够采纳间接倒入整个对应分组形式,间接应用对应属性,例如:

// 这里采纳间接倒入定义的 Deps 以及 Versions 分组形式
import static Deps.*
import static Versions.*

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {

    // 这里就能够间接应用对应的属性
    compileSdkVersion compileSDK
    buildToolsVersion buildTools

    defaultConfig {
        minSdkVersion minSDK
        targetSdkVersion targetSDK
        versionCode appVersionCode
        versionName appVersionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
    }
    // ...
}

dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])
    // 同理,这里也是一样,间接应用对应的属性名即可
    implementation kotlinStdLib
    implementation appcompat
    implementation coreKtx
    api 'com.google.android.material:material:1.2.0'
    testImplementation junit
    androidTestImplementation extJunit
    androidTestImplementation espresso

    api mmkv
    api 'com.airbnb.android:lottie:3.4.1'
}

这种形式比拟有好的几个特点如下:

  • 反对跳转;
  • 反对智能提醒;
  • Gradle 编译时染指,感脚很湿高大上

然而要害的更新提醒呢?

ummm,不开森。

加个 gif 配图吧~

手动编写 buildSrc 须要留神:

  • 目录构造:例如:buildSrc/src/main/kotlin(java)
  • 在 build.gradle.kts 中增加 jcenter(),否则 kotlin-dsl 加载失败

二、refreshVersions 应用(2020/09/15)

网上搜到对于 refreshVersions 的形容,感觉蛮适合,尝试一波。

大略的劣势在于以下几点:

  • 集中管理依赖
  • 以最小老本提醒依赖降级

操作步骤如下:

Step 1:批改 settings.gradle 文件

// settings.gradle.kts
import de.fayard.refreshVersions.RefreshVersionsSetup

// Here you might have some pluginManagement block:
pluginManagement {//...}

buildscript {repositories { gradlePluginPortal() }
    dependencies.classpath("de.fayard.refreshVersions:refreshVersions:0.9.5")
}

rootProject.name = 'Your Android Project Name'
include ':app'
include ':helper'
include ':weight'
// include other module

RefreshVersionsSetup.bootstrap(settings)

Step 2:同步后执行命令

./gradlew migrateToRefreshVersionsDependenciesConstants --console=plain

依据提醒进行依赖替换:

随后生成 versions.properties 文件:

## suppress inspection "SpellCheckingInspection" for whole file
## suppress inspection "UnusedProperty" for whole file
##
## Dependencies and Plugin versions with their available updates
## Generated by $ ./gradlew refreshVersions
## Please, don't put extra comments in that file yet, keeping them is not supported yet.

version.androidx.appcompat=1.1.0
##             # available=1.2.0-alpha01
##             # available=1.2.0-alpha02
##             # available=1.2.0-alpha03
##             # available=1.2.0-beta01
##             # available=1.2.0-rc01
##             # available=1.2.0-rc02
##             # available=1.2.0
##             # available=1.3.0-alpha01
##             # available=1.3.0-alpha02

version.androidx.core=1.2.0
##        # available=1.3.0-alpha01
##        # available=1.3.0-alpha02
##        # available=1.3.0-beta01
##        # available=1.3.0-rc01
##        # available=1.3.0
##        # available=1.3.1
##        # available=1.4.0-alpha01
##        # available=1.5.0-alpha01
##        # available=1.5.0-alpha02

##。。。

有一点感觉不难受的中央是,它内置了 Android 一部分的依赖,而对于咱们理论开发中应用其它依赖,则显示不太敌对了,如下图:

钻研好一段时间,各种蒙圈,理论的成果还是不是太称心,如果能在 buildSrc 的根底上新增版本更新就更好了。

三、未知

期待能和 buildSrc 联合应用。

心愿有所理解大佬指导一二。

参考资料

  • 配置我的项目全局属性
  • Use buildSrc to abstract imperative logic
  • refreshVersions
退出移动版