本篇只针对gradle外部配置做详细说明,诸如组件化,jenkins,artifactory等细节不做阐述
以我做过的项目为例
每个组件都独立维护大量的android,第三方,及其他组件的依赖,项目集成时,各个组件依赖版本不同还会引起冲突。
当组件上传新的版本,相依赖的组件还要更新。比如公共库从1.0-snapshot修改到1.1-snapshot。那么交易明细,交接班,对账单就要都进行修改,非常的麻烦。这时就非常需要一个统一的配置入口。
“”修改一次到处运行“是我们这次的目标,好了,废话铺垫完,开始进入正题。
一.设计思路
- gradle文件部署在远端web服务器下
- 每个组件依赖远端gradle文件
- 打包aar上传至artifactory
- jenkins通过脚本监控artifactory中是否有新的组件aar,如果有将gradle文件中对应的版本更新为最新
优点:
解放了双手
- 只需要修改远端gradle,每个组件都会同时共享,只需操作一下同步
- 组件发布新版本,不需要手动去修改远端gradle,jenkins会自动修改(过去的方式只要有一个组件发布新版本,开发人员要通知依赖方去升级,每个依赖方都要手动修改版本,麻烦而且容易忘记修改,不能及时发现问题)
二.环境
本文只针对jenkins+artifactory举例,如果环境不同,可以举一反三,环境不重要,思路才是终解
jenkins--持续构建,编写自动化脚本,同步外部gradle文件
artifactory--本地私服,组件化后的aar发布到此处
三.提取gradle通用配置
gradle大致结构如下图
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.qianbao.ipos.myapplication"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
minSdkVersion,targetSdkVersion,compileSdkVersion,dependencies中的内容都可以作为统一的配置项,如果你项目中有环境配置,譬如生产环境,测试环境,那么这些不同环境的域名或其他项都可作为配置项
四.自定义gradle
1.根节点ext
2.次节点是为了保证层次清晰,进行了分组
ext {
version = [
compileSdk : 28,
buildTools : "28.0.3",
minSdk : 21,
targetSdk : 28,
router : "1.5.8.0-RELEASE",
biznetwork : "1.5.9.0-RELEASE",
//Android
androidSupport : "28.0.0",
androidEspresso : "3.0.2",
//腾讯
tencentXinge : "4.3.1-beta",
tencentWup : "1.0.0.E-release",
tencentMid : "4.0.7-Release",
tencentJg : "1.1",
]
androidDependencies = [
//support,共用同一版本
animatedVectorDrawable: "com.android.support:animated-vector-drawable:${version.androidSupport}",
supportVectorDrawable : "com.android.support:support-vector-drawable:${version.androidSupport}",
supportCoreUtils : "com.android.support:support-core-utils:${version.androidSupport}",
]
testDependencies = [
//espresso,共用同一版本
espressoCore : "com.android.support.test.espresso:espresso-core:${version.androidEspresso}",
espressoIntents: "com.android.support.test.espresso:espresso-intents:${version.androidEspresso}",
espressoContrib: "com.android.support.test.espresso:espresso-contrib:${version.androidEspresso}",
]
tencentDependencies = [
xinge: "com.tencent.xinge:xinge:${version.tencentXinge}",
wup : "com.tencent.wup:wup:${version.tencentWup}",
mid : "com.tencent.mid:mid:${version.tencentMid}",
jg : "com.tencent.jg:jg:${version.tencentJg}"
]
iposDependencies = [
router : "com.qianbao.ipos:router:${version.router}",
datagramparser: "com.qianbao.ipos:datagramparser:${version.datagramparser}",
]
}
五.如何使用
1.在项目根目录下的build.gradle中添加外部gradle
我的项目中的外部gradle是部署在artifactory的tomcat下(这样就省去了单独部署服务端),artifactory安装目录/tomcat/webapps/artifactory
apply from: 'http://{url}/artifactory/dependencies_1.5.9.gradle'
buildscript {
repositories {
jcenter()
google()
maven { url 'https://dl.bintray.com/umsdk/release' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.9.0"
}
}
2.在app/moudle下添加如下配置
看着是不是很清晰简洁
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def ext = rootProject.extensions.getByName("ext")
def versionConfig = ext.version
def testDependencies = ext.testDependencies
def androidDependencies = ext.androidDependencies
def tencentDependencies = ext.tencentDependencies
def iposDependencies = ext.iposDependencies
def pushPublishing = '1.5.9.18-SNAPSHOT'
android {
compileSdkVersion versionConfig.compileSdk
buildToolsVersion versionConfig.buildTools
defaultConfig {
minSdkVersion versionConfig.minSdk
targetSdkVersion versionConfig.targetSdk
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
//测试相关引用
androidTestImplementation testDependencies.junit
androidTestImplementation testDependencies.workTesting
//android包
implementation androidDependencies.appcompatV7
implementation androidDependencies.workRuntime
//腾讯推送
implementation tencentDependencies.xinge
implementation tencentDependencies.wup
implementation tencentDependencies.mid
implementation tencentDependencies.jg
//ipos组件
implementation iposDependencies.router
implementation iposDependencies.datagramparser
implementation iposDependencies.biznetwork
}
六.自动更新外部gradle
到第五步其实已经完成了引用外部gradle的功能,但还存在一个问题,你要不停的去远程手动修改gradle文件,如果项目的参与人多还会造成其他的状况。减少人工的参与就是降低产生bug的风险。
下面将介绍通过jenkins如何完成自动更新,如果不了解jenkins请先做一下功课,否则下面对你没有启发作用
1.jenkins为修改外部gradle文件,提供了可视化环境
2.项目的组件由脚本自动完成,其余配置由界面化配置完成
3.jenkins配置
(1)参数部分
(2)触发器部分
通过Build Authorization Token Root Plugin插件,artifactory插件,都可以满足功能,但经过实测有些需求并不能满足
这里我采用了定时触发,每周1-周五,9点-17点,每20分钟触发一次
(3)shell脚本部分
思路:
私服Artifactory分为release和snapshot版,同版本以release优先,不同版本以最新的版本为准,将所有组件的版本解析后将外部gradle对应的组件版本修改
1)先遍历Artifactory所有libs-release-local下的release组件,通过下方的url访问可以解析到每个组件下的maven-metadata文件,
2)以同样的方式遍历snapshot
#!/bin/sh -x
currentVersion=`echo ${JOB_NAME#*-}`
gradleFile=/opt/jfrog/artifactory/tomcat/webapps/artifactory/dependencies_${currentVersion}.gradle
artifactoryUrl="http://192.168.1.138:8081/artifactory"
group="com/qianbao/ipos"
backupFile=$WORKSPACE/${JOB_NAME}.backup
function syncRelease(){
releasePath=/var/opt/jfrog/artifactory/backup/backup-daily/current/repositories/libs-release-local/com/qianbao/ipos
releaseLibPath="libs-release-local"
releaseDirectory=$( ls -l $releasePath | grep -v "metadata" | grep "^d" | awk '{print $9}')
count=0
if [ ! -f "$backupFile" ];then
touch $backupFile
fi
echo "==========================================Begin loop the Release lib of Artifactory=========================================="
for direcotryName in $releaseDirectory
do
checkUrl=$artifactoryUrl/$releaseLibPath/$group/$direcotryName/maven-metadata.xml
metadataXml=$(curl -s $checkUrl)
versionName=$(echo "$metadataXml" | awk -F '[<>]' '//{print $3}')
last=$(awk -F '[<>]' '/<${direcotryName}>/{print $3}' $backupFile)
versionCode=$(expr $versionName : "\([0-9]\{1,2\}\(\.[0-9]\{1,2\}\)\{2\}\).*")
if [ $currentVersion == $versionCode ] && [ "$versionName" != "$last" ];then
sed -i "s/$direcotryName\s*:\s*\"[0-9].*/$direcotryName : \"$versionName\",/" $gradleFile
sed -i "/<$direcotryName>.*<\/$direcotryName>/d" $backupFile
echo "<$direcotryName>$versionName$direcotryName>" >> $backupFile
echo "==========================================${direcotryName} has been update to version:${versionName}=========================================="
updateArray[count]=$direcotryName;
count=`expr $count + 1`
else
echo "==========================================The release lib of Artifactory is unchanged =========================================="
fi
done
}
function syncSnapshot(){
snapshotPath=/var/opt/jfrog/artifactory/backup/backup-daily/current/repositories/libs-snapshot-local/com/qianbao/ipos
snapshotDirectory=$( ls -l $snapshotPath | grep -v "metadata" | grep "^d" | awk '{print $9}')
snapshotLibPath="libs-snapshot-local"
echo "==========================================Begin loop the Snapshot lib of Artifactory=========================================="
for direcotryName in $snapshotDirectory
do
checkUrl=$artifactoryUrl/$snapshotLibPath/$group/$direcotryName/maven-metadata.xml
metadataXml=$(curl -s $checkUrl)
versionName=$(echo "$metadataXml" | awk -F '[<>]' '//{print $3}')
versionCode=$(expr $versionName : "\([0-9]\{1,2\}\(\.[0-9]\{1,2\}\)\{2\}\).*")
last=$(awk -F '[<>]' '/<$direcotryName>/{print $3}' $backupFile)
if [ "${updateArray[*]}" != "" ];then
exsit=$(echo "${updateArray[*]}" | grep -w "$direcotryName")
if [ "$exsit" != "" ] || [ "$versionName" == "$last" ];then
echo "==========================================The snapshot lib of Artifactory is unchanged =========================================="
continue
fi
fi
if [ $currentVersion == $versionCode ];then
sed -i "s/$direcotryName\s*:\s*\"[0-9].*/$direcotryName : \"$versionName\",/" $gradleFile
sed -i "/<$direcotryName>.*<\/$direcotryName>/d" $backupFile
echo "<$direcotryName>$versionName$direcotryName>" >> $backupFile
echo "==========================================${direcotryName} has been update to version:${versionName} =========================================="
fi
done
}
#########通过Aritifactory上最新版本,同步配置文件
#########规则:条件1:release有与当前版本一致的包优先替换,条件2:snapshot有与当前版本一致的包替换,如果release与snapshot冲突,release优先,条件3:两者都不满足则不替换
#########同步release库
syncRelease
#########同步snapshot库
syncSnapshot