您的位置:首页 > 移动开发 > Android开发

android studio的maven私服使用配置踩坑实录

2016-06-28 16:52 936 查看

前言:

随着公司项目的不断增大,开发人员的不断增加,仅用git来进行代码管理、在开发的机器上手工打apk包通过IM工具提交给QA进行测试的开发流程已不再合适,效率及规范性急需提高。

经讨论,决定在公司android项目中使用MAVEN + JENKINS + ARTIFACTORY组合来进行开发流程优化

本文主要介绍在android studio上使用maven私服的实践过程及踩过的一些坑,最终配置在 另一篇文章 中贴出。

相关工具的配置不是本文的重点,需要的同学可以通过下面的传送门了解更多:

maven : 一个项目构建管理工具

公共库的module全部发布到公司maven私服中,app通过添加maven依赖的方式使用

maven的更多介绍请看 这里 , Maven官方文档

jenkins: 一种开源的持续集成系统

自动构建打包,通过配置让QA在jenkins上通过点击按钮打各app不同环境的apk包进行测试

jenkins的安装与配置可以参考 这里 Jenkins官网

artifactory: 一款maven私服构建&管理工具

用来搭建并管理我们的maven私服仓库

artifactory的使用方式参考文档: 30分钟搭建一个android的私有Maven仓库 英文原文

MAVEN + JENKINS + ARTIFACTORY整合

第一步:使用jenkins

问题:开发电脑上可以正常打包的命令在jenkins无法正常工作

可以通过很少的配置让jenkins拉取git上的代码并执行打包的工作,但在实际的配置过程中,发现我们的代码结构并不适合这种方式

原因:

我们的代码结构如下如:

---------------------------------------------------------------------
|   CommonLib              |     business1       |    business2     |
|        lib_module_1      |          app_1      |         app_1    |
|        lib_module_...    |          app_...    |         app_...  |
|        lib_module_n      |          app_n      |         app_n    |
---------------------------------------------------------------------


公共lib库及不同的业务线分别在不同android studio工程中,git地址不同,module采用相对地址引用的方式进行依赖,jenkins无法进行配置

解决方式

module的依赖方式改为maven,搭建maven私服

第二步:使用artifactory搭建maven私服

参考的实现方式是: 30分钟搭建一个android的私有Maven仓库

问题1. 每个module的build.gradle中都要进行配置

设置packageName、libraryVersion、artifactory配置等

publishing {
publications {
aar(MavenPublication) {
groupId packageName
version = libraryVersion
artifactId project.getName()

// Tell maven to prepare the generated "* .aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}
}
}


解决方式

做到以下配置后,升级module版本只需维护gradle.properties中的版本号,并在命令行调用
./deploy.sh lib_...
即可

同一个工程下的module使用相同的groupId,如:com.xiwei.commonlib

在gradle.properties中统一配置每个module的maven版本号,module之间的依赖,版本号直接引用gradle.properties中的变量

在module的build.gradle中,defaultConfig下添加versionName变量,值为gradle.properties中定义的变量

新建artifactory.gradle

subprojects {
//artifactory相关

apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def myGroupId = 'com.xiwei.commonlib'

publishing {
publications {
aar(MavenPublication) {
if (!project.hasProperty('android')){
return
}
def libVersion = "${project.android.defaultConfig.versionName}"

groupId myGroupId
version = libVersion
artifactId project.getName()

// Tell maven to prepare the generated "*.aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}
}
}
}


在工程根目录的build.gradle中添加一行

apply from: "artifactory.gradle"


新建deploy脚本:

deploy.sh

#!/bin/sh
./gradlew :$1:clean :$1:assembleRelease :$1:artifactoryPublish


deploy.bat

@echo off
gradlew :%1:clean :%1:assembleRelease :%1:artifactoryPublish


问题2. module的依赖关系没有传递

例如:当B依赖A,C在依赖B时要同时添加A的依赖,否则会报ClassNotFoundException

原因

使用artifactory进行的deploy时,生成的pom文件([module]/build/publications/aar/pom-default.xml)中未包含依赖信息:dependencies

<?xmlversion="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiwei.commonlib</groupId>
<artifactId>lib_xiwei_common</artifactId>
<version>1.0.5</version>
<packaging>aar</packaging>
</project>


我们需要的pom文件应该长成这样:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiwei.commonlib</groupId>
<artifactId>lib_xiwei_common</artifactId>
<version>1.0.5</version>
<packaging>aar</packaging>
<dependencies>
<dependency>
<groupId>com.xiwei.commonlib</groupId>
<artifactId>lib_statistics</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>com.xiwei.commonlib</groupId>
<artifactId>lib_framework_image</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>


解决方式

修改build.gradle中的artifactory配置,原来的配置是

publishing {
publications {
aar(MavenPublication) {
if (!project.hasProperty('android')){
return
}
def libVersion = "${project.android.defaultConfig.versionName}"

groupId myGroupId
version = libVersion
artifactId project.getName()

// Tell maven to prepare the generated "* .aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}
}
}


修改为(修改方式参考 这里 ):

publishing {
publications {
aar(MavenPublication) {
if (!project.hasProperty('android')){
return
}
def libVersion = "${project.android.defaultConfig.versionName}"

groupId myGroupId
version = libVersion
artifactId project.getName()

// Tell maven to prepare the generated "* .aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}

//The publication doesn't know about our dependencies, so we have to manually add them to the pom
pom.withXml {
//Creating additional node for dependencies
def dependenciesNode = asNode().appendNode('dependencies')

//Defining configuration names from which dependencies will be taken (debugCompile or releaseCompile and compile)
def configurationNames = ["releaseCompile", 'compile']
configurationNames.each { configurationName ->
project.configurations.getByName(configurationName).allDependencies.each {
if (it.group != null && it.name != null) {
println it.group + ":" + it.name + "" + it.version + "," + v_lib_framework_http
println("${it.group}:${it.name}:${it.version}:v_lib_framework_http:${v_lib_framework_http}")
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)

//If there are any exclusions in dependency
if (it.excludeRules.size() > 0) {
def exclusionsNode = dependencyNode.appendNode('exclusions')
it.excludeRules.each { rule ->
def exclusionNode = exclusionsNode.appendNode('exclusion')
exclusionNode.appendNode('groupId', rule.group)
exclusionNode.appendNode('artifactId', rule.module)
}
}
}
}
}
}
}
}


问题3. 在windows上deploy时,报错如下:

Execution failed for task ':lib_framework_http:artifactoryPublish'.
> File 'E:\work\CommonLib\lib_framework_http\build\publications\aar\pom-default.xml' does not exist, and need to be published from publication aar


原因

artifactory没有自动调用构建pom的task

解决方式

deploy脚本: deploy.bat

@echo off
gradlew :%1:clean :%1:assembleRelease :%1:artifactoryPublish


修改后的脚本deploy.bat:

@echo off
gradlew :%1:clean :%1:assembleRelease :%1:generatePomFileForAarPublication :%1:artifactoryPublish


问题4. 使用maven方式依赖的lib升级过于频繁

被依赖的lib修改代码后需要升级或强制刷新dependencies才能生效,添加新功能或修改bug时十分不便

原因

使用指定版本或动态版本(如:1.1.+)时,均会产生maven缓存,lib修改后新发布的版本不能及时生效

解决方式

开发阶段使用SNAPSHOT版进行发布及依赖

问题5. 升级版本,发布时报错

Error:Failed to resolve: com.xiwei.commonlib:lib_statistics:1.0.2


原因

为了维护方便,正在发布的module版本号与其它module依赖该module指定的版本号在gradle.properties中为同一个变量,升级发布时,修改了这个变量,执行gradlew命令会检查所有module的dependencies

由于发布尚未开始,maven仓库中并无此版本的module,故而报错

解决方式

新建artifactory_version.properties,用来配置发布的module的版本号,build.gradle在发布时,版本信息从该properties文件中读取(为了方便,key为module的name)

新建modify.sh/modify.bat, 在module发布结束后,读取artifactory_version.properties中该module的版本并写入到gradle.properties文件中,更新被依赖的版本号

修改deploy.sh, 发布后调用modify.sh修改被依赖的版本号

artifactory_version.properties

#发布的类型:snapshot/release
maven_type=snapshot

lib_db=1.0.0
lib_framework_image=1.0.0
...
lib_statistics=1.0.1
lib_xiwei_common=1.0.5


modify.sh

#!/bin/sh

#project的版本定义文件
SOURCE_FILE_NAME="artifactory_version.properties"
#dependencies的版本定义文件
GRADLE_FILE_NAME="gradle.properties"
#从SOURCE_FILE_NAME的key到GRADLE_FILE_NAME的key需要添加的前缀:比如:lib_db -> v_lib_db 前缀为 v_
KEY_PRE_FIX="v_"

function contains
{
STRING_A=$1
STRING_B=$2
if [[ ${STRING_A/${STRING_B}//} == $STRING_A ]]
then
return 0
else
return 1
fi
}

function replace_prop() {
KEY=$1
VALUE=$2
SUFFIX=''
if [[ ${maven_type} = 'snapshot' ]]; then
SUFFIX='-SNAPSHOT'
fi
cat $GRADLE_FILE_NAME | while read LINE
do
contains $LINE "$KEY_PRE_FIX$KEY="
result=$?
if [[ $result = 1 ]]; then
#包含$KEY_PRE_FIX$2=的行内容替换为v_$2=$3
sed -ig "s/$LINE/$KEY_PRE_FIX$KEY=$VALUE$SUFFIX/g" ${GRADLE_FILE_NAME}
rm -f ${GRADLE_FILE_NAME}g
return
fi
done
}
#读取需要拷贝的properties文件
. ${SOURCE_FILE_NAME}
#todo check params
#替换GRADLE_FILE_NAME文件中key为$1的行内容:例如v_lib_db=1.0.0 -> v_lib_db=1.0.1
replace_prop $1 ${!1}


总结

通过一步步踩坑、优化,目前实现的效果为:

module采用maven的方式进行依赖

使用jenkins进行CI,QA可自助打不同环境的apk包

只需维护artifactory_version.properties这一个文件进行版本管理即可

修改版本信息后,通过调用命令可一键发布所有包,且互相之间的依赖生效

涉及到的文件

整个配置过程中涉及到的文件有:

artifactory.gradle

artifactory_version.properties

build.gradle

deploy.sh

modify.sh

deploy.bat

modify.bat

使用方式

module修改后,artifactory_version.properties中对应module及传递依赖的module要进行升级,并将maven_type改为snapshot进行发布

测试验收结束后,maven_type改为release进行发布(调用)

发布命令

发布单个module:

mac:
./deploy.sh moduleName


windows:
deploy.bat moduleName


发布当前工程中的所有module:

mac:
./deploy.sh -a


windows:
deploy.bat -a


原文地址:http://blog.csdn.net/cdecde111/article/details/51777170
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息