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

前言:

随着公司项目的不断增大,开发人员的不断增加,仅用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


<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.0modelVersion>
  <groupId>com.xiwei.commonlibgroupId>
  <artifactId>lib_xiwei_commonartifactId>
  <version>1.0.5version>
  <packaging>aarpackaging>
project>

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


<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.0modelVersion>
  <groupId>com.xiwei.commonlibgroupId>
  <artifactId>lib_xiwei_commonartifactId>
  <version>1.0.5version>
  <packaging>aarpackaging>
  <dependencies>
    <dependency>
      <groupId>com.xiwei.commonlibgroupId>
      <artifactId>lib_statisticsartifactId>
      <version>1.0.1version>
    dependency>
    <dependency>
      <groupId>com.xiwei.commonlibgroupId>
      <artifactId>lib_framework_imageartifactId>
      <version>1.0.0version>
    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

你可能感兴趣的:(android)