Appearance
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 以下版本的。
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_name1.第二步
在 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'
// ....
}