Android开发设计nowinandroid构建脚本学习

目录
  • 引言
  • gradle.properties 中的配置
  • 自动安装 git hook
  • 使用 includeBuild 而不是 buildSrc
  • 如何复用 build.gradle 代码?
  • 使用 Version Catalog 管理依赖
  • 代码格式检查
  • 自定义 lint 检查
  • 总结

引言

nowinandroid 项目是谷歌开源的示例项目,它遵循 Android 设计和开发的最佳实践,并旨在成为开发人员的有用参考

这个项目在架构演进,模块化方案,单元测试,Jetpack Compose,启动优化等多个方面都做了很好的示例,的确是一个值得学习的好项目

今天我们来学习一下 nowinandroid 项目的构建脚本,看一下都有哪些值得学习的地方

gradle.properties 中的配置

要看一个项目的构建脚本,我们首先看一下 gradle.properties

# Enable configuration caching between builds.
org.gradle.unsafe.configuration-cache=true
android.useAndroidX=true
# Non-transitive R classes is recommended and is faster/smaller
android.nonTransitiveRClass=true
# Disable build features that are enabled by default,
# https://developer.android.com/studio/releases/gradle-plugin#buildFeatures
android.defaults.buildfeatures.buildconfig=false
android.defaults.buildfeatures.aidl=false
android.defaults.buildfeatures.renderscript=false
android.defaults.buildfeatures.resvalues=false
android.defaults.buildfeatures.shaders=false

可以看出,nowinandroid 项目主要做了以下几个配置

  • 开启配置阶段缓存
  • 开启 androidX,并且移除了 Jetifier
  • 关闭 R 文件传递
  • 关闭 build features

前面3个配置之前都介绍过,我们来看一下关闭 build features

AGP 4.0.0 引入了一种新方法来控制您要启用和停用哪些构建功能,如ViewBindingBuildConfig

我们可以在 gradle.properties 中全局开启或关闭某些功能,也可以在模块级 build.gradle 文件中为每个模块设置相应的选项,如下所示:

android {
    // The default value for each feature is shown below. You can change the value to
    // override the default behavior.
    buildFeatures {
        // Determines whether to generate a BuildConfig class.
        buildConfig = true
        // Determines whether to support View Binding.
        // Note that the viewBinding.enabled property is now deprecated.
        viewBinding = false
        // Determines whether to support Data Binding.
        // Note that the dataBinding.enabled property is now deprecated.
    }
}

通过停用不需要的构建可能,可以提升我们的构建性能,比如我们最熟悉的BuildConfig,每个模块都会生成这样一个类,但其实我们在绝大多数情况下是用不到的,因此其实可以将其默认关闭(在 AGP 8.0 中 BuildConfig 生成已经变成默认关闭了)

自动安装 git hook

有时我们会添加一些 git hook,用于在代码提交或者 push 时做一些检查

但使用 git hook 的一个问题在于,每次拉取新项目之后,都需要手动安装一下 git hook,这一点常常容易被忘记

那么有没有什么办法可以自动安装 git hook 呢?nowinandroid 项目提供了一个示例

// settings.gradle.kts
val prePushHook = file(".git/hooks/pre-push")
val commitMsgHook = file(".git/hooks/commit-msg")
val hooksInstalled = commitMsgHook.exists()
    && prePushHook.exists()
    && prePushHook.readBytes().contentEquals(file("tools/pre-push").readBytes())
if (!hooksInstalled) {
    exec {
        commandLine("tools/setup.sh")
        workingDir = rootProject.projectDir
    }
}

其实原理很简单,在settings.gradle.kts中添加以上代码,这样在 Gradle 同步时,就会自动判断 git hook 有没有被安装,如果没有被安装则自动安装

使用 includeBuild 而不是 buildSrc

pluginManagement {
    includeBuild("build-logic")
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

为了支持在不同的模块间共享构建逻辑,此前我们常常会添加一个 buildSrc 模块

但是 buildSrc 模块的问题在于每次发生修改都会导致项目的绝大多数缓存失效,从而导致构建速度变得极慢

因此官方现在更推荐我们使用 includeBuild,比如 nowinandroid 的构建逻辑就通过 includeBuild 放在了 build-logic 目录

如何复用 build.gradle 代码?

其实我们项目中的各个模块的 build.gradle 中的代码,大部分是重复的,做的都是一些重复的配置,当要修改时就需要一个一个去修改了

nowinandroid 通过抽取重复配置的方式大幅度的减少了 build.gradle 中的代码,如下所示

plugins {
    id("nowinandroid.android.feature")
    id("nowinandroid.android.library.compose")
    id("nowinandroid.android.library.jacoco")
}
android {
    namespace = "com.google.samples.apps.nowinandroid.feature.author"
}
dependencies {
    implementation(libs.kotlinx.datetime)
}

这是 nowinandroid 的一个 feature 模块,可以看出除了每个模块不同的namespace与各个模块的依赖之外,其他的内容都抽取到nowinandroid.android.feature等插件中去了,而这些插件的代码都存放在build-logic 目录中,通过 includeBuild 引入,大家可自行查看

总得来说,通过这种方式可以大幅减少重复配置代码,当配置需要迁移时也更加方便

使用 Version Catalog 管理依赖

在 build.gradle 中添加依赖有以下几个痛点

  • 项目依赖统一管理,在单独文件中配置
  • 不同Module中的依赖版本号统一
  • 添加依赖时支持代码提示

针对这几种需求,Gradle7.0 推出了一个新的特性,使用 Version Catalog 统一依赖版本,它支持以下特性:

  • 对所有 module 可见,可统一管理所有module的依赖
  • 支持声明依赖bundles,即总是一起使用的依赖可以组合在一起
  • 支持版本号与依赖名分离,可以在多个依赖间共享版本号
  • 支持在单独的libs.versions.toml文件中配置依赖
  • 支持代码提示(仅 kts)

noinandroid 中目前已经全面启用了 Version Catalog,如上所示,统一依赖版本,支持代码提示,体验还是不错的

关于 Version Catalog 的具体使用可以查看:【Gradle7.0】依赖统一管理的全新方式,了解一下~

代码格式检查

nowinandroid 作为一个开源项目,不可避免地会有第三方贡献一些代码,因此也需要在代码合并前做一些格式检查,保证代码风格的统一

nowinandroid 通过 spotless 来检查代码格式,主要是通过两种方式触发

  • 通过上面提到的 git hook,在代码 push 时触发检查
  • 通过 github workflow,在代码 push 到 main 分支时触发检查

上面两种方式都会调用以下命令

./gradlew spotlessCheck --init-script gradle/init.gradle.kts --no-configuration-cache --stacktrace

可以看出,这里主要是执行 spotlessCheck 任务,并且指定了 init-script,我们来看一下 init.gradle.kts 里面做了什么

// init.gradle.kts
rootProject {
    subprojects {
        apply<com.diffplug.gradle.spotless.SpotlessPlugin>()
        extensions.configure<com.diffplug.gradle.spotless.SpotlessExtension> {
            kotlin {
                target("**/*.kt")
                targetExclude("**/build/**/*.kt")
                ktlint(ktlintVersion).userData(mapOf("android" to "true"))
                licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
            }
            format("kts") {
                target("**/*.kts")
                targetExclude("**/build/**/*.kts")
                // Look for the first line that doesn't have a block comment (assumed to be the license)
                licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
            }
            format("xml") {
                target("**/*.xml")
                targetExclude("**/build/**/*.xml")
                // Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml)
                licenseHeaderFile(rootProject.file("spotless/copyright.xml"), "(<[^!?])")
            }
        }
    }
}

可以看出,这里指定了对于 kotlin , kts , xml 等文件的格式要求,比如 kotlin 代码需要遵守 ktlint 规范,并且文件开头必须是 license 声明

自定义 lint 检查

除了代码风格的统一,nowinandroid 项目还自定义了一些 lint 检查,跟 spoltess 一样,也是通过 git hook 与 github workflow 两种方式触发,两种方式都会触发以下代码

./gradlew lintDemoDebug --stacktrace

nowinandroid 中有一个自定义的 lint 模块,自定义 lint 规则就定义在这里,如下所示:

class DesignSystemDetector : Detector(), Detector.UastScanner {
    override fun createUastHandler(context: JavaContext): UElementHandler {
        return object : UElementHandler() {
            override fun visitCallExpression(node: UCallExpression) {
                val name = node.methodName ?: return
                val preferredName = METHOD_NAMES[name] ?: return
                reportIssue(context, node, name, preferredName)
            }
            override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) {
                val name = node.receiver.asRenderString()
                val preferredName = RECEIVER_NAMES[name] ?: return
                reportIssue(context, node, name, preferredName)
            }
        }
    }
    companion object {
        @JvmField
        val ISSUE: Issue = Issue.create(
            id = "DesignSystem",
            briefDescription = "Design system",
            explanation = "This check highlights calls in code that use Compose Material " +
                "composables instead of equivalents from the Now in Android design system " +
                "module."
        )
        // Unfortunately :lint is a Java module and thus can't depend on the :core-designsystem
        // Android module, so we can't use composable function references (eg. ::Button.name)
        // instead of hardcoded names.
        val METHOD_NAMES = mapOf(
            "MaterialTheme" to "NiaTheme",
            "Button" to "NiaFilledButton",
            "OutlinedButton" to "NiaOutlinedButton",
            // ...
        )
        val RECEIVER_NAMES = mapOf(
            "Icons" to "NiaIcons"
        )
        fun reportIssue(
            context: JavaContext, node: UElement, name: String, preferredName: String
        ) {
            context.report(
                ISSUE, node, context.getLocation(node),
                "Using $name instead of $preferredName"
            )
        }
    }
}

总得来说,这个自定义规则是检查是否使用了 Compose 的默认 Material 组件而没有使用 nowinandroid 封装好的组件,如果检查不通过则会抛出异常,提醒开发者修改

总结

本文主要介绍了 nowinandroid 项目构建脚本中的一系列小技巧,具体包括以下内容

  • gradle.properties 中的配置
  • 自动安装 git hook
  • 使用 includeBuild 而不是 buildSrc
  • 如何复用 build.gradle 代码?
  • 使用 Version Catalog 管理依赖
  • 代码格式检查
  • 自定义 lint 检查

希望对你有所帮助~

项目地址

github.com/android/now…

以上就是Android开发设计nowinandroid构建脚本学习的详细内容,更多关于Android nowinandroid 构建脚本的资料请关注我们其它相关文章!

(0)

相关推荐

  • android studio 3.0 gradle 打包脚本配置详解

    本文介绍了android studio 3.0 gradle 打包脚本配置,分享给大家,具体如下: 修改输出的名字 保存输出的文件路径 def fileArray = [] //遍历输出文件 android.applicationVariants.all { variant -> variant.outputs.all { output -> def outputFile = output.outputFile if (outputFile != null && outputF

  • 详解基于Android的Appium+Python自动化脚本编写

    1.Appium Appium是一个开源测试自动化框架,可用于原生,混合和移动Web应用程序测试, 它使用WebDriver协议驱动iOS,Android和Windows应用程序. 通过Appium,我们可以模拟点击和屏幕的滑动,可以获取元素的id和classname,还可以根据操作生成相关的脚本代码. 下面开始Appium的配置. appPackage和APPActivity的获取 任意下载一个app 解压 但是解压出来的xml文件可能是乱码,所以我们需要反编译文件. 逆向AndroidMan

  • Android与iOS包体优化及一键自动打包脚本

    目录 系统信息 介绍 安卓APK优化包体大小 一.原理与介绍 二.Flutter代码配置 三.Android代码配置 四.多渠道调试与打包指令 安卓一键打包脚本 一.简单介绍 二.项目路径结构 三.脚本内容 四.脚本使用步骤 苹果优化包体大小 一.常规优化(分发到 App Store 或者 打Ad hoc 测试包) 二.非常规优化 1.Flutter导出IPA(共4步) 2.第一次优化包体大小(共5步) 3.第二次优化包体大小(共6步) 4.一些说明 苹果一键打包脚本 一.简单介绍 二.项目路径

  • Android实现自动截图脚本

    做开发的总会碰到测试或者项目经理问你要某个界面截图的情况,用手机的快捷键截图再上传效率不高,又不太想用手机助手(怕全家桶),便打起Android的ADB命令的主意.adb指令中screencap指令就是截图方法,再通过pull拉取到指定文件夹即可. 这边我对不同的操作系统都进行了相应的整理和使用.windows下为批处理程序,mac下为shell可执行脚本程序. 需注意,脚本使用,都需要先在桌面上新建AndroidScreen文件夹,然后电脑同时只可以连接一台手机(当然这些也都可以完善). Wi

  • 浅谈Android程序与JavaScript脚本的交互

    我们都知道,手机时代的来临的主要标志是啥?能够方便的接入互联网!互联网展现给我们的方式一般都是网页,网页中又必不可少的拥有javascript,所以说,android提供对javascript的支持那是迫在眉睫了,幸好,android早就给我们提供了无缝连接.让我们可以通过android与javascript进行交互. 我们的应用很简单,如图: 我们有一个输入框,旁边有个按钮,点击按钮就会提示我们输入的内容.当然这只是html中最简单的程序了,但是你将这个程序放入android手机中访问下试试,

  • Android之在linux终端执行shell脚本直接打印当前运行app的日志的实现方法

    1.问题 我们一般很多时候会需要在ubuntu终端上打印当前运行app的日志,我们一般常见的做法是 1).获取包名 打开当前运行的app,然后输入如下命令,然后在第一行TASK后面的就可以看到包名 adb shell dumpsys activity top 2).我们的终端安装了pidcat.py脚本,然后执行如下的命令就可以打印当前运行app的全日志, pidcat.py packageName 3).思考,为什么每次都需要这样重复的操作呢?一说到重复,我们应该立马想到是否可以用脚本解决重复

  • Android开发设计nowinandroid构建脚本学习

    目录 引言 gradle.properties 中的配置 自动安装 git hook 使用 includeBuild 而不是 buildSrc 如何复用 build.gradle 代码? 使用 Version Catalog 管理依赖 代码格式检查 自定义 lint 检查 总结 引言 nowinandroid 项目是谷歌开源的示例项目,它遵循 Android 设计和开发的最佳实践,并旨在成为开发人员的有用参考 这个项目在架构演进,模块化方案,单元测试,Jetpack Compose,启动优化等多

  • Android开发笔记之Intent初级学习教程

    本文讲述了Android开发笔记之Intent初级学习教程.分享给大家供大家参考,具体如下: 项目创建步骤: New Android Project-> Project name:Intent Build Target:Android 2.2 Application name:IntentDemo Package name:com.b510.intent.activity Create Activity:MainActivity Min SDK Version:8 Finish 1.拨打电话 按

  • 分享10个很棒的学习Android开发的网站

    我推荐的网站,都是我在学习Android 开发过程中发现的好网站,给初学者一些建议,少走一些弯路. Android Developers 作为一个Android 开发者,官网的资料当然不可错过,从设计,培训,指南,文档,都不应该错过,在以后的学习过程中慢慢理解体会. Android Developer Android Guides - CodePath CodePath 是国外一个技术培训机构,主要培训iOS 和Android 开发,而CodePath 将Android Guides 放在Git

  • Android手机开发设计之记事本功能

    本文实例为大家分享了Android手机开发设计之记事本功能,供大家参考,具体内容如下 一.需求分析 1.1业务需求分析 近年来,随着生活节奏的加快,工作和生活的双重压力全面侵袭着人们,如何避免忘记工作和生活中的诸多事情而造成不良的后果就显得非常重要.为此我们开发一款基于Android系统的简单记事本,其能够便携记录生活和工作对诸多事情,从而帮助人们有效地进行时间管理. 1.2功能需求分析 本记事本项目希望可以开发出一款符合用户生活工作习惯的简单应用,能够满足用户的各方面需求,可以对记事进行增加.

  • Android开发学习路线图

    行业背景: 今天,涉及通信产业链中的每个环节,都有Android的身影,Android是第一款完全完整打通了整个通信产业链中的操作系统,手机方案商.集成商.运营商.内容提供商.用户,都在玩Android,都惊讶于Android的爆发式增长速度,Android现在每天有超过50万台新的Android设备启用.        随着Android平台的扩张,引发了Android人才荒,未来人才需求缺口将达百万.但符合条件的Android工程师屈指可数,企业招聘难度可想而知.据新京报等媒体报道Andro

  • 21天学习android开发教程之MediaPlayer

    本文介绍MediaPlayer的使用.MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了.MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView.SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGL ES库. 先贴出本文程序运行结果的截图,上面是播放/停止音频,可用SeekBar来调进度,下面

  • Android开发学习笔记之通过API接口将LaTex数学函数表达式转化为图片形式

    本文将讲解如何通过codecogs.com和Google.com提供的API接口来将LaTeX数学函数表达式转化为图片形式.具体思路如下: (1)通过EditText获取用户输入的LaTeX数学表达式,然后对表达式格式化使之便于网络传输. (2)将格式化之后的字符串,通过Http请求发送至codecogs.com或者Google.com. (3)获取网站返回的数据流,将其转化为图片,并显示在ImageView上. 具体过程为: 1.获取并格式化LaTeX数学表达式 首先,我们在这个网站输入LaT

  • Android开发学习之WallPaper设置壁纸详细介绍与实例

    今天和大家分享的是关于在Android中设置壁纸的方法,在Android中设置壁纸的方法有三种,分别是: 1.使用WallpaperManager的setResource(int ResourceID)方法 2.使用WallpaperManager的setBitmap(Bitmap bitmap)方法 3.重写ContextWrapper 类中提供的setWallpaper() 除此之外,我们还需要在应用程序中加入下列权限: <uses-permission android:name="a

  • Android开发艺术探索学习笔记(七)

    第七章 Android动画深入分析 Android的动画分为三种:View动画,帧动画,属性动画.帧动画属于View动画. 7.1 View动画 View动画的作用对象是View,共有四种动画效果:平移(Translate),缩放(Scale),旋转(Rotate),透明度(Alpha). 7.1.1 View动画的种类 View动画的保存路径:res/anim/filename.xml.XML格式语法如下: <?xml version="1.0" encoding="

  • Android开发学习路线的七大阶段

    看了专业的培训机构的课程大纲,才知道,自己学习android的路途才刚刚开始!特此整理分享一下,希望能帮到那些准备学习android开发,或者正在学习android开发,但是又没有找到明确路线的童鞋们!(PS:特此声明,这篇文章不是给培训机构做广告哈,本人也是在自学android开发!!) 第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和StringBuffer的使用.正则表达式. 3.面向对象的抽象,封装,继承,多态,类与对象,对象初始化和回收:

随机推荐