Gradle技巧

Max OX用户安装配置gradle:

假设您下载好的 Gradle 文件在 /Users/UFreedom/gradle 目录

  1. vim ~/.bash_profile
  2. 添加下面内容:export GRADLE_HOME = /Users/UFreedom/gradleexport export PATH=$PATH:$GRADLE_HOME/bin
  3. source ~/.brash_profile

签名
开发App时经常遇到Release版和Debug版共存问题,由于默认的签名不同,经常要卸载Debug版安装Release版,非常麻烦。
有两种方法可以避免这种情况:

  1. 使用同一个签名 ;
  2. 使用不同包名

方法1
android {
buildTypes {
debug {signingConfig signingConfigs.myConfig}
release {signingConfig signingConfigs.myConfig}
}
}

方法2

android {
   buildTypes {
       debug {packageNameSuffix ".debug"}
   }
}

引用 aar

要输出 aar 文件,必须将 Module 配置为 library,在 gradle 文件中如下:

  1. 输出 aar : apply plugin: 'com.android.library'
  2. 输出 apk :apply plugin: 'com.android.application'

一份 aar 文件其实就是一份 zip 包,和 jar 不同的是,它将一些资源文件、第三方库文件、so 文件等等都打包在内,而代码文件编译后压缩在在 classes.jar 中

如 aar的内容


Paste_Image.png

依赖方式1
导入方式,点击new -module

Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png

把这个文件夹当做一个项目来依赖了

依赖方式2

首先需要将 aar 文件放入引用 Module 的 libs 目录下,和一般的 jar 文件类似。然后在 gradle 配置文件中把 libs 目录加入依赖:

repositories {
flatDir {
dirs 'libs'
}

最后
compile(name: 'mylib-debug', ext: 'aar')

依赖即可关联完毕。构建一下工程,在 Module 的 build/intermediates/exploded-aar
目录下,可以看到有一些临时文件生成

aar里面可以直接引用到资源文件,string,drawable等等
且aar里面配置过的权限,直接引用后无需再在主工程里面配置了

buildTypes节点下使用buildConfigField。

下面是默认的buildTypes形式

buildTypes {
    release {
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.release
    }
}

但是这里其实默认还有一个debug type,只不过默认不显示,显示完整如下

buildTypes {
  release {
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.release
  }
  debug{
  }
}

默认的构建版本就这么两种,其实我们还可以构建新的版本

如:

android {
    buildTypes {
        staging {
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            buildConfigField "String", "API_URL","http://staging.example.com/api"
         }
    }
}

我们定义了一个staging版本,该版本定义了一个新的application id,这让其与debug和release版本的applicationID不同。假设你使用了默认的配置,那么applicationID将会是这样的:

  1. Debug: com.package
  2. Release: com.package
  3. Staging: com.package.staging

还可以继承版本,复写其中的属性

android {
       buildTypes {
           staging.initWith(buildTypes.debug) //继承debug构建版本
           staging {
               applicationIdSuffix ".staging"
               versionNameSuffix "-staging"
               debuggable = false
           } 
        }
}

当我们打包编译项目时,我们能不能这里就可以设置一些参数信息,直接可以作用于项目,从而在项目中,动态根据build.gradle中设置的信息,进行一些代码层面的逻辑处理,比如在debug type下正常输出日志信息,但是release type下,屏蔽日志输出。那么就可以通过buildConfigField

//注意,里面一定要应用签名
buildTypes { 
  release {
    buildConfigField "boolean", "LOG_DEBUG", "false"
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.release // ===========
  }
  debug{
    buildConfigField "boolean", "LOG_DEBUG", "true"  //=======
  }
}

因为我在项目中使用了开源库 Logger 进行日志输出,这个lib可以在Application的onCreate方法中进行开关设置,从而控制Log日志是否显示在console,所以最终使用如下:

if(BuildConfig.LOG_DEBUG){
    Logger.init("AppPlusLog").setLogLevel(LogLevel.FULL);
}else{
    Logger.init("AppPlusLog").setLogLevel(LogLevel.None);
}

gradle 的多模块构建

模块耦合

即你可以在一个模块中引用其他模块的属性,不建议你们这么做,完全可以在根目录下的build文件中定义这些属性。

Paste_Image.png

grade图形化让你运行模块间的任务变得简单,但是其没有为所有模块同时运行一个任务,所以如果你希望这么做,最快的方式是使用命令行(注意当前位置 ls下)。

声明模块
settings.gradle文件在根目录(不管主项目app是否依赖某个库,在项目下面都会被包含进来 )
include ':app', ':mylibrary', ':mylibrary2'

模块在某个文件夹下面

project
├─── setting.gradle
├─── build.grade
├─── app
│    └─── build.gradle
└─── libraries
     ├─── library1
     │    └─── build.gradle
     └─── library2
          └─── build.gradle

则需要这么定义

include ':app', ':libraries:library1', ':libraries:library2'

app 想依赖某个库

dependencies { compile project(':libraries:library1')}

gradle 构建生命周期

如果你有多个模块,settings.gradle文件定义了这些模块的位置。如果这些子目录包含了其自己的build.gradle文件,gradle将会运行它们,并且将他们合并到构建任务中。这就解释了为什么你需要申明在一个模块中申明的依赖是相对于根目录(指的是:libraries:library1这种)。

构建任务将所有的模块聚合在一起的时候.你可以配置所有的模块在根目录下的build.gradle。
这让你能够简单的浏览到整个项目的配置,但是这将会变得一团乱麻,特别是当你的模块需要不同的插件的时候。
另外一种方式是将每个模块的配置分隔开,这一策略保证了每个模块之间的互不干扰。这也让你跟踪构建的改变变得容易,
因为你不需要指出哪个改变导致了哪个模块出现错误等。

gradle的最大策略是混合。你可以在根目录下定义一个build文件去定义所有模块相同的熟悉,
然后在每个模块中的build文件去配置只属于该模块的参数。
Android studio遵循了该原则,其创建了一个build.gradle文件在根目录,
然后再每个模块文件夹下创建了另外一个build文件。

groovy语法

在Java中,打印一天String应该是这样的:

System.out.println("Hello, world!");
在Groovy中,你可以这么写:

println 'Hello, world!'
你应该主要到几点不同之处:

没有了System.out
没有了方括号
列结尾没有了;

这个例子同样使用了单引号,你可以使用双引号或者单引号,但是他们有不同的用法。双引号可以包含插入语句。插入是计算一个字符串包含placeholders的过程,并将placeholders的值替换,这些placeholder可以是变量甚至是方法。Placeholders必须包含一个方法或者变量,并且其被{}包围,且其前面有$修饰。如果其只有一个单一的变量,可以只需要$。下面是一些基本的用法:

def name = 'Andy'
def greeting = "Hello, $name!"
def name_size "Your name is ${name.size()} characters long."

greeting应该是“ Hello,Andy”,并且 name_size 为 Your name is 4 characters long.

string的插入可以让你更好的动态执行代码。比如

 def method = 'toString'
 new Date()."$method"()

这在Java中看起来很奇怪,但是这在groovy里是合法的。

Classes和members
Groovy里面创建类和Java类似,举个例子:

class MyGroovyClass {
       String greeting
       String getGreeting() {
           return 'Hello!'
        } 
}

注意到不论是类名还是成员变量都没有修饰符。其默认的修饰符是类和方法为public,成员变量为private

当你想使用MyGroovyClass,你可以这样实例化:

def instance = new MyGroovyClass()
instance.setGreeting 'Hello, Groovy!'
instance.getGreeting()   

当你想使用MyGroovyClass,你可以这样实例化:

def instance = new MyGroovyClass()
instance.setGreeting 'Hello, Groovy!'
instance.getGreeting()   

你可以利用def去创建变量,一旦你为你的类创建了实例,你就可以操作其成员变量了。get/set方法groovy默认为你添加 。你甚至可以覆写它。

如果你想直接使用一个成员变量,你可以这么干:

 println instance.getGreeting()
 println instance.greeting

而这二种方式都是可行的。

方法
和变量一样,你不必定义为你的方法定义返回类型。举个例子

java形式

public int square(int num) {
       return num * num;
} 
square(2);

groovy形式

 def square(def num) {
       num * num
 }
 square 4
 

没有了返回类型,没有了入参的定义。def代替了修饰符,方法体内没有了return关键字。然而我还是建议你使用return关键字。当你调用该方法时,你不需要括号和分号。

更简单的写法

def square = { num ->
       num * num
}
square 8

groovy闭包

在grade中,我们经常使用闭包,例如Android代码体和dependencies也是。

groovy集合

有二个重要的容器分别是lists和maps。
创建一个list很容易,我们不必初始化:
List list = [1, 2, 3, 4, 5]
为list迭代也很简单,你可以使用each方法:

list.each() { element ->
       println element
}

你甚至可以使得你的代码更加简洁,使用it:

list.each() {
       println it // it是闭包中的概念
}

map和list差不多:

Map pizzaPrices = [margherita:10, pepperoni:12]
如果你想取出map中的元素,可以使用get方法:

pizzaPrices.get('pepperoni')
pizzaPrices['pepperoni']

同样的groovy有更简单的方式:

pizzaPrices.pepperoni

Build Variant

android gradle 插件,允许对最终的包以多个维度进行组合。
BuildVariant = BuildType x ProductFlavor

product flavors用来为一个app创建不同版本。典型的例子是,一个app有付费和免费版

buildTypes {
    debug {
    }
    release {
    }
}

productFlavors {
    pro {
    }

    fre {
    }
}
lintOptions {
    abortOnError false
}


这两个维度的组合,会产生如下包:

proDebug
proRelease
freDebug
proRelease

当你添加了flavor dimensions,你就需要为每个flavor添加flavorDimension,否则会提示错误

多个flavors构建变体
在一些例子中,你可能需要创建一些product flavors的合并版本。举个例子,client A和client B可能都想要一个free和paid的版本,而他们又都是基于一样的代码,但是有不一样的颜色等。创建四个不同的flavors意味着有重复的配置。合并flavors最简单的做法可能是使用flavor dimensions,就像这样:

android {
       flavorDimensions "color", "price"
       productFlavors {
           red {
               flavorDimension "color"
           }
           blue {
               flavorDimension "color"
           }
           free {
               flavorDimension "price"
           }
           paid {
               flavorDimension "price"
           }
       }
}

即 2个Color(red blue)*2个Price(free paid)即 4种
redFree redPaid blueFree bluePaid

总的构建是2(Debug release)*4 = 8

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

推荐阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,733评论 6 342
  • 转载注明出处:http://www.jianshu.com/p/5255b100930e 0. 前言 完全由个人翻...
    王三的猫阿德阅读 2,501评论 0 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • Gradle配置最佳实践 本文会不定期更新,推荐watch下项目。如果喜欢请star,如果觉得有纰漏请提交issu...
    Solang阅读 1,621评论 0 4
  • 有多久了,没有再抬起头,静静地看一看明灯楼宇之上的那一弯弦月,那是我在夜里常常会做的事。当瞳孔里落满如同雾霭一...
    黑落白落阅读 260评论 0 2