目前的android开发为了减少编译时间,开发效率,大多都采用模块化,组件化的开发方式。采用这种方式不可避免的将会用到多个Library。 那么当我们协同开发时,如何处理每个人的版本统一呢?
当你的项目中 module
的数量超过一个甚至越来越多的时候,对 Gradle 依赖进行统一管理就变得重要起来,因为你不会想在升级一个三方依赖的版本后发现冲突,然后一个个打开各个 module
的 build.gradle
文件,找到你升级的那个依赖引用,重复的进行版本修改;
因此我们有了初步的优化方案:
config.gradle
文件,在其中按照以下格式添加相关配置;ext {
/**
* module开关统一申明在此处
* true: 表示作为一个模块
* false: 表示作为独立程序,可单独运行
*/
isModule_a = true
isModule_b = true
// isModule_Location = false
// isModule_Login = false
// isModule_Main = false
// isModule_Personal = false
// isModule_ProductDetail = false
// isModule_ShoppingCar = false
/**
* 版本信息统一管理
*/
android = [
compileSdkVersion: 31,
buildToolsVersion: "30.0.3",
applicationId : "com.XXXX.XXXX",
minSdkVersion : 24,
targetSdkVersion : 31,//27以上的版本http请求 权限不允许
versionCode : 1,
versionName : "1.0.0"
]
dependencies = [
//basic
"appcompat" : 'androidx.appcompat:appcompat:1.4.1',
"material" : 'com.google.android.material:material:1.5.0',
"constraintlayout" : 'androidx.constraintlayout:constraintlayout:2.1.3',
"navigation-fragment" : 'androidx.navigation:navigation-fragment:2.4.1',
"navigation-ui" : 'androidx.navigation:navigation-ui:2.4.1',
//Rxjava
"rxjava" : "io.reactivex.rxjava2:rxjava:2.1.6",
"rxandroid" : "io.reactivex.rxjava2:rxandroid:2.0.1",
"rxrelay" : "com.jakewharton.rxrelay2:rxrelay:2.0.0",
/*Rx生命周期管理*/
"rxlifecycle" : "com.trello.rxlifecycle2:rxlifecycle:2.2.0",
"rxlifecycle-components": "com.trello.rxlifecycle2:rxlifecycle-components:2.2.0",
//Retrofit
"retrofit" : "com.squareup.retrofit2:retrofit:2.4.0",
"retrofit-gson" : "com.squareup.retrofit2:converter-gson:2.4.0",
"retrofit-adapter" : "com.squareup.retrofit2:adapter-rxjava2:2.4.0",
"okhttp-log-interceptor": "com.squareup.okhttp3:logging-interceptor:3.10.0",
"okhttp3" : "com.squareup.okhttp3:okhttp:3.10.0",
"gson" : "com.google.code.gson:gson:2.8.2",
"logger" : "com.orhanobut:logger:2.1.1",
//butterknife
"butterknife" : "com.jakewharton:butterknife:10.1.0",
"butterknife-anno" : "com.jakewharton:butterknife-compiler:10.1.0",
/*eventBus*/
"eventBus" : "org.greenrobot:eventbus:3.1.1",
//room
"room" : "androidx.room:room-runtime:2.2.5",
"room-anno" : "androidx.room:room-compiler:2.2.5",
"room-rxjava2" : "androidx.room:room-rxjava2:2.2.5", // 如果需要用到 rxjava
"room-guava" : "androidx.room:room-guava:2.2.5",// 如果需要用到 guava
"room-testing" : "androidx.room:room-testing:2.2.5",//需要用到相关测试工具的话
//cameraX
"camerax-core" : "androidx.camera:camera-camera2:1.0.0-beta06",//CameraX 核心库
"camerax-lifecycle" : "androidx.camera:camera-lifecycle:1.0.0-beta06",// CameraX 生命周期
"camerax-view" : "androidx.camera:camera-view:1.0.0-alpha10", //CameraX view 集合,比如 cameraview,preview等
//Glide 4.11.0 才适配AndroidX
"Glide" : "com.github.bumptech.glide:glide:4.11.0",
"Glide-anno" : "com.github.bumptech.glide:compiler:4.11.0",
//腾讯buggly
"TecentBugly" : "com.tencent.bugly:crashreport:latest.release",
"TecentBugly-native" : "com.tencent.bugly:nativecrashreport:latest.release",
// 屏幕适配集成
"Screen-Adapter" : "me.jessyan:autosize:1.2.1",
//组件化 Arouter
"Arouter" : "com.alibaba:arouter-api:1.2.2",
"Arouter-anno" : "com.alibaba:arouter-compiler:1.1.3"
]
avcProtocol = [
"innerNet": "ws://",//ws
"extraNet": "wss://"
]
url = [
// "debug" : "https://XXXXX.XXXXX.cn",//
// "debug" : "http://192.168.71.126",//
]
port = [
// // "debug_port" : 53073 ,//avc
]
filefolder = [
"release_root_folder": "",
"debug_root_folder" : "_debug"
]
}
build.gradle
文件顶部添加 apply from: "config.gradle"
;gradle 7.0 之前
// Top-level build file where you can add configuration options common to all sub-projects/modules.
println "----- RootGradle Start -----"
apply from: "${rootProject.getRootDir()}/config.gradle"
println "RootGradle ext path--->"+"${rootProject.getRootDir()}/config.gradle"
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
gradle 7.0之后
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.2' apply false
id 'com.android.library' version '7.2.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}
apply from: this.rootProject.file('config.gradle')
task clean(type: Delete) {
delete rootProject.buildDir
}
module
的 build.gradle
中就可以通过 rootProject
来引用对应的依赖及参数了;app 的build.gradle
plugins {
id 'com.android.application'
}
println "----- app Start -----"
android {
def versionConfig = rootProject.extensions.getByName("ext").android
println "---app versionConfig is:" + versionConfig
namespace 'com.demo.agreebankmvvm'
compileSdk versionConfig.compileSdkVersion
buildToolsVersion versionConfig.buildToolsVersion
defaultConfig {
applicationId "com.demo.agreebankmvvm"
minSdk versionConfig.minSdkVersion
targetSdk versionConfig.targetSdkVersion
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
//版本名后面添加一句话,意思就是flavor dimension 它的维度就是该版本号,这样维度就是都是统一的了
flavorDimensions "channel"
//指定room.schemaLocation生成的文件路径
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
//arouter
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
signingConfigs {
release {//发布版本的签名配置
storeFile file(rootProject.RELEASE_KEYSTORE_FILE)
keyAlias rootProject.RELEASE_KEY_ALIAS
storePassword rootProject.RELEASE_KEYSTORE_PWD
keyPassword rootProject.RELEASE_KEY_PWD
}
debug {//调试版本的签名配置
storeFile file(rootProject.DEBUG_KEYSTORE_FILE)
keyAlias rootProject.DEBUG_KEY_ALIAS
storePassword rootProject.DEBUG_KEYSTORE_PWD
keyPassword rootProject.DEBUG_KEY_PWD
}
}
buildTypes {
debug {
File file = new File("${rootProject.getRootDir()}/jks/debugBank.jks")
println "---debug signkey file is:" + file.exists()
signingConfig signingConfigs.debug
buildConfigField('String', 'PROJECT_ROOTFILE', "\"${filefolder["debug_root_folder"]}\"") //debug根文件夹名称
buildConfigField('String', 'SERVER_URL', "\"${url["debug"]}\"")//配置debug的服务器地址
buildConfigField('int', 'MESSAGE_URL_PORT', "${port["debug_port"]}") //配置debug模式下的服务器端口
buildConfigField('String', 'avc_innerprotocol', "\"${avcProtocol["innerNet"]}\"") //配置debug模式下的协议内网(avc的初始化用)
buildConfigField('String', 'avc_extraprotocol', "\"${avcProtocol["extraNet"]}\"") //配置debug模式下的协议外网(avc的初始化用)
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
File file = new File("${rootProject.getRootDir()}/jks/releaseBank.jks")
println "---release signkey file is:" + file.exists()
signingConfig signingConfigs.release
buildConfigField('String', 'PROJECT_ROOTFILE', "\"${filefolder["release_root_folder"]}\"") //release根文件夹名称
buildConfigField('String', 'SERVER_URL', "\"${url["release"]}\"")//配置release模式下的服务器地址
buildConfigField('int', 'MESSAGE_URL_PORT', "${port["release_port"]}") //配置release模式下的服务器的端口
buildConfigField('String', 'avc_extraprotocol', "\"${avcProtocol["extraNet"]}\"") //配置 release模式下的协议(avc的初始化用)
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
//多渠道打包
productFlavors {
//juphone版本
juPhonePHONE {
buildConfigField('int', 'videoType', '0')
buildConfigField('String', 'machineType', "\"phone\"" )
buildConfigField('String', 'channelType', "\"C002\"" )
applicationId "com.agree.bank.client_phone.phone"
applicationIdSuffix ".juPhone"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/debug",
APP_NAME: "phone-juPhone-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
juPhonePAD {
buildConfigField('int', 'videoType', '0')
buildConfigField('String', 'machineType', "\"pad\"")
buildConfigField('String', 'channelType', "\"C003\"" )
applicationId "com.agree.bank.client_phone.pad"
applicationIdSuffix ".juPhone"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/debug",
APP_NAME: "pad-juPhone-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
//avc版本
AVCPHONE {
buildConfigField('int', 'videoType', '1')
buildConfigField('String', 'machineType', "\"phone\"" )
buildConfigField('String', 'channelType', "\"C002\"" )
applicationId "com.agree.bank.client_phone.phone"
applicationIdSuffix ".AVC"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/ic_launcher_round",
APP_NAME: "phone-AVC-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
AVCPAD {
buildConfigField('int', 'videoType', '1')
buildConfigField('String', 'machineType', "\"pad\"")
buildConfigField('String', 'channelType', "\"C003\"" )
applicationId "com.agree.bank.client_phone.pad"
applicationIdSuffix ".AVC"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/ic_launcher_round",
APP_NAME: "pad-AVC-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
//trtc版本
TrtcPHONE {
buildConfigField('int', 'videoType', '2')
buildConfigField('String', 'machineType', "\"phone\"" )
buildConfigField('String', 'channelType', "\"C002\"" )
applicationId "com.agree.bank.client_phone.phone"
applicationIdSuffix ".trtc"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/ic_launcher_round",
APP_NAME: "phone-TRTC-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
TrtcPAD {
buildConfigField('int', 'videoType', '2')
buildConfigField('String', 'machineType', "\"pad\"")
buildConfigField('String', 'channelType', "\"C003\"" )
applicationId "com.agree.bank.client_phone.pad"
applicationIdSuffix ".trtc"
//替换清单文件中的标签
manifestPlaceholders = [
APP_ICON: "@mipmap/ic_launcher_round",
APP_NAME: "pad-TRTC-BK",
]
//versionName
versionName "1.0.0"
//versionCode
versionCode 1
}
}
//打包重命名
android.applicationVariants.all {
variant ->
variant.outputs.all {
output -> output.outputFileName = "app" + "-PackTime" + new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) +"--" +buildType.name+ ".apk"
}
}
//databinding
buildFeatures.dataBinding = true
}
dependencies {
// >基础依赖 - 其他模块需要可以单独依赖
implementation project(':librarys:lib_basic')
//ui_libary
implementation project(':librarys:lib_ui')
//pop_libary
implementation project(':librarys:lib_pop')
//net_libary
implementation project(':librarys:lib_net')
// 引入各个模块
if (rootProject.ext.isModule_a) {
implementation project(path: ':modules:module_a')
}
if (rootProject.ext.isModule_b) {
implementation project(path: ':modules:module_b')
}
//retrofit
implementation rootProject.ext.dependencies["retrofit"]
implementation rootProject.ext.dependencies["retrofit-gson"]
implementation rootProject.ext.dependencies["retrofit-adapter"]
//okhttp
implementation rootProject.ext.dependencies["okhttp-log-interceptor"]
implementation rootProject.ext.dependencies["okhttp3"]
// gson
implementation rootProject.ext.dependencies["gson"]
//room
implementation rootProject.ext.dependencies["room"]
annotationProcessor rootProject.ext.dependencies["room-anno"]
implementation rootProject.ext.dependencies["room-rxjava2"]
//arouter
implementation rootProject.ext.dependencies["Arouter"]
annotationProcessor rootProject.ext.dependencies["Arouter-anno"]
}
App 的manifest.xml
gradle.poroperties
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
#test
test = aaa
##########################################################################
# debug ???? ??
DEBUG_KEYSTORE_FILE = /../jks/debugBank.jks
# release ???? ??
RELEASE_KEYSTORE_FILE = /../jks/releaseBank.jks
# debug ???????
DEBUG_KEY_ALIAS = debugkey
# release ???????
RELEASE_KEY_ALIAS = releaseKey
# debug keyStore ????? --> keyStorePassword
DEBUG_KEYSTORE_PWD = 123456
# debug ????? --> keyPassword
DEBUG_KEY_PWD = 123456
# release keyStore ????? --> keyStorePassword
RELEASE_KEYSTORE_PWD = 123456
# release ????? --> keyPassword
RELEASE_KEY_PWD = 123456
module_a 的 build.gradle
if (Boolean.valueOf(rootProject.ext.isModule_a)) {
apply plugin: 'com.android.library'
println "----- module_a Start as library-----"
} else {
apply plugin: 'com.android.application'
println "----- module_a Start as application-----"
}
android {
def versionConfig = rootProject.extensions.getByName("ext").android
println "---module_a versionConfig is:" + versionConfig
namespace 'com.demo.module_a'
compileSdk versionConfig.compileSdkVersion
buildToolsVersion versionConfig.buildToolsVersion
defaultConfig {
// 作为程序独立运行时才设置AppId
if (!Boolean.valueOf(rootProject.ext.isModule_a)) {
applicationId "com.demo.module_a"
}
minSdk versionConfig.minSdkVersion
targetSdk versionConfig.targetSdkVersion
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//arouter
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dataBinding {
enabled = true
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
if (!Boolean.valueOf(rootProject.ext.isModule_a)) {
manifest.srcFile 'src/main/AndroidManifest.xml'
} else {
manifest.srcFile 'src/debug/AndroidManifest.xml'
}
}
}
}
dependencies {
// >基础依赖 - 其他模块需要可以单独依赖
implementation project(':librarys:lib_basic')
implementation fileTree(dir: 'libs', include: ['*.jar'])
//arouter
implementation rootProject.ext.dependencies["Arouter"]
annotationProcessor rootProject.ext.dependencies["Arouter-anno"]
}
module_a 的 main/manifest.xml
module_a 的 debug/manifest.xml