gradle概览
Project build.gradle
//配置构建过程
buildscript {
//配置依赖仓库 maven
repositories {
mavenCentral()
}
//配置依赖插件 gradle
dependencies {
classpath 'com.android.tools.build:gradle:0.11.1'
}
}
//应用android插件
apply plugin: 'android'
//配置android构建所需所有参数
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
}
Module build.gradle
下面是实际项目的一个截图,我们常用的几个顶层配置都在这了,我们重点关注android这个配置项,其他几项不太需要修改
接下来看下android配置项下面的子集
defaultConfig{} 默认配置,是ProductFlavor类型。它共享给其他ProductFlavor使用
sourceSets{ } 源文件目录设置,是AndroidSourceSet类型。
buildTypes{ } BuildType类型
signingConfigs{ } 签名配置,SigningConfig类型
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
aaptOptions{ } aapt配置,AaptOptions类型
lintOptions{ } lint配置,LintOptions类型
dexOptions{ } dex配置,DexOptions类型
compileOptions{ } 编译配置,CompileOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。 用于设定 jacoco版本
splits{ } Splits类型
下面列几个常用的配置项,
lintOptions {
lintConfig file("lint.xml")
abortOnError false
}
sourceSets { //目录指向配置
main {
manifest.srcFile 'AndroidManifest.xml' //指定 AndroidManifest 文件
java.srcDirs = ['src'] //指定 source 目录
resources.srcDirs = ['src'] //指定 source 目录
aidl.srcDirs = ['src'] //指定 source 目录
renderscript.srcDirs = ['src'] //指定 source 目录
res.srcDirs = ['res'] //指定资源目录
assets.srcDirs = ['assets'] //指定 assets 目录
jniLibs.srcDirs = ['libs'] //指定 lib 库目录
}
debug.setRoot('build-types/debug') //指定 debug 模式的路径
release.setRoot('build-types/release') //指定 release 模式的路径
}
signingConfigs { //签名配置
release { //发布版本签名配置
storeFile file("fk.keystore") //密钥文件路径
storePassword "123" //密钥文件密码
keyAlias "fk" //key 别名
keyPassword "123" //key 密码
}
debug { //debug版本签名配置
storeFile file("fk.keystore")
storePassword "123"
keyAlias "fk"
keyPassword "123"
}
}
buildType { // build 类型
release { //发布
minifyEnabled true //混淆开启
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-android.txt' //指定混淆规则文件
signingConfig signingConfigs.release //设置签名信息
}
debug { //调试
signingConfig signingConfigs.release
}
custom {//自定义类型
minifyEnabled false
renderscriptDebuggable true
}
}
local.properties
配置sdk.dir属性,配置这个跟配置ANDROID_HOME环境变量差不多
任务
● assemble 这个任务会汇集工程的所有输出。
● check 这个任务会执行所有校验检查
● connectedCheck 运行checks需要一个连接的设备或者模拟器,这些checks将会同时运行在所有连接的设备上。
● deviceCheck 通过API连接远程设备运行checks。它被用于CI(译者注:持续集成)服务器上。
● build 这个任务会同时执行 assemble 和 check 任务
● clean 这个任务会清理工程的所有输出
共享变量
定义整个项目的公共变量,如sdk版本等,让所有子module都使用同样的配置
新建common_config.gradle文件
project.ext{
//java语言相关
javaVersion = 8
javaMaxHeapSize = '4G'
//Android编译相关
compileSdkVersion = 23
buildToolsVersion = '23.1.1'
minSdkVersion = 16
targetSdkVersion = 23
//混淆相关
minifyEnbale = true
shrinkResEnable = minifyEnable
//JDK版本兼容
sourceCompatibility = this.&getJavaVersion()
targetCompatibility = this.&getJavaVersion()
}
def getJavaVersion(){
switch(project.ext.javaVersion){
case "6":
return JavaVersion.VERSION_1_6
case "7":
return JavaVersion.VERSION_1_7
case "8":
return JavaVersion.VERSION_1_8
default:
return JavaVersion.VERSION_1_6
}
}
module中使用
apply from: "${project.rootDir}/common_config.gradle"
minSDKVersion project.ext.minSdkVersion
除了在每个module中进行如上配置导入common_config.gradle之外还可以使用下面方式
只需在Project的build.gradle做如下一次性配置
subprojects{
apply from: "${project.rootDir}/common_config.gradle"
dependencies{
testCompile 'junit:junit:4.12'
}
}
多渠道打包
上面的常用内容配置一个apk的打包足够了,但很多时候我们应用上架需要配置多个应用商店每个apk包都有一些不同的信息,下面看看这种情况如何处理。
多渠道需要处理的主要就是每个渠道都有一些各自的参数,下面看看这方面怎么处理。这里假设每个渠道的application label都不一样。
这里引用一个变量${APP_NAME},我们需要在build.gradle中根据不同的渠道进行配置
这里主要是两个配置项,都在android配置项里
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
上面配置了release和debug两个版本
productFlavors{
//百度推广渠道
baidu {
applicationId "com.android.baidu"
versionCode 1
versionName "1.0"
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
manifestPlaceholders = [ APP_NAME : "app-百度"]
}
//360推广渠道
qh360 {
applicationId "ccom.android.three"
versionCode 1
versionName "1.0"
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
manifestPlaceholders = [ APP_NAME : "app-360"]
}
//豌豆荚推广渠道
wandoujia {
applicationId "com.android.douban"
versionCode 1
versionName "1.0"
manifestPlaceholders = [ APP_NAME : "app-豌豆荚"]
}
}
上面配置了三个渠道,三个渠道主要修改了包名跟配置了APP_NAME.这样配置渠道包的工作就差不多好了,这里会生成(release+debug) * (baidu + 360 + wandoujia) = 6个Apk包。
此外还要做一个额外的工作,就是输出的时候 修改apk文件名,否则你只能看到一个Apk包了
这个工作只需要配置andorid下的一个配置项即可
applicationVariants.all{variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def buildType = variant.buildType.name
//这里修改apk文件名,格式为 app_渠道名-版本名-当前时间-编译版本.apk
def fileName = "app_${variant.productFlavors[0].name}-V${defaultConfig.versionName}-${getCurrentTime()}-${buildType}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
我们注意到这边还需要一个getCurrentTime()的函数,在与android同级的目录下定义一个好了
//获取当前时间
def getCurrentTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
最后在项目的根目录下运行gradle build,注意输出目录
签名
签名这块也很简单,Build -> Generate Signed APK 里可以创建一个key
创建后,我们在build.gradle的android配置项里做如下配置
signingConfigs{
myconfig {
keyAlias 'huang'
keyPassword '123456'
storeFile file('/home/huangshunbo/demo.jks')
storePassword 'huangshunbo'
}
}
最后在想要使用该签名的buildTypes里做下引用即可
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.myconfig
}
}
就这样,签名搞定。下面备注点小知识
查看三方应用或是系统应用签名:解压apk -> 进入META-INF得到CERT.RSA文件,通过
keytool -printcert -file META-INF/CERT.RSA
查看签名信息
查看签名文件demo.jks信息
keytool -v -list -keystore demo.jks
混淆
首先在buildTypes配置需要混淆并指定混淆规则文件
buildTypes {
debug {
minifyEnabled true //是否要混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//混淆的规则
}
}
Proguard的4个特性:压缩、优化、混淆、预检测
proguard-android.txt是Proguard默认的混淆配置文件
proguard-rules.pro在module根目录下,可替代proguard-android.txt作为补充。
一般的,我们在proguard-rules.pro文件里做相关的混淆配置
常用的一些配置:
-keep开头的表示保持不变,不去混淆
-keep {Modifier} {class_specification} #保护指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} #保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} #保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。
-keepnames {class_specification} #保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)
-keepclassmembernames {class_specification} #保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
-keepclasseswithmembernames {class_specification} #保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)
eg:
-keep public class * extends android.app.Activity #保持Activity的子类不被混淆
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
-keep class **.R$* {*;} # 保留R下面的资源
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
#不做预校验
-dontpreverify
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#忽略警告
-ignorewarning
#混淆过程打印日志的级别
-verbose
#不使用优化方案
-dontoptimize
#混淆时不做预校验
-dontpreverify
#如果项目中使用到注解,需要保留注解属性
-keepattributes *Annotation*
#保持native方法不作混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持Views中的setter和getter方法不混淆,保证属性动画能够正常执行
-keepclassmembers public class * extends android.view.View{
void set*(***);
*** get*();
}
#保持Activity中参数是View类型的函数,保证在XML文件中配置的onClick属性的值能够正常调用到
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#保持枚举类型中的函数
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#不混淆泛型
-keepattributs Signature
#保留代码行号,这在混淆后代码运行中抛出异常信息时,有利于定位出问题的代码
-keepattributes SourceFile,LineNumberTable
#保留R类
-keep class **.R$*{
*;
}
Proguard运行后生成的四个文件(build/outputs/mapping/release目录下)
- dump.txt:列出生成的APK文件中所有class文件的内部结构
- mapping.txt:列出混淆钱的Java源码和混淆后的类、方法、属性名之间的映射关系
- seeds.txt:列出未混淆的类和成员
- usage.txt:列出从APK文件中剥离的代码
Maven Central 和 JCenter
目前存在两个标准的Java & Android Maven仓库:Maven Central 和 JCenter。目前JCenter相对有优势而且Maven Central可以说是JCenter的一个子集。上传函数库到JCenter只需要到Bintray网站上进行操作即可
仓库的匹配模式
compile 'de.greenrobot:eventbus:2.4.0'
GROUP_ID组织/公司/个人名:ARTIFACT_ID函数库名:VERSION版本号
杂
.arr 的导入
# 生成arr
android{
repositories {
flatDir {
dirs 'aars'
}
}
}
# 使用aar
dependencies {
compile(name:'libraryname', ext:'aar')
}
dependencies
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') //编译lib 目录下的 jar 文件
compile project(':Easylink') //编译附加的项目
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.jakewharton:butterknife:8.4.0' //编译第三方开源库
}