一、搭建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
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