使用Gradle与Ant实现可配置不同环境的自动打包
一、搭建jenkins环境和配置gradle环境 网上搭建jenkins的教程很多,这里不再赘述,主要说下jenkins中配置gradle环境 点击“Manage Jenkins” 1、在“Manage Plugins”中搜索并安装gradle插件 2、在“Configure System”中配置指向你电脑中gradle所在路径(这步前当然要下载gradle)
一、搭建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、http://blog.csdn.net/changemyself/article/details/39927381
8、《Gradle构建编译速度太慢的解决方法》http://www.52codes.net/article/658.html
更多推荐
所有评论(0)