使用Gradle与Ant实现可配置不同环境的自动打包

一、搭建jenkins环境和配置gradle环境

??网上搭建jenkins的教程很多,这里不再赘述,主要说下jenkins中配置gradle环境

??点击“Manage Jenkins”

????1、 在“Manage Plugins”中搜索并安装gradle插件

????2、 在“Configure System”中配置指向你电脑中gradle所在路径(这步前当然要下载gradle)

????

二、新建jenkins项目并设置构建gradle配置项

??1、点击new item新建一个jenkins项目

??2、设置构建配置项

????a、配置svn代码所在目录

????

????b、配置执行gradle命令(【注意】只有在jenkins中下载安装 了gradle插件后,在”Build”构建项中点击”Add build step”增加构建步骤中看到“Invoke Gradle script”调用gradle脚本)

????

如上几步后能实现gradle最基本的打包(输出apk的路径app/build/outputs/apk/xxxx.apk)


三、配置ant脚本修改与环境相关的配置项代码(修改jenkins的项目源码)

??根据网上搜索的资料,可以在build.gradle脚本的task中修改项目中.java代码,但并没看到大量修改源码并很方便的做法;对于目前所在项目组打包中修改多次环境相关的源代码,还是用ant来专门处理修改源码,两种方式:

??1、jenkin的”Add build step”中可以先调用”Invoke Ant”然后”Invoke Gradle script”

??2、build.gradle中导入ant脚本(此方法缺点就是不能在”Invoke Ant”的Properties中动态修改源码)

ant.importBuild ‘../power-gradle.xml‘

ant脚修改源码步骤如下:

??a、AppConfig .java源码

package com.demo.project;
public class AppConfig {
    /**
     *
     * 是否打开调试
     */
    public static boolean isDebug = true;
    /**
     * 配置是否用于测试
     */
     public static boolean isTest = true;
}

??b、before-gradle.xml脚本

<?xml version="1.0" encoding="UTF-8"?>
<project name="DemoProject" basedir="." default="release">

    <!--《一》、 start 项目源代码目录 -->
    <property name="src" value="app/src" />
    <property name="res" value="app/src/main/res" />
    <!--《一》、end 项目源代码目录 -->

    <!--《二》、start 文件修改涉及到的文件名称及路径声明 -->
    <property name="AppConfig" value="${src}/main/java/com/demo/project/AppConfig.java" />
    <!--《二》、 end 文件修改涉及到的文件名称及路径声明 -->

    <!--《三》、start 在Jenkins中Ant属性Properties根据需求来配置不同值 -->
    <!-- 1、AppConfig文件 -->
    <!-- isDebug,默认false-->
    <property name="isDebug" value="false" />
    <property name="isDebug-pattern" value="isDebug( )*=( )*.*"></property>
    <property name="replace-isDebug-pattern" value="isDebug = ${isDebug};" />

    <!-- isTest,默认true -->
    <property name="isTest" value="true" />
    <property name="isTest-pattern" value="isTest( )*=( )*.*"></property>
    <property name="replace-isTest-pattern" value="isTest = ${isTest};" />
    <!--《三》、end 在Jenkins中Ant属性Properties根据需求来配置不同值 -->

    <target name="init">
        <echo> 1、setting AppConfig file accord ant Properties</echo>
        <!-- 关闭debug -->
        <echo>replace isDebug to ${isDebug}</echo>
        <replaceregexp file="${AppConfig}" match="${isDebug-pattern}" replace="${replace-isDebug-pattern}" byline="true" flags="gs" encoding="utf-8" />
        <!-- 是否可以选择环境-->
        <echo>replace isTest to ${isTest}</echo>
        <replaceregexp file="${AppConfig}" match="${isTest-pattern}" replace="${replace-isTest-pattern}" byline="true" flags="gs" encoding="utf-8" />
    </target>

    <target name="release" depends="init">
        <echo>ant prepare for release</echo>
    </target>

</project>

??c、jenkins中配置。

??

==> 以上几步可以将isTest设为false,isDebug设为false,执行构建后能出来相应代码配置的apk

五、外部导入签名文件

??专门新建一个文件存放签名有关的keystore所在路径和签名密码,据说酱紫比较安全。。

1、build.gradle中

signingConfigs {
        //外部文件方式导入签名
        def Properties props = new Properties()
        def propFile = new File(‘signing.properties‘)
        if (propsFile.exists() && propFile.canRead()) {
            props.load(new FileInputStream(propFile))

            signingConfigs {
                release {
                    storeFile file(props[‘storeFile‘])
                    storePassword props[‘storePassword‘]
                    keyAlias props[‘keyAlias‘]
                    keyPassword props[‘keyPassword‘]
                }
            }
        }
    }

2、signing.properties中。项目目录下新建该文件

//keystore的绝对路径
storeFile=C:\\demo\\project\\demo.keystore
storePassword=123456
keyPassword=123456
keyAlias=demo

六、多渠道打包

1、AndroidManifest.xml

<meta-data android:name="CHANNEL_ID" android:value="${CHANNEL_ID_VALUE}"/>

2、build.gradle

??a、方式一:

productFlavors {//多渠道打包,命令行打包:gradle assembleRelease
    xiaomi {
//        applicationId ‘xiaomiRelease‘ //注释的话,默认xiaomiRelease和xiaomiDebug
          manifestPlaceholders.put("CHANNEL_ID_VALUE", ‘xiaomi‘)
     }
    googlepaly {
//        applicationId ‘googlepalyRelease‘  //默认googlepalyRelease和googlepalyDebug
          manifestPlaceholders.put("CHANNEL_ID_VALUE", ‘googlepaly‘)
     }
}

??a、方式二:

productFlavors {
    xiaomi{}
    googleplay{} 

    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [CHANNEL_ID_VALUE: name]//name的值是xiaomi/googleplay
    }

}

3、打包命令

?电脑中配置了gradle环境变量

??1、gradle clean build -b ./build.gradle构建所有包

????

??2、gradle assembleRelease构建所有渠道发布包

??3、gradle assemble[xxx]Release构建单个渠道发布包。

????如:gradle assembleXiaomiRelease或gradle assembleGooglepalyRelease等和渠道名相关的release命令

4、查看渠道是否随配置更改。查看在下图目录中AndroidManifest.xml中CHANNEL_ID的值xiaomi / googleplay

5、复制apk到目录下apks目录。因为上面release出来的包层级过深,不方便测试人员在jenkins上查找下载apk,所有此步将./app/build/outputs/apk下所有的xx.apk放到DemoProject下的apks目录

//复制输出apk到项目目录下的apks目录
task copyFiles(type: Copy) {
    description = ‘Copy apks to project directory ./apks ‘
    from ‘build/outputs/apk‘
    into ‘./../apks‘  //因为默认./在app目录
    include(‘**/*‘)  //复制所有
}
//根据命令行是构建所有渠道gradle assembleRelease、单个渠道包(如:gradle assembleXiaomiRelease)
//还是build构建包。即copyFiles任务是依赖assembleRelease/assembleXiaomiRelease/build
assembleRelease.dependsOn copyFiles

完整的build.gradle脚本

apply plugin: ‘com.android.application‘

import java.util.regex.Pattern
////获取详细时间
def buildTime() {
    return new Date().format("yyyyMMdd‘-‘HHmm", TimeZone.getDefault())
}
//获取日期
def buildDate() {
    return new Date().format("yyyyMMdd", TimeZone.getDefault())
}

android {
    compileSdkVersion 21
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.demo.project"
        minSdkVersion 8
        targetSdkVersion 8
        multiDexEnabled true
    }

    sourceSets {
        main {
//            manifest.srcFile ‘AndroidManifest.xml‘
//            java.srcDirs = [‘src‘]
//            resources.srcDirs = [‘src‘]
//            aidl.srcDirs = [‘src‘]
//            renderscript.srcDirs = [‘src‘]
//            res.srcDirs = [‘res‘]
//            assets.srcDirs = [‘assets‘]
            jniLibs.srcDirs = [‘libs‘] // 指定jni路径
        }
    }
//    签名
    signingConfigs {
        release {
//            storeFile file(‘release.keystore‘)
//            storePassword ‘123456‘
//            keyAlias ‘demo‘
//            keyPassword ‘111111‘
        }
    }
    buildTypes {
        release {
            //是否混淆开关
            minifyEnabled false
            //是否zip对齐
            zipAlignEnabled true
            //是否打开debuggable开关
            debuggable false
            //是否打开jniDebuggable开关
            jniDebuggable false
            //混淆配置文件
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.txt‘
            //签名配置
//            signingConfig signingConfigs.release

//            //release发布版本时针对多渠道。相当于省略多个manifestPlaceholders.put("CHANNEL_ID_VALUE", ‘xiaomi‘)
//            productFlavors.all { flavor ->
//                manifestPlaceholders.put("CHANNEL_ID_VALUE", name) //name等于xiaomi / googlepaly
//            }
        }
    }
    lintOptions {//lint检查,有任何的错误或者警告提示,都会终止构建。false是关闭lint
        //在打包Release版本的时候进行检测,可以打开,这样报错还会显示出来
        checkReleaseBuilds false
        //abortOnError一定要设为false,这样即使有报错也不会停止打包了
        abortOnError false
    }
    productFlavors {//多渠道打包,命令行打包:gradlew assembleRelease
        xiaomi {
//            applicationId ‘xiaomiRelease‘ //注释的话,默认xiaomiRelease和xiaomiDebug
            manifestPlaceholders.put("CHANNEL_ID_VALUE", ‘xiaomi‘)
        }
        googlepaly {
//            applicationId ‘googlepalyRelease‘  //默认googlepalyRelease和googlepalyDebug
            manifestPlaceholders.put("CHANNEL_ID_VALUE", ‘googlepaly‘)
        }
    }
    android.applicationVariants.all { variant ->
        def manifestFile = file("src/main/AndroidManifest.xml")
        def pattern = Pattern.compile("versionName=\"(.+)\"")
        def manifestText = manifestFile.getText()
        def matcher = pattern.matcher(manifestText)
        matcher.find()
        //获取versionName
        def versionName = matcher.group(1)
        pattern = Pattern.compile("versionCode=\"(.+)\"")
        matcher = pattern.matcher(manifestText)
        matcher.find()
        //获取versionCode
        def versionCode = matcher.group(1)

        if (variant.buildType.name.equals(‘release‘)) {
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith(‘.apk‘)) {
//                    def fileName = "gradle4android_v${defaultConfig.versionName}_${releaseTime()}_${variant.flavorName}.apk"
                    def fileName = buildDate() + "/" + applicationId + "-v" + versionName + "-" + variant.name + "-" + buildTime() + "-" + variant.flavorName + ".apk"
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        } else {
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith(‘.apk‘)) {
                    def fileName = buildDate() + "/" + applicationId + "-v" + versionName + "-" + variant.name + "-" + buildTime() + "-unaligned.apk"
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        }
    }

}

//复制输出apk到项目目录下的apks目录
task copyFiles(type: Copy) {
    description = ‘Copy apks to project directory ./apks ‘
    from ‘build/outputs/apk‘
    into ‘./../apks‘  //因为默认‘./‘在app目录
    include(‘**/*‘)  //复制所有
}
//根据命令行是构建所有渠道gradle assembleRelease,单个渠道包(如:gradle assembleXiaomiRelease)
//还是build构建包。即copyFiles任务是依赖assembleRelease/assembleXiaomiRelease/build
assembleRelease.dependsOn copyFiles

dependencies {
    compile fileTree(include: [‘*.jar‘], dir: ‘libs‘)
}

??gradle在多渠道打包下超有优势,完爆ant;如上脚本gradle打了2个包在哥mac上只需要35-50s,纯ant脚本打一个包2min。。。

??


问题解决:

1、

Could not resolve all dependencies for configuration ‘:classpath’.

Could not resolve com.android.tools.build:gradle:1.5.0.

Required by:

:DemoProject: unspecified

Could not GET ‘https://jcenter.bintray.com/com/android/tools/build/gradle/1.5.0/gradle-1.5.0.pom‘.

Connection to https://jcenter.bintray.com refused

解决方案就是:降低代码中要求的版本classpath ‘com.android.tools.build:gradle:1.3.0’

2、gradle编译速度超慢

命令行中加–offline。如:gradle assemble - -offline,gradle clean - -offline

??gradle-tool是执行gradle的bin目录下gradle工具(window是gradle.bat,unix系统的是gradle)

  <target name="clean" depends="xxx">
       <echo>gradle clean --offline</echo>
       <exec executable="${gradle-tool}" failonerror="true">
           <arg value="clean" />
        <arg value="--offline" />
       </exec>
   </target>

参考:

1、http://doc.okbase.net/tanlon/archive/125036.html

2、http://www.jianshu.com/p/aa7f93d29805

3、多渠道打包:http://mp.weixin.qq.com/s?__biz=MzI4MzE2MTQ5Mw==&mid=402123825&idx=1&sn=404bdcfd65b6da9a9058260a753b6b55#rd

4、完整脚本:https://github.com/WuXiaolong/Gradle4Android

5、gradle系列:http://gold.xitu.io/#/tag/gradle

6、http://blog.csdn.net/shanlianting/article/details/49820607

7、《Gradle构建编译速度太慢的解决方法》http://www.52codes.net/article/658.html

时间: 2024-08-04 16:32:42

使用Gradle与Ant实现可配置不同环境的自动打包的相关文章

Maven配置jar(war)包自动打包上传Maven服务器的配置

创建jar(war)包工程 创建一个maven工程 在工程中穿件一个测试类 配置pom.xml <distributionManagement> <repository> <id>nexus-releases</id> <url>http://127.0.0.1:8081/nexus/content/repositories/releases/</url> </repository> <snapshotReposit

[原] Jenkins Android 自动打包配置(转)

一.Jenkins自动打包配置 目标:1. 自动打包:2. 自动上传:3. 友好下载 1. Jenkins简介 Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作. 减少重复劳动,减少人工成本. 持续.自动地构建/测试软件项目: 监控一些定时执行的任务: 2. Jenkins配置 添加git plugin和 role插件 设置人员权限,根据角色授权 启动访问http://ip/8080即可,见下3.1 开机自启脚本 添加git项目,配置脚本,见下3.2 项目打包脚本和3.

Maven、gradle、Ant、Eclipse IDE

Maven.gradle.Ant.Eclipse IDE之间的关系 http://wenku.baidu.com/view/d33208810912a21615792910.html?from=search 觉得应该很多同学有和我一样的疑惑,所以分享下. 1.使用github上的开源项目时是不是经常发现有个叫maven的东西? 2.第一次使用Android studio时是不是要下载一个gradle的玩意? 折腾了一天,想导入下github的客户端源码.当然现在还没成功...各种看不懂的错误.郁

Gradle的安装与基本配置

学习其他内容时间久了感觉比较枯燥,效率变低,于是想要了解一下Spring源码.下载后发现Spring源码需要使用Gradle来构建(build),下载其依赖的jar包等.因此有必要安装一下Gradle环境. 参:spring 源码如何导入到eclipse 一.Gradle简介 百科:Gradle是一个基于Apache Ant和Apache Maven概念的项目依赖管理.自动化建构工具.它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置. 面向Java

Android Studio中Gradle统一管理版本号引用配置

Gradle统一管理版本号引用配置 为了提高项目开发效率,在实际项目开发过程中往往会引入一些开源框架,还有项目中使用的各种module,moudle过多时最好提供一种统一的方式去管理版本号,如:compileSdkVersion.buildToolsVersion.androidTestCompile 等,便于日后对版本号进行维护,此处记录2种方式处理上述问题. 方式一 1.在项目根目录下创建.gradle文件,如:config.gradle 2.在根目录下的build.gradle文件中引入我

Apache Ant 简介和配置

Apache Ant 简介 Apache Ant是目前事实上的Java应用的标准build脚本工具.使它大受欢迎的一个主要愿意是它的和灵活,允许程序员创建自己的Task来对Ant进行扩展. 本文主要内容有: 对Ant的简介 介绍常用的Ant脚本 Ant的安装 Apache Ant是Apache基金会下的一个项目, 官网:http://ant.apache.org/ 下载地址:http://ant.apache.org/bindownload.cgi 根据不同的平台下载不同的压缩包,直接解压到安装

Java构建工具:如何用Maven,Gradle和Ant+Ivy进行依赖管理

原文来自:https://zeroturnaround.com/rebellabs/java-build-tools-how-dependency-management-works-with-maven-gradle-and-ant-ivy/ 编译的时候可以运行,运行时出问题 在当今java项目自动化构建的场景当中,依赖管理已经成为了项目构建自动化工具中的一个主要部分,但是在过去并总是这样. 回想以前那个很爽的时候,你的项目依赖性管理只需要将jar包导入到lib文件夹中,然后将其加入到你的版本控

Eclipse下配置Ant脚本 自动打包带签名的Android apk

虽然eclipse很少用了,但是在古老的项目上还是会用到.一个麻烦事是打带签名包的时候,非常不方便.下边纪录下配置ant,自动打包带签名apk的过程,作为备忘.(PC环境为MAC) 1,第一步得安ant,下载对应安装包,解压后配置环境变量: export ANT_HOME="/Users/yanzi/work/apache-ant-1.9.4" export PATH=${PATH}:${ANT_HOME}/bin 通过which ant检查是否安装成功. 2,在项目目录下运行:and

Maven、gradle、Ant、Eclipse IDE,ADT,intellij IDEA

(1)Maven.gradle.Ant.Eclipse IDE之间的关系 觉得应该很多同学有和我一样的疑惑,所以分享下. 1.使用github上的开源项目时是不是经常发现有个叫maven的东西? 2.第一次使用Android studio时是不是要下载一个gradle的玩意? 折腾了一天,想导入下github的客户端源码.当然现在还没成功...各种看不懂的错误.郁闷为什么他们弄这些高端玩意干嘛,我们平时eclipse里面不一样的好好的开发吗. 幸好无意间发现网上这篇回答,豁然开朗. "一般而言.