Jenkins Android 集成

本文详细介绍如何使用Jenkins配合Git及Gradle实现Android项目的自动化构建,包括配置流程、参数化构建及二维码下载等功能。

在 window7 本机环境下用 Jenkins 对 Android 集成打包。

本文综合 Android Jenkins+Git+Gradle持续集成-实在太详细 利用Jenkins玩转Android自动打包发包 这两篇文章而成。

一、基本配置和构建


1. 下载 jenkins

官网 下载地址

2. 安装相应的插件

系统管理>> 管理插件
Branch API Plugin
build timeout plugin
build-name-setter
Credentials Binding Plugin
description setter plugin
Dynamic Parameter Plug-in
Environment Injector Plugin
fir-plugin(可选)
Git plugin(可选)
GIT server Plugin(可选)
Gradle Plugin
Pipeline: Basic Steps
Pipeline: Build Step
Pipeline: Input Step
Pipeline: Nodes and Processes
Pipeline: Stage Step
Post-Build Script Plug-in
SSH Slaves plugin
Subversion Release Manager plugin(可选)
Timestamper
Workspace Cleanup Plugin
Subversion Plug-in(可选)

因为 jenkins 版本更新,Dynamic Parameter Plug-in 这插件因为不安全,已经没有了,不够可以从下面这个网站去下载 然后在 高级>上传插件 中上传即可
这里写图片描述

详情参考jenkins参数化构建过程添加参数时没有Dynamic Paramter选项怎么办?

3.配置
. 配置Global Tool Configuration

系统管理>> Global Tool Configurantion

这里包括配置 JDK, GIT以及Gradle,具体看截图
这里写图片描述

这里写图片描述

我这里配置了 Gradle2.14 和 Gradle 3.4.1,其实配一个就可以了,看个人需求。
这里写图片描述

.配置 Android 环境

系统管理 >> 全局属性
这里写图片描述
这里的 SDK 路径要与 Android Studio 里配置的一致

4.新建构建项目

. 进行 git 项目地址的配置
这里写图片描述



. 添加 Credentials , 就是添加账号和密码
这里写图片描述

. 构建
增加构建步骤 >> Invoke Gradle script >> Invoke Gradle
选择相应的 Gradle Version, 在 Tasks 中添加相应的 gradle 脚本命令

然后保存,回到项目主页面,选择立即构建即可
这里写图片描述



备注: 可能出现的问题 构建的时候可能会因为 android build cache 路径过长,导致失败

AAPT err(Facade for 1574801287): \\?\C:\Windows\System32\config\systemprofile\.android\build-cache\a6567330c6202da5c23cba8fdcd5a6cd9ef3e184\output\res\drawable-mdpi-v4\abc_scrubber_control_to_pressed_mtrl_005.png ERROR: Unable to open PNG file

解决方法:单独建立一个 build cache 目录,用于构建,然后在 gradle.properties 中指定刚刚建立的 build cache 路径即可。

android.enableBuildCache=false
android.buildCacheDir=D:\\Android_cache


二、自定义构建

自定义构建需要 Android 项目和 Jenkins 相应的配置

1. 参数化构建过程

jenkins 项目配置中相关的构建
. 配置项目分支
这里写图片描述
在源码中也要进行相应的修改
这里写图片描述


. 配置 product flavor
这里的选项必须要与项目中 build.gradle 中是一致
这里写图片描述

. 是否为 Jenkins 构建
这里写图片描述


. 构建时间
这里写图片描述


. 配置构建版本
这里写图片描述


. 配置构建自定义标签(可选项)
这里写图片描述



项目 build.gradle 中的配置

apply plugin: 'com.android.application'

// 获取时间戳
def getDate(){
    def date = new Date();
    def formattedDate = date.format('yyyy-MM-dd-HH-mm')
    return formattedDate
}

// 版本号
def verCode = 1
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.yxhuang.jenkinsdemo"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode verCode
        versionName APP_VERSION
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    // 签名信息
    signingConfigs {
        release {
            //由于本地打包使用的是本机上的KeyStore,而Jenkins打包用的是服务器上的KeyStore
            //两个路径不一样
            if("true".equals(IS_JENKINS)){
                storeFile file(KEY_STORE_FILE_PATH_IN_SERVER)
            }else {
                storeFile file(KEY_STORE_FILE_PATH_IN_LOCAL)
            }
        }

        debug{

        }
    }


    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }

        debug {

        }
    }


    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

    // 渠道
    productFlavors {
       Commonsoon {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "commonsoon"]
        }

        Zhushou91 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zhushou91"]
        }

        Market360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "market360"]
        }

        Xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }

        Wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }

        Marketandroid {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "marketandroid"]
        }

        Yingyonghui {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyonghui"]
        }

        Jifengmarket {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "jifengmarket"]
        }

        Mumayi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "mumayi"]
        }

        Anzhimarket {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "anzhimarket"]
        }

        Yingyongbao {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]
        }

        Huaweimarket {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "huaweimarket"]
        }
    }

    //修改生成的apk名字
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // 新名称
            def newName
            // 时间戳
            def timeNow
            // 输出路径
            def outDirectory;

            if ("true".equals(IS_JENKINS)) {   // 服务器打包
                timeNow = BUILD_TIME
                outDirectory = BUILD_PATH_IN_SERVER
                newName = 'android-v' + APP_VERSION + '-' + variant.productFlavors[0].name + '-' +  timeNow + '-' + variant.buildType.name + '.apk'
            } else {    // 本机打包
                timeNow = getDate()
                outDirectory = output.outputFile.getParent()
                if (variant.buildType.name.equals('debug')) {
                    newName = "android-v${APP_VERSION}-debug.apk"
                } else {
                    newName = 'android-v' + APP_VERSION + '-' + variant.productFlavors[0].name + '-' + timeNow + '-' + variant.buildType.name + '.apk'
                }
            }

            output.outputFile = new File(outDirectory + '/' + timeNow , newName)

        }
    }

}

// 定义一个任务来获取 Release Password
task getReleasePassword << {
    def keypassword = ''
    def storepassword = ''
    def keyalies = ''
    if (rootProject.file('private.properties').exists()){
        Properties properties = new Properties();
        properties.load(rootProject.file('private.properties').newDataInputStream())
        keypassword = properties.getProperty('release.password')
        storepassword = properties.getProperty('release.storepassword')
        keyalies = properties.getProperty('release.keyalies')
    }

    android.signingConfigs.release.keyPassword = keypassword
    android.signingConfigs.release.storePassword = storepassword
    android.signingConfigs.release.keyAlias = keyalies
}

// 运行时才添加,相当于 Hook
tasks.whenTaskAdded { theTask ->
    if (theTask.name.contains("Release")){
        theTask.dependsOn "getReleasePassword"
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}


在 gradle.properties 中的配置如下

# 编译路径
android.enableBuildCache=false
android.buildCacheDir=D:\\Android_cache


## APP version name
APP_VERSION = 1.0.1

# 是否为 Jenkins 编译, 默认是 false
IS_JENKINS = false

# 构建时间
BUILD_TIME = ''

# keyStore 在服务器上的路径
KEY_STORE_FILE_PATH_IN_SERVER = E:\\work\\testkeystore\\jenkinsDemo.jks
# keyStore 在本地路径
KEY_STORE_FILE_PATH_IN_LOCAL = E:\\work\\testkeystore\\jenkinsDemo.jks

# 服务器生构建路径
BUILD_PATH_IN_SERVER = D:\\Workspaces\\Jenkins\\apk

因为我这里是在本机的环境下构建的,所以 keyStore 在服务器和本地路径一样的,如果在服务器上构建的话,进行相应的修改即可。


签名信息是在 prviate.properties 上配置的,正常情况下这个文件不用提交到 git 上的。

release.password=123456
release.storepassword=123456
release.keyalies=yxhuang

关于签名等 gradle 详细内容,可以参考我的上一篇文章Gradle for Android 简要记录


配置完成后就可以看到
这里写图片描述


Build with Paramters 构建生成的 apk
这里写图片描述


三、二维码下载

构建完成后,apk 包还要去目录中拿,我们可以用二维码展现出来,这样就可以扫码下载安装 apk 了。生成二维码有两种方法,一种是利用蒲公英的二维码,另一种是自己生成二维码。
这里需要用到 Tomcat, 先把 Tomcat 安装好,然后进行一些配置

1. 配置 Tomcat

. 改端口
由于我们之前已经安装了 Jenkins, 它的端口是 8080, Tomcat 的也是,这里会有冲突,所以要改一下 tomcat 的端口。
在安装目录下 conf/server.xml 文件将

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

改为

<Connector port="8084" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

. 将 jenkins 放入到 tomcat 中
将 jenkins 目录下的 war 文件夹里面的所有东西都复制到 tomcat 目录下 webapps 目录的 jenkins 文件夹中。
如果这样时候在浏览器中进入 http://localhost:8084/jenkins 这时候会发现变成了重新安装 jenkins 了。所以我们还需要经 tomcat 中的 jenkins 指向我们之前已经配置好的 jenkins.
在 tomcat 目录下 conf/context.xml 文件中添加

<Environment name="JENKINS_HOME" value="D:\Program Files (x86)\Jenkins" type="java.lang.String"/>

其中 value 值是之前 jenkins 安装的目录

Context>
    ...
    <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
    -->
    <!-- 将 jenkins 目录添加进来 -->
    <Environment name="JENKINS_HOME" value="D:\Program Files (x86)\Jenkins" type="java.lang.String"/>
</Context>

然后就可以看到了
这里写图片描述


1. 利用蒲公英二维码

利用蒲公英的二维码需要用到 curl 命令,在 windows 操作系统是没有,需要安装。可参考这篇文章windows下使用curl命令
. 在构建步骤中选择 Execute windows batch command
这里写图片描述
其中 file 是配置生成的 apk, uKey 和 api_key 是蒲公英上自己账户的 uKey 和 api_key

. Set build description
设置 build 的描述,展现二维码,在构建后操作选择
这里写图片描述

. 系统设置 >> Configure Global Security 中 Markup Formatter 选择 Safe HTML
这里写图片描述

最后生成就可以看到二维码了
这里写图片描述

2. 自己生成二维码

自己生成二维码需要用到 python 以及 qrcode 这个库。所以先安装好 python 和 clone 下来 qrcode。
还有 python 安装 PLY
. Jenkins 配置 python 环境
在系统管理 >> 系统设置 >> 全局属性中设置
这里写图片描述

. 构建的路径改为在 tomcat 的目录下

# 服务器生构建路径
BUILD_PATH_IN_SERVER = D:\\Program Files\\Tomcat 8.0\\webapps\\apk

. Python 脚本设置
路径名称因为有空格,要用双引号括起来。需要经 IP 改自己本机的 IP
这里写图片描述
. 构建后的设置
这里写图片描述

<img src='http://192.168.13.1:8084/apk/${BUILD_TYPE}/qrcode.png' width=200px height=200px><br><a href=http://192.168.13.1:8084/apk/${BUILD_TIME}/android-v${APP_VERSION}-${PRODUCT_FLAVOR}-${BUILD_TIME}.apk">http://localhost:8084/apk/${JENKINS_TIME}/android-v${APP_VERSION}-${PRODUCT_FLAVOR}-${JENKINS_TIME}-${ENVIRONMENT}.apk</a>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值