Android常用的Gradle配置和加速编译

Why Gradle

Gradle makes the impossible possible, the possible easy and the easy elegant.

在Android开发中经常会用Gradle来构建项目,Gradle能很方便的项目的版本集成和打包,虽Gradle官方已经给出很详细的文档了,但还是有必要抽离出一些常用的配置。

整个Android项目的编译依赖于Gradle的编译,虽然前几天发布了Android 2.0 stable,拥有了Instant Run强大的功能,但是有“改一行布局代码Run一次”习惯的同学有必要知道如何加速Gradle的编译。

主要介绍一下:

  • 如何配置Gradle
  • 如何加速Gradle的编译
  • 一些常用的项目构建知识

How Gradle

gradle.properties文件适合配置IDE的属性,当然也适合配置你在项目的关键/敏感参数,因为它将运行在Incubating parallel mode(

孵化并行模式,应该解释为运行时候嵌入在项目当中),也是属于默认的gitignore,这样你的敏感信息(key账号密码,appkey等)就不会被push到git了,你需要注意的是** 属性中有中文的话,记得转成unicode来显示,不然可能引发一些莫名的错误 **

类似于这样,你可以把你的签名keystore的信息,服务端的endpoint,第三方服务的appkey,ide的配置信息放在这。

  KEY_ALIAS=yat3s
  KEYSTORE_PASSWORD=123456
  KEY_PASSWORD=123456
  umeng_appkey_product=adcdefghijk
  umeng_appkey_dev=adcdefghijk
  deepshare_appid=adcdefghijk
  bugly_appid_product=adcdefghijk
  bugly_appid_dev=adcdefghijk
  rong_appkey=adcdefghijk
  endpoint_product=http://api.yat3s.com
  endpoint_dev=http://api.yat3s.com:9000
  app_name=\u006f\u0070\u0065\u006e\u5f00\u8154`

** 那么配置好这些信息如何在Gradle和Java中使用呢?**

其实Groovy语言和Java很接近也很好用,往下看↓

buildTypes

  buildTypes {
   release {
       minifyEnabled true
       shrinkResources true
       signingConfig signingConfigs.release
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
       buildConfigField "String", "ENDPOINT", "\"${endpoint_product}\""
       resValue "string", "umeng_appkey", "${umeng_appkey_product}"
       resValue "string", "deepshare_appid", "${deepshare_appid}"
       resValue "string", "bugly_appid", "${bugly_appid_product}"
       resValue "string", "rong_appkey", "${rong_appkey}"
       resValue "string", "channel", "product"
       resValue "string", "op_app_name", "${app_name}"
   }
   debug {
       signingConfig signingConfigs.release
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
       buildConfigField "String", "ENDPOINT", "\"${endpoint_product}\""
       resValue "string", "umeng_appkey", "${umeng_appkey_dev}"
       resValue "string", "deepshare_appid", "${deepshare_appid}"
       resValue "string", "bugly_appid", "${bugly_appid_dev}"
       resValue "string", "rong_appkey", "${rong_appkey}"
       resValue "string", "channel", "dev"
       resValue "string", "op_app_name", "dev_${app_name}"
     }
   }
  • 引用gradle.properties 只需要加 ${key}
  • 定义在 buildConfigField "String", "ENDPOINT",""${endpoint_product}"",在Java享用时候只需要读取BuildConfig.ENDPOINT即可
  • 定义在 resValue "string", "umeng_appkey", "${umeng_appkey_product}" , 在xml中享用只需要R.string.umeng_appkey即可

记住几个点:

  • 在你确保你minifyEnabled(混淆)没问题的时候debug模式尽量别开minifyEnabled和shrinkResources,这样会大大降低编译速度
  • 如果真要开混淆,把生成mapping关掉
  • 尽量把一些第三方key分成staging和product,这样容错性高,避免你推送给你的用户一个"Test"
  • 定义buildConfigField时候注意双引号的问题 ""${endpoint_product}""
  • 如果不方便管理签名可debug和release同一个签名。** 如果需要同时安装debug和release包只需要修改applicationId即可 **

defaultConfig

这里尽量新建一个Conifg.gradle文件来统一管理这些基本配置(在project下右键new file即可) ,

Config.gradle文件如下

ext {
android = [compileSdkVersion: 23,
           buildToolsVersion: "23.0.1",
           applicationId    : "com.yat3s.d3v",
           minSdkVersion    : 15,
           targetSdkVersion : 23,
           versionCode      : 36,
           versionName      : "1.3.1"]
}
dependencies = [
               design              : "com.android.support:design:23.3.0",
               nineoldandroids     : "com.nineoldandroids:library:2.4.0",
               retrofit            : "com.squareup.retrofit:retrofit:2.0.0",
               rxandroid           : "io.reactivex:rxandroid:1.0.0",
               okhttp-urlconnection: "com.squareup.okhttp:okhttp-urlconnection:2.0.0",
               okhttp              : "com.squareup.okhttp:okhttp:2.0.0",
               butterknife         : "com.jakewharton:butterknife:7.0.1"] 

然后在项目的build.gradle文件下添加 ** apply from: "config.gradle" **

  apply from: "config.gradle"
  buildscript {
      repositories {
        jcenter()
      }
      dependencies {
        classpath 'com.android.tools.build:gradle:2.0.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
      }
    }       
    allprojects {
      repositories {
        jcenter()
      }
    }       ``

然后你使用起来就简单多了

def config = rootProject.ext.android // 配置
def dep = rootProject.ext.dependencies // 依赖
useLibrary 'org.apache.http.legacy' // 如果你是api23的话,在用到apache的http库时候,记得加上这个,不然混淆时候因为urlConnection的升级导致异常
compileSdkVersion config.compileSdkVersion
buildToolsVersion config.buildToolsVersion
defaultConfig {
  applicationId config.applicationId
  minSdkVersion config.minSdkVersion
  targetSdkVersion config.targetSdkVersion
  versionCode config.versionCode
  versionName config.versionName
  manifestPlaceholders = [UMENG_CHANNEL_VALUE: "open"]
}

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile dep.design
  compile dep.retrofit
  compile dep.okhttp
}

那么这样用的好处是什么呢?

  • 如果你有多个Module都需要依赖design包的话,design包一升级导致了多个module需要改版本,你就可能同时引入了多个依赖导致apk增大
  • 统一管理versionCode和versionName
  • 看起来是不是更简洁

signingConfigs

def keystore = file('keystore/yat3s.jks')
signingConfigs {
    release {
        keyAlias KEY_ALIAS
        keyPassword KEY_PASSWORD
        storePassword KEYSTORE_PASSWORD
        storeFile keystore
    }
}    
  • 在非资源定义(下面有提到的resValue为资源定义,其他的地方则为非资源定义)下引用gradle.properties可直接输入properties的key
  • 如果你要公开你的源码记得把你的keystore ignore掉,私有库无视该项

packagingOptions

packagingOptions {
  exclude 'META-INF/LICENSE'
  exclude('META-INF/LICENSE.txt')
  exclude('META-INF/NOTICE.txt')
  exclude 'META-INF/NOTICE'
  exclude 'META-INF/DEPENDENCIES'
  // umeng推送的jar包含有的okio库跟okhttp的okio库冲突
  exclude 'META-INF/maven/com.squareup.okio/okio/pom.xml'
  exclude 'META-INF/maven/com.squareup.okio/okio/pom.properties'
}
  • 主要处理第三方库在导入时候的一些声明文件冲突,Option this

compileOptions {

compileOptions {
  sourceCompatibility JavaVersion.VERSION_1_7
  targetCompatibility JavaVersion.VERSION_1_7
}
  • 个人觉得如果你不用lambda表达式的话,可以用java1.7,因为1.8还不是完美的支持Android

lintOptions

 lintOptions {
    disable "InvalidPackage"
    disable "MissingTranslation" // 禁用中英文string.xml的强制lint
    lintConfig file("lint.xml")
}

打包管理

def getDate() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) // 注意时区
}     

// 获取当前git的Revision
def getRevision() {
    return ext.hash = 'git rev-parse --short HEAD'.execute().text.trim()
}
productFlavors {
   rc_open {}
   rc_360 {}
   rc_yingyongbao {}
   rc_baidu {}
   rc_91 {}
   rc_wandoujia {}
   rc_anzhuo {}
   rc_xiaomi {}
   rc_meizu {}
   rc_oppo {}
   rc_huawei {}
   rc_weibo {}
   rc_dev {}
   }
productFlavors.all { flavor ->
    // 这里只是方便友盟统计每个渠道的数据
    flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
 }

  // 修改打包后APK的文件名
  applicationVariants.all { variant ->
   variant.outputs.each { output ->
       def oldFile = output.outputFile
       if (variant.buildType.name.equals('release')) {
           // 输出apk名称为yat3s_v1.0_2016-04-12_yingyongbao_a23f2e1.apk
           def releaseApkName = 'yat3s-v' + defaultConfig.versionName + '_' + getDate() + '_' + variant.productFlavors[0].name + "_" + getRevision() + '.apk'
           output.outputFile = new File(oldFile.parent, releaseApkName)
       }
       if (variant.buildType.name.equals('debug')) {
          // Do nothing
       }
   }
 }
  • 多渠道打包用的是Gradle的productFlavors
  • git的Revision 方便你管理你的release和tag
  • 打包的时候可以用Jenkins来自动Build你的包

Speed Gradle

我们都知道编译项目时候是依赖gradle的,gradle的构建速度决定了你的工作效率,上面零散的提到几点,下面总结一下:

  • 第一个大招 升级Android studio 2.0 并且使用最新版的gradle 2.0 使用Instant Run
  • 在你确保你的混淆没问题时候在debug模式下关闭所有混淆minifyEnabled false, shrinkResources false
  • 尽可能的让你的所有module的依赖库版本一致。
  • 在允许的情况下,在android studio的配置中,开启offline模式,在构建项目时候在命令后面加上--daemon --parallel --offline即可
  • 在添加依赖的时候尽量明确版本号,省去gradle查找最新版的时间,不要compile 'com.facebook.fresco:fresco:latest' 或compile 'com.facebook.fresco:fresco:1.+',
  • 开启守护线程并行编译,在gradle.properties中添加
    org.gradle.parallel=true
    org.gradle.daemon=true
    org.gradle.jvmargs=-Xms256m -Xmx1024m
  • 在gradle中def方法的时候尽量在debug情况下减少耗时操作或者不操作,比如:
    def getRevision() {
    if (!System.getenv('CI_BUILD')) {
    return 0
    }
    return ext.hash = 'git rev-parse --short HEAD'.execute().text.trim()
    }

写在最后

如果那里写的不对或者有更好的方式,欢迎指出批评,感恩。欢迎关注~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,397评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • Gradle对于很多开发者来说有一种既熟悉又陌生的感觉,他是离我们那么近,以至于我每天做项目都需要他,但是他又是离...
    阿_希爸阅读 9,566评论 10 199
  • 这几个月是要把生活所有的不顺都经历一遍么?突然所有不利的事都集中大爆发了。 无助,恐惧,心酸,委屈,所有的负面情绪...
    迷心儿阅读 355评论 4 2
  • #20160929每天一个关键词#努力需要学习 今天熊猫书院学的《精进——如何成为厉害的人》,书中有关“努力需要学...
    劲汶阅读 289评论 0 0