当 jenkins遇上Android Studio 3.0

4,328 阅读9分钟

概述

简介

jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
关于Android Studio持续集成的文章已经是满天飞了,不过都是在AS 2.X的环境下面进行集成的,最近升级了AS 3.0之后,发现按照之前的一些方法无法在AS 3.0上顺利集成,本来很简单的几步操作,却调试了很久,下面简单记录一下调试的过程,可以让一部分开发者少走弯路。

本文是基于GitLab集成,其余的类似于Git,SVN其实原理都一样,稍微有点区别,稍微调试一下就好。

正文

基本知识

简单的Groovy语法

普通标识符:以字母、美元符号$或下划线_开始,不能以数字开始

def date = new Date()

引号标识符:使用单引号括住的字符串

def name = 'android'

括号{}:表示引用
美元符号$:表示拼接

assemble${PRODUCT_FLAVOR}${BUILD_TYPE}
//相当于assembleWandoujiaRelease

基本的gradle命令

说来惭愧,平时都是点击AS的可视化按钮,很少去研究这些命令,直到这次debug,才发现,命令行在debug确实很有用

  • gradlew clean //删除app目录下的build文件
  • gradlew build //编译debug跟release包
  • gradlew assembleDebug //编译debug包
  • gradlew assembleRelease //编译release包

jenkins提供的全局变量

这些变量可以在写脚本,包括gradle脚本以及python脚本的时候可以调用,我们也可以自己通过插件来配置一些变量,用来进行构建不同的渠道包,下面选取了一些常用的:

  • BRANCH_NAME :项目分支名称
  • CHANGE_AUTHOR:修改项目的作者
  • BUILD_NUMBER:构建的序列号
  • JOB_NAME:构建的项目名称
  • WORKSPACE:服务器构建项目的位置
  • JENKINS_HOME:jenkins的根目录
  • GIT_COMMITTER_EMAIL: Git提交作者的邮箱

登陆无效解决方案

当关掉jenkins的网页,再重新打开的时候,会让你重新登录,但是当你输入正确的用户名跟密码的时候,却会提示你登陆无效,解决方案如下:

  • 1.找到安装目录下的config文件
  • 2.找到useSecurity节点,将true改为false
    <useSecurity>false</useSecurity>
  • 3、找到authorizationStrategy跟securityRealm删除
  • 4、重启jenkins,不知道怎么重启的,直接重启电脑,再次启动jenkins即可。

修改build.gradle文件

AS3.0升级了gradle,改动较大,对比一下之前的代码,便可以发现区别,主要是在flavor的添加时必须增加一个dimension,apk输出路径做了较大的修改,为了减少代码量,只贴出了变动的部分

android {
    signingConfigs {
        config {
            keyAlias 'demo'
            keyPassword '123456'
            storeFile file('chuangmei.jks')
            storePassword '123456'
            flavorDimensions "versionCode"
        }
    }

    flavorDimensions "market"
    productFlavors {
        xiaomi {
            dimension "market"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        wandoujia {
            dimension "market"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }

    }
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            outputFileName = variant.productFlavors[0].name + new Date().format('yyyyMMddHHmmss') + '-' + variant.buildType.name + '.apk'
        }
    }
}

安装jenkins

官网是jenkins.io,有三种安装方式,分别是war包,native包以及docker容器,这里我选择的是native包,因为这种方式可以帮助我们安装一部分插件,基本上可以满足我们的需求。

配置环境

插件安装

native包安装
基本够用,然后可以根据需求扩展
war包安装

  • Git plugin
  • Gradle Plugin
  • SSH plugin
    这里选择的几个插件貌似能够打出apk,网上有很多文章,会安装很多插件,一来没必要,二来很多插件已经过时了,最新的jenkins版本已经不支持,即使是通过本地上传的方式,除非使用较老的jenkins版本。

系统设置

设置构建路径
找到主目录,然后点击高级

修改构建路径
修改构建路径

理解了groovy语法,上面的路径就很好理解了,这个是可以随便修改的

设置环境变量
找到全局属性,勾选环境变量,设置SDK路径

设置环境变量
设置环境变量

全局工具配置

name可以随便填,对应的value则是相应的路径

JDK路径

JDK路径
JDK路径

Git路径
Git路径
Git路径

Gradle路径
Gradle路径
Gradle路径

配置项目

创建一个项目

名称随便填,这里选择自由风格的软件项目,选择第一个也可以,看自己需求

创建项目
创建项目

配置项目

参数化构建

参数名称 参数类型 参数值
BUILD_TYPE choice Build,Debug
PRODUCT_FLAVOR choice Xiaomi,Wandoujia

参数化构建
参数化构建

构建环境

配置相应的构建环境

构建环境
构建环境

构建

根据之前设置的条件进行编译操作

构建
构建

构建后操作

主要是可以用来收集构建出来的apk以及相应的编译文件

构建后操作
构建后操作

开始构建

其实最花时间的还是这里,因为,升级了AS 3.0之后,gradle的版本变成了4.1,改动特别大,所以升级要慎重,但是已经升级了,问题还是得解决。

执行 gradle clean assembleRelease

是从这一行代码进行报的错,提示我说是在release合并资源的时候报错了,下面是具体的信息

下面最后一行开始报错

:app:generateAndroidReleaseResValues
:app:generateAndroidReleaseResources
:app:mergeAndroidReleaseResources

然后错误一直不断重复

AAPT err(Facade for 1119711668) : No Delegate set : lost message:\\?\C:\Windows\System32\config\systemprofile\.gradle\caches\transforms-1\files-1.1\appcompat-v7-25.4.0.aar\76d6a769daf730ed767830374ebcd3bd\res\drawable-hdpi-v4\abc_textfield_search_default_mtrl_alpha.9.png ERROR: Unable to open PNG file

追踪堆栈信息 --stacktrace --debug

* What went wrong:
16:04:41.129 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Execution failed for task ':app:mergeAndroidReleaseResources'.
16:04:41.129 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] > Error: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.AaptException: 
16:04:41.129 [ERROR]

对吧,日志都出来了,看地我是一脸懵逼,只看懂了app:mergeAndroidReleaseResources。

漫长的debug之路

环境检查

我的项目在本地是成功编译过的,不管是debug还是release都是OK的,clean也是没问题的,所以我当时就觉得应该是服务端编译的问题,但是服务端的代码是从gitlab上面获取的,跟我本地的是一模一样的,不应该有问题,难道是编译环境出了问题吗,因为上面的报错都是跟gradle相关的,所以我就打印了各自的gradle:

本地grade版本:

Gradle 4.1
------------------------------------------------------------

Build time:   2017-08-07 14:38:48 UTC
Revision:     941559e020f6c357ebb08d5c67acdb858a3defc2

Groovy:       2.4.11
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_131 (Oracle Corporation 25.131-b11)
OS:           Windows 10 10.0 amd64

服务端grade版本:

Gradle 4.1
------------------------------------------------------------

Build time:   2017-08-07 14:38:48 UTC
Revision:     941559e020f6c357ebb08d5c67acdb858a3defc2

Groovy:       2.4.11
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_131 (Oracle Corporation 25.131-b11)
OS:           Windows 10 10.0 amd64

是一样的,呵呵哒,只能再分析别的原因了,其实这个时候是没有什么思路的,因为太诡异了,基本上什么都一样了,但是服务端就是编译不成功,我能怎么办,我也很绝望啊。然后就用Google搜索了一下,搜到的答案基本上都不是太相关,只好作罢。

目录对比

其实在对比环境之后当时就想着回退版本了,毕竟已经折腾了很久了,不过转念一想,程序员不就是为问题而生的吗,然后又冷静思考了一会儿,还有什么是不一样的,终于发现了,目录,服务端编译的目录跟本地的目录不一样,可是这个在理论上是没有影响的,不过值得一试。然后我就直接打开了服务端在本地的项目,然后进行检查。

gradle clean

本地

E:\Jenkins\workspace\Test>gradle clean
> Configure project :app
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:clean'.
> Unable to delete file: E:\Jenkins\workspace\Test\app\build\intermediates\merged-not-compiled-resources\android\release\anim\abc_fade_in.xml

服务端

[Gradle] - Launching build.
[Test] $ cmd.exe /C "C:\Users\pangchao\.gradle\wrapper\dists\gradle-4.1-all\bzyivzo6n839fup2jbap0tjew\gradle-4.1\bin\gradle.bat clean && exit %%ERRORLEVEL%%"
:clean
:app:clean

BUILD SUCCESSFUL in 20s
2 actionable tasks: 2 executed
Build step 'Invoke Gradle script' changed build result to SUCCESS

是不是很意外,一个失败一个成功,而且居然是本地失败,服务端成功,很诡异。

gradle assembleRelease

本地打包

E:\Jenkins\workspace\Test>gradle assembleMumayi
> Configure project :app
[E:\Jenkins\workspace\Test\app\build\outputs\mapping\mumayi\release\dump.txt]...
Removed unused resources: Binary resource data reduced from 559KB to 539KB: Removed 3%

BUILD SUCCESSFUL in 31s
51 actionable tasks: 49 executed, 2 up-to-date
E:\Jenkins\workspace\Test>

服务端打包

[Gradle] - Launching build.
:app:assembleMumayiRelease
:app:assembleMumayi
BUILD SUCCESSFUL in 7s
51 actionable tasks: 6 executed, 45 up-to-date
Build step 'Invoke Gradle script' changed build result to SUCCESS
Finished: SUCCESS

可以看到先由本地编译,然后再经过服务端编译时都可以成功的,但是之前我们是先经过服务端编译时不能成功的,也就是说,我们要先进入到服务端的目录本地成功编译一次之后,才能在服务端成功编译。最重要的一点是服务端打包之间不能进行clean,具体原因我也不是很清楚,应该是跟AS 3.0升级的特性有关系,改天研究一下官方文档才能知道具体原因,也就是说目前的情况如下:
也就是在AS3.0的基础上,如果我想在服务端自动构建apk,那么首先必须在本地成功编译一次,既然是这样,那么我们干脆在本地先把所有渠道的Debug包Release包先统一编译一次,这样的话在服务端不管想要打哪种包都是OK的,就这么愉快地决定了。

  • gradlew clean
  • gradlew build

这样就好了,剩余的操作跟之前的AS 2.X基本一致,OK,到此为止,AS 3.0也可以很轻松的使用jenkins,虽然折腾了很久,但是最终还是解决了问题。

后续

集成过jenkins的小伙伴们可能知道,其实还有很多功能没有细说,比如说打完包后将安装包自动上传到fir或者蒲公英,生成一个二维码,发送邮件到指定的收件人,其实这些都比较好解决的,网上已经有很多教程了,而且这些都可以通过插件跟脚本实现,下面贴一下相关的插件,大家Google或者百度一下就可以搞定了,本文主要在于分析一下AS 3.0的继承问题,没有针对这些问题进行研究。