Skip to content

Gradle配置

基本配置

首先,在基础配置信息中我建议引入 org.ajoberstar.grgit 插件《插件地址》Grgit 是一个用于操作 Git 仓库的 Gradle 插件。

通过引入这个插件我们能获取很多Git仓库相关的信息,比如提交的commit id,打的版本TAG标识等等,我们可以在打包配置中把这些信息记录在文件名字上,很方便。

第一步

配置仓库地址。

kotlin
maven {
    // jitpack仓库
    setUrl("https://jitpack.io")
}
groovy
maven {
    // jitpack仓库
    url 'https://jitpack.io' 
}

🌟 🌟 🌟 官方文档说:从 5.0.0 开始,grgit 仅发布到 Maven Central 仓库,就不用再配置 jitpack 仓库了。

第二步

在项目根目录的 build.gradle 文件中引入插件,将以 5.0.0 版本作为示例。

kotlin
plugins {
    // grgit插件
    id("org.ajoberstar.grgit") version "5.0.0" apply false
}
groovy

plugins {
    // grgit插件
    id 'org.ajoberstar.grgit' version '5.0.0' apply false
}

Gradle 低版本适配

Gradle 7.0 之前的 buildscript 用法:

在Grgit 4.1.1 以上版本是不支持 Gradle 7.0 以下版本的。

《Grgit版本发行说明》

《Grgit文档站点》

groovy
// 配置构建脚本所需的类路径依赖
buildscript {
    
    // 定义用于下载依赖项的仓库
    repositories {
        // 从 Maven 中央仓库获取插件和依赖
        mavenCentral()
    }

    // 定义构建脚本的类路径依赖
    dependencies {
        
        // 这里添加 Grgit 插件(用于 Git 操作)库
        classpath 'org.ajoberstar.grgit:grgit-gradle:4.1.1'
    }
}

第三步

在项目的 app 主模块中,找到build.gradle 文件,并引用插件。

kotlin
plugins {
    id("org.ajoberstar.grgit")
}

/**
 * 获取当前时间戳->单位秒
 */
fun versionTimestamp(): Int {
    return (System.currentTimeMillis() / 1000).toInt()
}

// 获取Git提交短链commit值
val gitAbbreviatedId: String = grgit.head().abbreviatedId

// 获取Git版本描述信息
val gitVersionName: String? = grgit.describe()

// 获取最新的TAG标识
val tags = grgit.tag.list().filter { it.commit == grgit.head() }

// 获取版本TAG
val gitVersionTag: String? = if (tags.isNotEmpty()) tags.first().name else gitVersionName ?: "V0.0"

android {
    namespace = "com.zt.dynamicanalyzer"
    // 编译源码版本
    compileSdk = 34

    defaultConfig {
        applicationId = "com.zt.dynamicanalyzer"
        // 最低适配版本
        minSdk = 19
        // 目标适配版本
        targetSdk = 34
        // 版本号(采用时间戳,每次打包不用操心更改版本号)
        versionCode = versionTimestamp()
        // 版本名采用TAG标签的值(一般就是:V1.0、V1.1、等等)
        versionName = "$gitVersionTag"
        // MultiDex 开关(作用是允许应用代码拆分成多个Dex文件,以避免方法数超过65,536个的限制。)
        multiDexEnabled = true
    }
}
groovy
plugins {
    id 'org.ajoberstar.grgit'
}

/**
 * 获取当前时间戳 -> 单位秒
 */
static def versionTimestamp() {
    return (System.currentTimeMillis() / 1000) as int
}

// 获取Git提交短链commit值
def gitAbbreviatedId = grgit.head().abbreviatedId

// 获取Git版本描述信息
def gitVersionName = grgit.describe()

// 获取最新的TAG标识
def tags = grgit.tag.list().findAll { it.commit == grgit.head() }

// 获取版本TAG
def gitVersionTag = tags ? tags[0].name : (gitVersionName ?: "V0.0")

android {
    namespace 'com.zt.dynamicanalyzer'
    // 编译源码版本
    compileSdk 34

    defaultConfig {
        applicationId 'com.zt.dynamicanalyzer'
        // 最低适配版本
        minSdk 19
        // 目标适配版本
        targetSdk 34
        // 版本号(采用时间戳,每次打包不用操心更改版本号)
        versionCode versionTimestamp()
        // 版本名采用TAG标签的值(一般就是:V1.0、V1.1、等等)
        versionName "$gitVersionTag"
        // MultiDex 开关(作用是允许应用代码拆分成多个Dex文件,以避免方法数超过65,536个的限制)
        multiDexEnabled true
    }
}

Gradle 低版本适配

另外,在Gradle 7.0 版本之前,引用插件的写法:

groovy
// 应用 grgit 插件
apply plugin: 'org.ajoberstar.grgit'

Android项目的Gradle基础配置整体比较基础,这里就不过多赘述了。

签名配置

在打包应用时,我们经常要给应用进行签名,我们可以在 build.gradle 文件中添加签名配置。好处是可以简化手动打包的繁琐流程,也可以避免打包时选错签名文件、输错密码等问题。而且还能自由配置多版本打包的签名配置。

第一步

在项目根目录(不是包名根目录)创建一个 signatures 目录(目录名能自由填写),把签名文件放进去。

app/
signatures/
 └──key.jks # 签名文件

第二步

gradle.properties 配置文件中定义签名配置信息

properties
# 应用打包的签名配置
signFile=../signatures/key.jks
signAlias=签名别名
signPassword=签名密码
signKeyPassword=签名密钥密码

第三步

build.gradle 文件中编写签名配置。

kotlin
android {
    
    // 签名配置
    signingConfigs {
        
        create("release") {
            storeFile = file(project.property("signFile") as String)
            keyAlias = project.property("signAlias") as String
            storePassword = project.property("signPassword") as String
            keyPassword = project.property("signKeyPassword") as String
        }
    }

    buildTypes {
        
        release {
            // ...
            // 引用发布版签名
            signingConfig = signingConfigs.getByName("release")
        }
    }
}
groovy
android {

    // 签名配置
    signingConfigs {
        
        release {
            storeFile file(project.property("signFile"))
            storePassword project.property("signPassword")
            keyAlias project.property("signAlias")
            keyPassword project.property("signKeyPassword")
        }
    }
    
    buildTypes {
        
        release {
            // ...
            // 引用发布版签名
            signingConfig signingConfigs.release
        }
    }
}

这样就完成了,可以去点Build > Build App Bundle(s)/Apk(s) > Build Apk(s) 选项一键打包了。

注意

然后值得注意的是签名配置不仅仅是一项技术操作,它也关乎应用的安全、可信度以及后续版本的管理。因此,请务必认真对待签名配置,确保密钥安全并避免泄漏。

然后关于签名的推荐文章:《Apk 签名的那些事》

多版本打包

通过区分不同的版本(如免费版、体验版、付费版),我们可以对其进行单独配置。

kotlin
android {
    
    buildTypes {
        // 开发版
        debug {
            isMinifyEnabled = false
            signingConfig = signingConfigs.getByName("release")
        }
        // 体验版
        create("trial") {
            isMinifyEnabled = false
            // 如果没有为 trial 版本定义资源或配置,使用 debug 版本的资源或配置作为回退
            // matchingFallbacks 用于在构建时匹配资源和依赖项,如果 trial 版本缺少某些资源或配置
            // 则尝试从 debug 构建类型中获取。这避免了缺少资源或配置时构建失败。
            matchingFallbacks.add("debug")
            signingConfig = signingConfigs.getByName("release")
        }
        // 发布版
        release {
            isMinifyEnabled = false
            signingConfig = signingConfigs.getByName("release")
            // 混淆配置
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}
groovy
android {
    
    buildTypes {
        // 开发版
        debug {
            minifyEnabled false
            signingConfig signingConfigs.release
        }
        // 体验版
        trial {
            minifyEnabled false
            // 如果没有为 trial 版本定义资源或配置,使用 debug 版本的资源或配置作为回退
            // matchingFallbacks 用于在构建时匹配资源和依赖项,如果 trial 版本缺少某些资源或配置
            // 则尝试从 debug 构建类型中获取。这避免了缺少资源或配置时构建失败。
            matchingFallbacks = ['debug']
            signingConfig signingConfigs.release
        }
        // 发布版
        release {
            minifyEnabled false
            signingConfig signingConfigs.release
            // 混淆配置
            proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
        }
    }
}

生成的构建版本

通过这个配置我们可以构建版本:

  • debug:调试版本
  • trial:体验版本
  • release:发布版本

添加构建变体

通过 flavorDimensions 添加一个产品的风味维度,通过 productFlavors 添加多个变体。每个变体可以根据需求进行不同的配置和依赖项管理,这个配置能帮助我们构建多个不同版本的应用程序。

kotlin
android {
    
    // 添加一个维度
    flavorDimensions.add("version")

    // 定义两个不同的产品风味(变体)
    productFlavors {
        // 免费版变体
        create("free") {
            // 指定这个变体的维度
            dimension = "version"
            // 为 free 变体的应用指定不同的应用名称(用于字符串资源)
            resValue("string", "app_name", "MyApp Free")
        }
        // 付费版变体
        create("paid") {
            // 指定这个变体的维度
            dimension = "version"
            // 为 paid 变体的应用指定不同的应用名称(用于字符串资源)
            resValue("string", "app_name", "MyApp Paid")
        }
    }
}
groovy
android {
    
    // 添加一个维度
    flavorDimensions 'version'

    // 定义两个不同的产品风味(变体)
    productFlavors {
        // 免费版变体
        free {
            // 指定这个变体的维度
            dimension 'version'
            // 为 free 变体的应用指定不同的应用名称(用于字符串资源)
            resValue 'string', 'app_name', 'MyApp Free'
        }
        // 付费版变体
        paid {
            // 指定这个变体的维度
            dimension 'version'
            // 为 paid 变体的应用指定不同的应用名称(用于字符串资源)
            resValue 'string', 'app_name', 'MyApp Paid'
        }
    }
}

生成的构建变体

通过上面配置,我们会得到以下的构建变体组合:

  • freeDebug:免费版的调试版本
  • freeTrial:免费版的体验版本
  • freeRelease:免费版的发布版本
  • paidDebug:付费版的调试版本
  • paidTrial:付费版的体验版本
  • paidRelease:付费版的发布版本

🍀 多维度

flavorDimensions 是一个List,所以我们可以定义多个维度。每个维度可以有多个变体,每个变体都代表应用的某种变体版本(例如,free 或 paid)。通过定义多个维度,我们可以将变体按不同的方式组合起来。

例如,我可以同时添加以下两个维度:

  • version:表示应用的版本,如 free 和 paid。
  • device:表示应用支持的设备类型,如 phone 和 tablet。
kotlin
android {
    
    // 定义多个维度
    flavorDimensions.add("version")  // 版本维度
    flavorDimensions.add("device")   // 设备维度

    // 添加变体
    productFlavors {
        create("free") {
            dimension = "version"
        }

        create("paid") {
            dimension = "version"
        }

        // 手机设备版本变体
        create("phone") {
            dimension = "device"
            resValue("string", "device_type", "Phone")
        }
        // 平板设备版本变体
        create("tablet") {
            dimension = "device" 
            resValue("string", "device_type", "Tablet")
        }
    }
}
groovy
android {
    // 定义多个维度
    flavorDimensions 'version', 'device'  // 版本维度和设备维度

    // 添加变体
    productFlavors {
        free {
            dimension 'version'
        }

        paid {
            dimension 'version'
        }

        // 手机设备版本变体
        phone {
            dimension 'device'
            resValue 'string', 'device_type', 'Phone'
        }
        // 平板设备版本变体
        tablet {
            dimension 'device'
            resValue 'string', 'device_type', 'Tablet'
        }
    }
}

生成的构建变体

使用上面配置后,Gradle 会自动生成以下构建变体组合:

  • freePhoneDebug:免费版,适用于手机设备,调试版本
  • freePhoneTrial:免费版,适用于手机设备,体验版本
  • freePhoneRelease:免费版,适用于手机设备,发布版本
  • freeTabletDebug:免费版,适用于平板设备,调试版本
  • freeTabletTrial:免费版,适用于平板设备,体验版本
  • freeTabletRelease:免费版,适用于平板设备,发布版本
  • paidPhoneDebug:付费版,适用于手机设备,调试版本
  • paidTabletTrial:付费版,适用于手机设备,体验版本
  • paidPhoneRelease:付费版,适用于手机设备,发布版本
  • paidTabletDebug:付费版,适用于平板设备,调试版本
  • paidTabletTrial:付费版,适用于平板设备,体验版本
  • paidTabletRelease:付费版,适用于平板设备,发布版本

总结:多维度可以管理复杂的应用版本,非常适合那些需要多种组合和支持多种版本、设备类型或市场渠道的项目。

打包配置

下面是打包 apk 的配置代码,这个配置定义了 APK 在构建输出时的文件命名规则,目的是让输出的 APK 文件具有清晰的标识。每次打包时,根据构建类型Debug或者Release或其他,以及项目的其他标识,来生成特定格式的文件名,便于区分和管理构建输出的apk包。

apk文件的命名规则是:变体名称_版本标识_打包标识_commit值.apk

1.第一步

gradle.properties 配置文件中定义打包标识。

properties
# 打包标识
PACKAGE_KEY=app_name

1.第二步

build.gradle 配置文件中编写打包配置。

kotlin
android {
    
    // 配置 APK 的打包文件命名规则
    applicationVariants.all {
        outputs.map {
            it as com.android.build.gradle.internal.api.ApkVariantOutputImpl
        }.forEach { output ->
            // 获取变体名称,可能包含 '-',去掉 '-' 符号改为 '_'。
            val variantName = output.name.replace("-", "_")
            val appName = if (buildType.name == "release") {
                // 只有在发布版的时候才拼接版本号TAG标识
                "${variantName}_${gitVersionTag}_${project.property("PACKAGE_KEY")}_${gitAbbreviatedId}.apk"
            } else {
                "${variantName}_${project.property("PACKAGE_KEY")}_${gitAbbreviatedId}.apk"
            }
            output.outputFileName = appName
        }
    }
}
groovy
android {

  // 配置 APK 的打包文件命名规则
  android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
      if (output instanceof com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
        // 获取变体名称,可能包含 '-',去掉 '-' 符号改为 '_'。
        def variantName = output.name.replace('-', '_')
        def appName
        if (variant.buildType.name == "release") {
          // 只有在发布版的时候才拼接版本号TAG标识
          appName = "${variantName}_${gitVersionTag}_${project.property('PACKAGE_KEY')}_${gitAbbreviatedId}.apk"
        } else {
          appName = "${variantName}_${project.property('PACKAGE_KEY')}_${gitAbbreviatedId}.apk"
        }
        output.outputFileName = appName
      }
    }
  }
}

💡 测试

假设当前选择了freeTrial的变体版本,那么输出结果就会是:

free_trial_app_name_08d8553.apk

选择freeRelease变体:

free_release_V1.0_app_name_08d8553.apk

推荐指数 ⭐️ ⭐️ ⭐️ ⭐️ ⭐️

虽然这种配置并不是强制要求的,因为每个项目的实际情况不一样嘛,但是我推荐按照此种方式的命名规则来打包。这样做有助于提高 apk 文件的可识别性和管理效率,尤其是在搭建 apk 包管理平台时,能够方便地识别和区分不同的 apk 版本。

引用第三方框架

⚠️ 注意事项

在正式引用第三方库时,我们要选择有维护、用户量大的热门库,因为这种库通常会更稳定并有更好的支持。尽量选择开源库并查看 GitHub 或其他托管平台上的更新频率和活跃度。

引用格式:

引用一些第三方框架,必须注明框架的作用及出处,以便出现问题时能够快速核查和反馈。

示例:

groovy
dependencies {
  // 上拉刷新下拉加载框架
  // 开源地址:https://github.com/scwang90/SmartRefreshLayout
  implementation 'io.github.scwang90:refresh-layout-kernel:2.0.6' // 核心必须依赖
  // 一些自定义刷新头
  implementation project(path: ':common_librarys:refresh-header')

  // 权限请求框架 https://github.com/getActivity/XXPermissions
  implementation 'com.github.getActivity:XXPermissions:18.0'

  // 图片加载框架
  // 开源地址:https://github.com/bumptech/glide
  // 官方文档:https://github.com/Muyangmin/glide-docs-cn
  implementation 'com.github.bumptech.glide:glide:4.15.1'
  kapt 'com.github.bumptech.glide:compiler:4.12.0'

  // 沉浸式框架
  // 开源地址:https://github.com/gyf-dev/ImmersionBar
  implementation 'com.geyifeng.immersionbar:immersionbar:3.2.2'

  // 动画解析库
  // 开源地址:https://github.com/airbnb/lottie-android
  // 一些动画资源:https://lottiefiles.com、https://icons8.com/animated-icons
  implementation 'com.airbnb.android:lottie:4.1.0'

  // TabLayout库
  // 开源地址:https://github.com/H07000223/FlycoTabLayout
  implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar'
}

💡 我注意到Gradle 7.0版本之后引入了‌libs.versions.toml文件,它是用于集中管理项目中的依赖项版本信息的。

那我们就也可以按照新版的格式:

kotlin
dependencies {
  // mmkv 数据存储框架
  // 开源地址:https://github.com/Tencent/MMKV
  implementation(libs.mmkv)

  // 依赖注入库 Hilt 是谷歌推荐的用于 Android 的依赖注入框架,可以简化依赖的创建和管理过程。
  // 开源地址: https://github.com/google/dagger
  // 官方文档: https://developer.android.com/training/dependency-injection/hilt-android
  implementation(libs.hilt.android)

  // Hilt 的注解处理器(compiler)在编译时生成代码,用于自动创建依赖类,从而实现自动注入。
  // 开源地址: https://github.com/google/dagger
  // 官方文档: https://developer.android.com/training/dependency-injection/hilt-android
  kapt(libs.hilt.compiler)

  // 阿里巴巴开发的一个高性能 JSON 库
  // 开源地址: https://github.com/alibaba/fastjson
  implementation(libs.fastjson)

  // AndroidX Activity KTX 库,提供了 Kotlin 扩展函数,简化了 Activity 的开发,
  // 如:集成 Jetpack 组件(如 ViewModel 和 Lifecycle)等。viewModels() 就是来自于此库,它简化了 ViewModel 的获取。
  // 开源地址: https://github.com/androidx/androidx/tree/androidx-main/activity
  // 官方文档: https://developer.android.com/jetpack/androidx/releases/activity
  implementation(libs.androidx.activity.ktx)

  // AndroidX Fragment KTX 库,为 Fragment 提供了更多便捷的 Kotlin 扩展函数,
  // 开源地址: https://github.com/androidx/androidx/tree/androidx-main/fragment
  // 官方文档: https://developer.android.com/jetpack/androidx/releases/fragment
  implementation(libs.androidx.fragment.ktx)

  // room 是一个 SQLite 数据库的封装库,提供了更高级别的抽象,简化了数据库的操作。
  // 开源地址: https://github.com/androidx/androidx/tree/androidx-main/room
  // 官方文档: https://developer.android.com/jetpack/androidx/releases/room
  implementation(libs.androidx.room.runtime)
  implementation(libs.androidx.room.ktx)
  annotationProcessor(libs.androidx.room.compiler)

  // Android项目基础库
  implementation(project(":common_librarys:andbasic"))

  // 封装的Toast提示框架
  implementation(project(":common_librarys:toaster"))
}

⚠️ 注意事项

在主项目子模块中,是否也采用libs.versions.toml全局依赖需求根据实际情况而定。

如果考虑到模块会有多项目使用的可能性,就不建议配置libs.versions.toml全局依赖,这样我们更能自由管控子模块引入的一些依赖版本。

groovy
// 考虑到模块会多项目使用的可能性,所以不在这里配置libs.versions.toml全局依赖
dependencies {
  // AndroidX 库:https://github.com/androidx/androidx
  implementation 'androidx.appcompat:appcompat:1.6.1'

  // ....
}

在 Apache-2.0 许可证下发布。