您的位置:首页 > 其它

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

2016-05-13 22:00 609 查看
一、搭建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、/article/2636856.html

8、《Gradle构建编译速度太慢的解决方法》http://www.52codes.net/article/658.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: