以下内容是针对自我一天的Gradle了解所得,如有不当之处,还望指正。
关于Gradle原理之类的东西,我看了但是理解的不好,所以也就不说了。具体看参见此文。深入理解Android之Gradle
1、utils.gradle
新建了一个工具gradle,主要用于存放公用方法处理,方法大致如下:
//从AndroidManifest中获得版本名称
def getVersionName() {
def xmlFile = project.file("src\\main\\AndroidManifest.xml")
def rootManifest = new XmlSlurper().parse(xmlFile)
return rootManifest['@android:versionName']
}
//从AndroidManifest中获得版本号
def getVersionCode() {
def xmlFile = project.file("src\\main\\AndroidManifest.xml")
def rootManifest = new XmlSlurper().parse(xmlFile)
return rootManifest['@android:versionCode']
}
//对于 android library编译,我会 disable 所有的 debug 编译任务
def disableDebugBuild() {
//project.tasks 包含了所有的 tasks,下面的 findAll 是寻找那些名字中带 debug 的 Task。
//返回值保存到 targetTasks 容器中
def targetTasks = project.tasks.findAll { task ->
task.name.contains("Debug")
}
//对满足条件的 task,设置它为 disable。如此这般,这个 Task 就不会被执行
targetTasks.each {
println "disable debug task : ${it.name}"
it.setEnabled false
}
}
//获取当前系统的时间
def releaseTime() {
return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}
//文件复制
def copyFile(File srcFile, File targetFile) {
targetFile.withOutputStream { os ->
srcFile.withInputStream { ins ->
os << ins
}
}
}
//清理输出目录
def cleanOutPut() {
File outputFile = new File("app\\build\\outputs\\apk")
if (outputFile.exists() && outputFile.isDirectory()) {
outputFile.deleteDir()
}
}
//将函数设置为 extra 属性中去,这样,加载 utils.gradle 的 Project 就能调用此文件中定义的函数了
ext {
getVersionCode = this.&getVersionCode
getVersionName = this.&getVersionName
disableDebugBuild = this.&disableDebugBuild
releaseTime = this.&releaseTime
copyFile = this.©File
cleanOutPut = this.&cleanOutPut
}
2、在所有项目中使用utils.gradle
在主项目(并非app module)的build.gradle添加如下代码。
buildscript {
....
}
//遍历所有项目,包括当前主项目
allprojects {
repositories {
jcenter()
}
}
//遍历所有子项目(module)
subprojects {
//为每个子 Project 加载 utils.gradle 。当然,这句话可以放到 buildscript 花括号之后
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
}
3、分渠道打包
3.1 在app module的AndroidManifest.xml中定义好 “占位符”
<meta-data
android:name="UMENG_CHANNEL"
android:value="${CHANNEL_VALUE}" />
<meta-data
android:name="CHANNEL_ID"
android:value="${CHANNEL_ID}" />
3.2 使用productFlavors列举所有待打包的渠道信息
productFlavors {
xiaomi {
manifestPlaceholders = [CHANNEL_VALUE: 'xiaomi', CHANNEL_ID: 300]
}
suibian {
manifestPlaceholders = [CHANNEL_VALUE: 'suibian', CHANNEL_ID: 400]
}
shishi {
manifestPlaceholders = [CHANNEL_VALUE: 'shishi', CHANNEL_ID: 200]
}
}
3.3 指定打包时的签名信息
使用gradle打包时,他会打包成两类包,一类是签名包,另一个就是为签名包(unaligned)。
unaligned代表没有进行zip优化的,unsigned代表没有签名的
如果此处你的配置有问题,密码或者别名不对,编译就会失败,给出类似 Failed to read key from keystore的提示。
apply plugin: 'com.android.application'
android {
...
signingConfigs {
release {
storeFile file("keyStore\\kkss.jks")
storePassword "aaaaaa"
keyAlias "kkssTest1"
keyPassword "aaaaaa"
}
//debug包的签名信息
debug {
storeFile file("keyStore\\kkss.debug.jks")
storePassword "aaaaaa"
keyAlias "kkssDebugTest1"
keyPassword "aaaaaa"
}
}
...
}
3.4 指定构建类型
在使用gradle构建时,可以使用assemble对所有buildType构建,也可以使用assembleRelease,assembleDebug,assembleDemo单独构建(demo为自定义字符串)。
apply plugin: 'com.android.application'
android {
...
buildTypes {
release {
minifyEnabled false//是否混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
debuggable true
minifyEnabled false//是否混淆
signingConfig signingConfigs.debug
}
//定义的构建类型,用assemble打包时自动构建,也可以用assembleDemo单独构建
demo {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
...
}
3.5 更改打包出来的apk文件名
此步骤只会更改签名包的apk文件名
apply plugin: 'com.android.application'
android {
...
//修改生成的apk名字,格式为 app名_版本号_打包时间_渠道名_buildType.apk
applicationVariants.all { variant ->
variant.outputs.each { output ->
def oldFile = output.outputFile
def versionName = variant.versionName
def releaseApkName = "appName_v" + versionName + "_${releaseTime()}_" + variant.productFlavors[0].name + '_' + variant.buildType.name + '.apk'
output.outputFile = new File(oldFile.parent, releaseApkName)
}
}
...
}
以下是可选步骤
3.6 使用AndroidManifest中指定版本信息
在AS中一般是以gradle文件中指定的版本信息(versionCode,versionName)进行打包,但是如果你想使用AndroidManifest的版本信息的话,你可以参见以下代码。
apply plugin: 'com.android.application'
android {
defaultConfig {
applicationId "com.crrain.frescotest"
minSdkVersion 10
targetSdkVersion 23
}
...
//创建一个task,动态更新defaultConfig的版本信息的配置
task initVersionInfoWithManifestFile {
//这里的getVersionCode(),getVersionName()是在utils.gradle中定义的。由于我们已经为每个子项目加载了该文件,所以此处可以直接使用。
defaultConfig.versionCode = getVersionCode().text().toInteger()
defaultConfig.versionName = getVersionName()
}
...
}
3.7 在编译时运行清理和设置版本信息Task
apply plugin: 'com.android.application'
android {
...
//新建的清理输出目录的Task,该Task依赖了初始化版本信息的Task,所以会运行之。
task cleanOutPutCash(dependsOn: initVersionInfoWithManifestFile) {
cleanOutPut()
}
//指定在编译时运行清理Task
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn cleanOutPutCash
}
...
}
3.8 禁用lint自检造成的打包失败
lintOptions {
abortOnError false
}
3.9 支持AAR包
aar是由AS打包出来的项目资源包(*.jar+res资源)。
apply plugin: 'com.android.application'
android {
...
//支持AAR
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
...
compile(name: 'xxx', ext: 'aar')
}