gradle构建工具使用,常用配置

151 阅读4分钟

说明

.gradle采用的groovy语言,而.gradle.kts用的才是kotlin语言,但为了语法高亮,均标识为kotlin

1. 依赖配置dependencies{},implementation...

// build.gradle
dependencies {
    // 语法
    // if not set version: if group is introduced in plugins{}, the version is same to the plugin, else the newest version
    implementation 'groupId:artifactId:version'
    // !!: Mandatory use this dependency
    implementation 'groupId:artifactId:version!!'
    implementation('groupId:artifactId:version') {
        // 只要是关联的子依赖,以groupId开头都会自动排除
        exclude('groupId')
        // exclude group :"com.android.support"
    }
    // 模块
    implementation project(path: ':mod-main')
    implementation project(':mod-main')
    implementation project(':modules:main')
    // 本地库
    implementation files("libs/xxx.aar") // 当前模块的 libs
    implementation files("${rootDir}/libs/xxx.aar") // 项目根目录的 libs
    implementation files("${rootDir}/../libs/xxx.aar")
    // 当前模块的 libs 
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // 区别implementation,compileOnly...
    // 添加到编译路径,即编译时能引用,编译器不报错
    // 进行打包,即运行时能引用,不报错闪退
    // 父模块,指的是依赖该模块的模块
    // 不暴露给父模块,即外部若需要引用子模块中的依赖时,需要自行引入

    /**
     * implementation
     * 添加到编译路径,进行打包,不暴露给父模块
     * 如果主模块依赖的多个子模块都使用`implementation`依赖了同一个库,Gradle的构建系统会智能地处理这种依赖关系,以避免在最终的APK中重复打包相同的库。
     */
    implementation

    /**
     * compileOnly
     * 添加到编译路径,不进行打包,不暴露给父模块
     * 此时要想项目正常运行,需要外部添implementation/api引入该依赖
     * 应用场景:只是引用了该依赖中只定义在{}外的数据,多为常量,如const val USER_INFO_DATA = "user_info_data",此时都不需要父模块再次依耐,但是光给常量单独开个模块合理吗?
     */
    compileOnly

    /**
     * runtimeOnly
     * 不添加到编译路径,进行打包,不暴露给父模块
     * 由于编译报错,直接不能打包
     * 应用场景:
     */
    runtimeOnly 'groupId:artifactId:version'
    // ???等价于
    implementation('groupId:artifactId:version') {
        scope = RuntimeScope.RUNTIME
        optional = true
    }
    
    /**
     * api
     * 添加到编译路径,进行打包,暴露给父模块
     */
    api

    /**
     * annotationProcessor kapt
     * 这两个选项本身不涉及到编译路径或打包,它们是用来处理注解的。
     * 需要注意的是,`annotationProcessor` 和 `kapt` 现在已经逐渐被替代。
     * 对于Java项目,建议使用`annotationProcessorOptions`配合`implementation`或`api`来配置注解处理器。对于Kotlin项目,则推荐使用`kapt`。
     */
    // Java的注解处理器配置
    annotationProcessor
    // Kotlin的注解处理器配置
    kapt

    /**
     * testImplementation
     * 仅在测试编译时需要的依赖,不会打包到最终jar,apk...中。
     */
    testImplementation 'groupId:artifactId:version'
    // ???等价于
    implementation('groupId:artifactId:version') {
        scope = RuntimeScope.Test
    }
    androidTestImplementation
    
    /**
     * developmentOnly
     * 
     */

}

2. 常用环境变量,自定义变量

// .gradle
// 单引号,双引号都可以表示字符串
// 双引号才支持占位符

// 常用环境变量
// 当前模块根路径
println "${projectDir}"
// project 根路径
println "${rootProject.projectDir}"
println "${rootDir}/ainow/common-build.gradle"
println "${project.rootProject.projectDir}./ainow/common-build.gradle"

// 变量使用
// 1. 在config.gradle定义,不要和系统变量冲突
ext {
    //是否单独运行某个module
    isRelease = false

    signingConfig = [
            storePassword: 'xxx',
            keyAlias     : 'xxx',
            keyPassword  : 'xxx'
    ]
}
// 2. 在project's build.gradle中
apply from: "${rootDir}/config.gradle"
//apply from: this.rootProject.file('config.gradle')

// 3. 访问变量
println "${rootProject.isRelease}"
println "${isRelease}"
println "${signingConfig.storePassword}"

3. 配置android{}

通常每个模块独立的配置

// build.gradle
android {
    // new AGP version : use namespace in build.gradle ,instead package attribute in the source AndroidManifest.xml
    // relate to R, databinding, you can use module's resourse by ${namespace}.R.xxx
    // 为包名才可以在AndroidManifest.xml简写 android:name=".MainActivity"
    // 不一定为包名
    namespace 'com.ainow.app'
    // sync 后,会检查该模块的资源是否以该前缀命名,没有以该前缀命名则会在编译时提示错误,但不会阻止编译
    resourcePrefix "app9920_"

    defaultConfig {
        // Application独有
        // Library projects cannot set applicationId.
        applicationId "com.ainow.app" // 系统apk唯一标识,默认为包名,可不同于包名
        versionCode 1
        versionName "1.0"
    }
    compileOptions {
        // 指定了源代码的兼容性级别为Java 17,意味着Java源代码将使用Java 17的特性进行编译,但不一定需要运行在Java 17上(除非targetCompatibility也指定为相同的版本)
        sourceCompatibility JavaVersion.VERSION_17
        // 这指定了编译后的字节码应该与Java 17兼容,意味着您的代码可以在Java 17(或更高版本,通常)上运行。
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        // 告诉Kotlin编译器生成与Java 17兼容的字节码。这是Kotlin特有的配置,因为Kotlin编译成Java字节码。
        jvmTarget = '17'
    }
    buildFeatures {
        dataBinding = true // androidx.databinding.ViewDataBinding
        viewBinding = true // ActivityMainBinding
        buildConfig true // sync后,自动生成BuildConfig类
    }
    viewBinding{
        enable=true
    }
    dataBinding{
        enable=true
    }
}

建议所有子模块应该统一的配置

// build.gradle
android {
    defaultConfig {
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = '17'
    }
}

aar

  • AAR(Android ARchive)是Android开发中使用的二进制分发格式,类似于Java的JAR文件,但专门为Android组件设计。
  • 打包内容
    • 编译后的Java字节码(classes.jar)
    • Android资源文件(res/)
    • Android清单文件(AndroidManifest.xml)
    • 原生库(jni/)
    • 资源索引(R.txt)
    • 可选的ProGuard规则(proguard.txt)
    • 可选的Lint规则(lint.jar)
  • 与JAR的区别
    • AAR包含Android特有的资源文件
    • 支持Android组件(如Activity、Service)
    • 可以包含自定义View的布局文件
    • 支持资源合并(如styles.xml)
  • 使用aar
// library 使用 compile
compile files("${rootDir}/ainow/libs/aznfz.aar")
compile files("${rootDir}/ainow/libs/opencv-4.5.0.aar")
// 然后在 app 使用 implementation
implementation files("${rootDir}/ainow/libs/aznfz.aar")
implementation files("${rootDir}/ainow/libs/opencv-4.5.0.aar")
// 这样才能正常打包,如果在library中implementation,只能在调试时正常使用,打包时时报错:Direct local .aar file dependencies are not supported when building an AAR. 
// 因为 gradle 不允许这么做
  • 打包aar
  • 注意事项
    • 避免在AAR中打包Application类
    • 谨慎处理AndroidManifest合并
    • 为资源添加前缀避免冲突

构建变体

构建release变体发生以下错误
https://www.jianshu.com/p/5838aabe3b4e
https://github.com/cordova-plugin-camera-preview/cordova-plugin-camera-preview/issues/637
最终本项目通过下面步骤解决:
1. ./gradlew updateLintBaseline 自动生成 app/lint-baseline.xml
2. 然后再所有模块build.gradle中添加
android{
    lint {
        baseline = file("lint-baseline.xml")
    }
}
此时成功构建release变体

打包优化

参考:APK包大小优化

4. 命令行

// 构建并运行,若多模块项目中有多个启动类,则都会启动
gradlew bootRun 
// tasks>build

bootJar 完整,可独立运行
jar 最小化

5. build.gradle

/**
 * 暂无用例
 * 让 compileOnly 配置继承 annotationProcessor 配置中的所有依赖
 * 这样,添加到 compileOnly 中的任何库也将被视为注解处理器,但仅在编译时使用,不会在运行时包含在内
 **/
configurations {

    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

其他脚本文件

6. install.gradle

  • 作用 用于将项目发布到本地 Maven 仓库(~/.m2/repository),方便在本地其他项目中直接依赖该库,无需每次修改后重新打包发布到远程仓库。
  • 核心功能 配置 Maven 发布任务,生成 pom.xml、.jar、.aar 等文件并安装到本地。 支持本地开发和调试库项目时的快速迭代。

7. jitpack.gradle

  • 作用 用于配置将 GitHub 仓库自动发布到 JitPack 平台,使其他开发者能直接通过 JitPack 依赖你的 GitHub 项目(无需手动打包或发布到 Maven 仓库)。
  • 核心功能 生成 JitPack 所需的元数据,支持按 GitHub 分支/标签/提交自动构建。 允许其他项目通过 implementation 'com.github.用户名:仓库名:版本号' 直接引用你的库。

小结

  • 本地开发:使用 install.gradle 快速测试库的依赖引用。
  • 开源项目:JitPack 是 GitHub 项目的简单发布方案,但更规范的做法是搭配 CI/CD 工具发布到标准仓库。

感谢