Android-Gradle阅读笔记

Gradle(2012) 是什么?

类似Ant(2000)和Maven(2004)概念的项目自动化建构工具。

Ant

Apache Ant是一个java库,主要用来构建Java程序。(C、C++、Java项目、Android项目)
主要功能:描述互相依赖, 提供了一个内置的编译,安装,测试和运行任务(target相当于gradle的task)。

Java项目的编译规则:
这里写图片描述

ADT
这里写图片描述
\ADT\adt-bundle-windows-x86_64-20140702\sdk\tools\ant
这里写图片描述
Build.xml
这里写图片描述

Maven

Maven与 Ant的区别(引用自http://hintcnuie.iteye.com/blog/122597

第一:ant脚本是可以直接运行在maven中的。maven和ant最大的差别就是在于maven的编译以及所有的脚本都有一个基础,就是POM(project object model)。这个模型定义了项目的方方面面,然后各式各样的脚本在这个模型上工作,而ant完全是自己定义,显然maven更胜一筹。
第二:Maven对所依赖的包有明确的定义,如使用哪个包,版本是多少,一目了然。而ant则通常是简单的inclde 所有的jar。导致的最终结果就是,你根本无法确定JBoss中的lib下的common-logging 是哪个版本的,唯一的方法就是打开 META-INF 目录下MANIFEST.MF。估计JBoss迟早会转向Maven的。
第三:Maven是基于中央仓库的编译,即把编译所需要的资源放在一个中央仓库里,如jar,tld,pom,等。当编译的时候,maven会自动在仓库中找到相应的包,如果本地仓库没有,则从设定好的远程仓库中下载到本地。这一切都是自动的,而ant需要自己定义了。这个好处导致的结果就是,用maven编译的项目在发布的时候只需要发布源码,小得很,而反之,ant的发布则要把所有的包一起发布,显然maven又胜了一筹。
第四:maven有大量的重用脚本可以利用,如生成网站,生成javadoc,sourcecode reference,等。而ant都需要自己去写。试试 maven site 的效果。
第五:maven目前不足的地方就是没有象ant那样成熟的GUI界面,不过mavengui正在努力中。目前使用maven最好的方法还是命令行,又快又方便。

Gradle

Gradle结合了前两者的优点,在此基础之上做了很多改进。
Gradle不用XML,它使用基于Groovy的专门的DSL, Gradle构建脚本变得比用Ant和Maven写的要简洁清晰,功能更强大,可以直接调用javase代码。

ANT、Gradle都可以单独安装,ANT通过命令行+build.xml运行,Gradle通过命令行+build.gradle运行

Gradle Wrapper

Wrapper,是Gradle的下载器,便于在团队开发过程中统一Gradle构建的版本,这样大家都可以使用统一的Gradle版本进行构建,避免因为版本不同带来不必要的问题。
这里写图片描述

Gradle日志

日志级别

级别用于
ERROR错误消息
QUIET重要消息
WARNING警告消息
LIFECYCLE进度消息
INFO信息消息
DEBUG调试信息
Gradle命令行
操作命令
帮助gradle –? 或者 gradle –h
查看所有可执行的Tasksgradle tasks
查看每个Task描述信息gradle help –task : xxmodule:xxxxtask
强制刷新依赖(版本库的version与snapshot版本变动后需要手动刷新)gradle –refresh-dependencies assemble

补充:SNAPSHOT
Maven中的SNAPSHOT版本(快照版本)
快照版本和正式版本的主要区别在于,本地获取这些依赖的机制有所不同。依赖正式版本,构建的会先在本次仓库中查找是否已经有了这个依赖库,如果没有的话才会去远程仓库中去拉取,不会拉取修改过已存在的同版本库。
.
开发的时候,需要SNAPSHOT版本(快照版本),在构建时去查看是否有同版本修改过的最新包,有则下载。在配置Maven的Repository可以配置查找的频率,频率共有四种,分别是always、daily、interval、never。
在Gradle,可以设置本地缓存的更新策略。
// check for updates every build
resolutionStrategy.cacheChangingModulesFor 0,’seconds’

Task

Groovy闭包≈Action

Groovy中的闭包(Closures)

学点Groovy来理解build.gradle代码

Gradle开发快速入门——DSL语法原理与常用API介绍

AndroidConfig 接口里声明 标签 android{}的配置

Groovy是基于JVM虚拟机的一种动态语言,语法与Java相似,完全兼容Java,增加了动态类型和灵活特性(支持闭包、支持DSL)。

闭包、FP函数式编程、lambda表达式

闭包是Groovy的一个非常重要的特性,可以说它是DSL的基础。

闭包(Closure)

维基百科:
1)闭包是引用了自由变量的函数。
2)由函数与其相关的引用环境组合而成的实体。

《JS中的闭包理解》:https://zhuanlan.zhihu.com/p/22486908?refer=study-fe

「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。
这里写图片描述

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。

闭包的作用

闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。

Groovy中的闭包(Closures):

闭包在groovy中是一个处于代码上下文中的开放的,匿名代码块。它可以访问到其外部的变量或方法。
这里写图片描述

闭包也是对象

闭包在groovy中是groovy.lang.Closure类的实例,这使得闭包可以赋值给变量或字段。

Groovy中的委托策略(略)

lambda表达式

——java1.8支持了lambda表达式

lambda表达式与闭包的关系:
lambda表达式大量用到了闭包和函数回调
lambda表达式说到底只是一个函数表达式的表现形式而已
准确的说lambda表达式与闭包没有直接的联系
如果支持函数表达式而不支持闭包,相当于买椟还珠
函数编程
函数风格的编程特点:
1.第一等公民是函数
2.带有闭包的Lambdas/Anonymous函数
3.不变性,大部分无态处理,没有状态和变量
4.高并发
5.无副作用的调用
6.通过tail call实现递归的性能优化。
7.模式匹配(Haskell, Erlang)
8.懒赋值(Miranda, Haskell)
9.Homoiconicity(类似LISP)

SQL是非常类似FP,它能渗透到业务中,它使用一致的数据结构(数据表结构Schema),一些基本函数能组合成很多查询语句,它是declarative声明式的, 也就是说,写出的SQL是告诉数据库我需要什么,数据库就为你返回,而不必指定数据库如何具体去查询。

Haskell 是纯函数式编程语言,研究函数式编程必修之路

Gradle groovy解读

Gradle Android 配置集锦

android {

//    SourceSet——源代码集合——源集
    sourceSets{
        release{
            // java 指定代码文件
            // res 指定资源文件
//            java.srcDirs = xxxx
//            res.srcDirs = yyyy
        }
        debug{

        }
    }

    compileSdkVersion 23 // 配置SDK的API Level,对应的是Android 6.0 SDK
    buildToolsVersion '23.0.3' //Android构建工具的版本(是一个工具包,包括appt、dex等工具)
    // defaultConfig是默认配置,它是一个ProductFlavor。ProductFlavor允许我们根据不同的情况同时生成多个不同的APK包。
    defaultConfig{
//        applicationId "com.tongcheng.android"  包名
//        minSdkVersion rootProject.ext.minSdkVersion  App最低支持的Android操作系统版本
//        targetSdkVersion rootProject.ext.targetSdkVersion
//        versionCode Integer.valueOf(appVersionCode)  App内部版本号,用于版本的升级AA.BB.CC(BB为版本迭代,CC为bug修复版本)
//        versionName appVersionName  App版本名称
//        multiDexEnabled true  配置BuildType是否启用自动拆分多个Dex的功能。解决65535问题
        // 如果启动期间需要的任何类未在主 DEX 文件中提供,那么您的应用将崩溃并出现错误 java.lang.NoClassDefFoundError。
        // 如果类在 multiDexKeepFile 或 multiDexKeepProguard 文件中匹配,则该类会添加至主 DEX 文件。
//        multiDexKeepProguard file("keep_in_main_dex.txt")
//        resConfigs "zh-rCN" 只有中文资源
//        ndk{
//            abiFilters "armeabi"
//        }
//        signingConfig  配置签名信息,对生成的App签名
//        proguardFile 配置App ProGuard混淆所使用的ProGuard配置文件。

    }

    // buildTypes是一个NamedDomainObjectContainer类型,是一个域对象(与SourceSet一样)。
    buildTypes{
        release{
            // 配置App ProGuard混淆所使用的ProGuard配置文件。
//            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard-im.pro', 'rn-proguard-rules.pro'
//            proguardFiles:同事配置多个混淆文件
//            debuggable false 是否生成一个可供调试的apk
//            jniDebuggable false 类上
//            minifyEnabled true 是否启用Proguard混淆
//            Android SDK提供了两个Proguard配置文件,proguard-android.txt和proguard-android-optimize.txt,一个是没有优化的,另一个是优化的。

//            构建时,打包前,会检测所有资源,如果没有被引用,这些资源就不会被打包到apk包中,不管自己的还是第三方的都会被处理
//            shrinkResources true 是否自动清理未使用的资源,默认为false
//            zipAlignEnabled true  zipalign优化:是一个整理优化APK文件的工具,客提高系统和应用的运行效率,更快地读写apk中的资源,降低内存的使用。

//            修改生成的apk文件名
//            applicationVariants.all { variant ->
//                variant.outputs.each { output ->
//                    def outputFile = output.outputFile
//                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
//                        // 输出apk名称为AppName_v1.0_2015-01-15_wandoujia.apk
//                        def apkFile = "AppName_v${defaultConfig.versionName}_${buildTime()}" +
//                                "_${variant.productFlavors[0].name}.apk"
//                        output.outputFile = new File(outputFile.parent, apkFile)
//                    }
//                }
//            }
        }
        debug{
//            Debug模式的签名使用的就是SDK自动生成的debug证书(.andriod/debug.keystore)

        }
    }

//    Android Gradle任务
//    assemble、check、build、connectedCheck、deviceCheck、lint、install、uninstall、gigningReport、androidDependencies等任

    signingConfigs {
        key_config {
//            keyAlias '17ukeystore'
//            keyPassword '17ukeystore'
//            storeFile file('/Users/android/share_root/etongAndroid.keystore')
//            storePassword '17ukeystore'
//            v2SigningEnabled false
        }
        debug {
            storeFile file('debug.keystore')
        }
    }

    flavorDimensions 'channel','pay'
    productFlavors{
        google{
//            动态配置AndroidManifest文件
//            在构建过程中,动态修改AndroidManifest文件中的内容(友盟统计等)
//            可以使用manifestPlaceholder、Manifest占位符
            manifestPlaceholders.put("UMENG_CHANNEL","google")
//            buildConfigField 'String','WEB_URL','"http://www.google.com"'// 自定义BuildConfig属性
//            resValue 'string','channel_tips','google渠道欢迎你' 动态添加自定义的资源

            dimension 'channel'

        }
        baidu{
            manifestPlaceholders.put("UMENG_CHANNEL","baidu")

            dimension 'channel'
        }

        free{
            dimension 'pay'
        }

        paid{
            dimension 'pay'
        }
        // 构建产物variant = ProductFlavor x BuildType
        // ProductFlavor = 以dimension为分组的乘积
        // variant = {  FreeGoogleRelease FreeGoogleDebug FreeBaiduRelease FreeBaiduDebug PaidGoogleRlease PaidGoogleDebug PaidBaiduRlease PaidBaiduDebug }
    }

    dexOptions {
//        jumboMode true 解决65535问题
//        javaMaxHeapSize "3072M" 配置最大堆内存
//        preDexLibraries属性,是否预执行dex Libraries库工程,开启后会大大提高增量构建的速度,不过可能会影响clean构建的速度,默认为true,如需要使用dx的—multi-dex选项生成多个dex,导致和库工程有冲突的时候,需要将该选项设置为false
//        threadCount 2  用来配置Gradle运行dx命令时使用的线程数量,适当的线程数量可以提高dx效率
//        incremental 配置是否启用dx的增量模式(或许有时候不工作)

    }

}


def buildTime() {
    def date = new Date()
    def formattedDate = date.format('yyyy-MM-dd', TimeZone.getTimeZone("UTC"))
    return formattedDate
}

使用Gradle配置进行模块化开发

以下所有内容为笔记——均可忽略

Gradle基础:

xxx作用
Settings文件主要是为了配置子工程。
Build文件(每个Project都会有一个Build文件)配置版本,接入插件,依赖库,依赖的Maven中心库
Task是一个操作,一个原子性的操作,比如打个jar包,复制一份文件,编译一次Java代码,上传一个jar到Maven中心库等,和Ant里的Target,Maven中的goal是一样的。(所谓task其实是project一个属性Project.hasProperty(‘xxxTask’) 为 true)
任务依赖dependsOn: xxxxTask

自定义属性
Project和Task以及SourceSet都可以添加额外的自定义属性,通过应用所属对应的ext属性即可实现。
添加之后可以通过ext属性对自定义属性读取和设置。

ext.age = 19
ext{
    phone = 123423
    address = ‘xxx’
}

自定义属性作用域广,可以跨Project,跨Task访问这些自定义属性。

脚本即代码,代码也是脚本
Gradle文件中写脚本,但是写的都是代码,可以即刻使用Groovy、Java以及Gradle的任何语法和API。可以定义Class、内部类、导包、定义方法、常量、接口、枚举等。

Gradle任务

多种方法访问任务
一:

task exTask1
exTask1.doLast{
    println ‘exTask1.doLast’
}

二:

task exTask2
tasks[‘exTask2’].doLast{
    println ‘exTask2.doLast’
}

tasks[‘exTask2’] 其实就是调用 tasks.getByName(‘exTask2’) 源码是调用 findByName(String name) 实现的
也可以通过路径进行访问:
findByPath(‘:example:exTask2’)
getByPath(‘:example:exTask2’)
get如果找不到会抛出UnknownTaskException异常,而find在找不到该任务的时候会返回null

任务的分组和描述

在创建任务的时候,尽量进行分组和描述,便于对任务进行归类整理,也便于阅读:
def Task myTask = task exTask3
myTask.group = BasePlugin.BUILD_GROUP
myTask.description = ‘这是一个构建的引导任务’

可以通过gradle tasks查看任务的分类描述

<<操作符
“<<” 操作符在Gradle的Task上是doLast方法的短标记形式,也就是说”<<”可以代替doLast

任务的执行分析
当我们执行Task的时候,其实就是执行其拥有的actions列表,这个列表保存在Task对象实力中的actions成员变量中,其类型是一个List
doFirst其实是add在第一个位置,doLast添加在最后一个位置

任务顺序
shouldRunAfter和mustRunAfter可以控制任务应该或者一定在某个任务之后执行。
例如:先执行单元测试,才能进行打包

任务的启用和禁用
Task中有个enabled属性,用于启用和禁用任务,默认是true,表启用;设置为false则禁止改任务执行,输出会提示该任务被跳过。

任务的onlyif断言
断言就是一个条件表达式。Task有个onlyIf方法,接受闭包作为参数,如果返回true则该任务执行,否则跳过。
用途:比如控制哪些情况下打什么包,什么时候执行单元测试,什么情况下执行单元测试的时候不执行网络测试等。
Example:
这里写图片描述

任务规则

当执行、依赖一个不存在的任务时,Gradle会执行失败。可以使用规则对其进行改进,当执行、依赖不存在的任务时,不会执行失败,而是打印提示信息,提示改任务不存在:
这里写图片描述

Gradle插件

Gradle本身提供了基本的概念和整体核心的框架,其他用于描述真实使用场景逻辑的都以插件扩展的方式来实现,比如构建Java应用,就是通过Java插件来实现的。

插件的作用:个人理解就是编译过程中,能用程序代码做的任何事情(代码生成、库拉取、编译修改、代码目录指定、扩展属性等等)

应用插件

二进制插件:就是实现了org.gralde.api.Plugin接口的插件
apply plugin:’java’
上面语句把Java插件应用到我们的项目中了,其中’java’是Java插件的plugin id,他是唯一的。

也可以:
apply plugin:org.gradle.api.plugins.JavaPlugin
也可以:
apply plugin:JavaPlugin
二进制插件一半都是被打爆在一个jar里独立发布的。我们自定义的插件,发布的时候制定plugin id最好是一个全限定名称,就像包名,避免重复。

脚本插件
build.gradle

apply from:’version.gradle’
其实就是把脚本加载进来,和二进制插件不同的使用from关键字,后面紧跟一个脚本文件,可以是本地的,也可以是网络的,如果是网络上的话要使用HTTP UR。

应用第三方发布的插件
第三方发布的jar的二进制插件,应用的时候,必须要现在buildscript{}里面配置classpath才能使用。
比如Andriod Gradle插件,就属于Andrid发布的第三方插件,如果要使用就要进行配置:
这里写图片描述

buildScript{}块是一个在构建项目前,为项目进行前期准备和初始化相关配置以来的地方,配置好所需的以来,就可以应用插件了:
apply plugin:’com.android.application’

使用plugins DSL应用插件
Gradle2.1以上版本才可以用,如果该插件已经被托管在https://plugins.gradle.org/网站上,我们就不用在buidscript里配置classpath以来了,直接使用plugins就可以应用插件:
这里写图片描述

更多好用的插件:

https://plugins.gradle.org/
Github

自定义插件

脚本插件

这里写图片描述

Groovy工程插件(二进制插件)

这里写图片描述

Gradle插件基础

sourceSets源码目录

第三方依赖:
仓库配置:
Repositories{
mavenCentral()
}
库依赖
项目依赖
Jar依赖

如何构建Java项目

build任务:编译源码,处理资源文件等等
clean任务:删除build目录以及其他构建生成的文件。
assemble任务:不会执行单元测试,只会编译和打包
check任务:只会执行单元测试,有时候还会做一些质量检查

源码集合SourceSet概念
SourceSet——源代码集合——源集
有了源集,我们能针对不同的业务和应用进行源代码分组

发布构建
将代码发布到库中
这里写图片描述

Andriod Gradle插件

Android其实就是Gradle的一个第三方插件,由Google的Android团队开发的。

Andriod Gradle插件分类
App插件id:com.android.applicaton
Library插件id:com.android.library
Test插件id: com.android.test

Android Gradle插件
Android Gradle插件是第三方插件,托管在Jcenter上,应用之前,需要先配置classpath
这里写图片描述

compileSdkVersion

compileSdkVersion 23 配置SDK的API Level,对应的是Android 6.0 SDK
这里写图片描述
方法的括号可以省略,分号可以省略,所以就是上面的写法。

buildToolsVersion
buildToolsVersion ’23.0.1’:Android构建工具的版本(是一个工具包,包括appt、dex等工具)

defaultConfig
defaultConfig是默认配置,它是一个ProductFlavor。ProductFlavor允许我们根据不同的情况同时生成多个不同的APK包。

buildTypes
buildTypes是一个NamedDomainObjectContainer类型,是一个域对象(与SourceSet一样)。
buildTypes里面有release、debug等,也可以新增N多自定义类型。

Android Gradle任务
assemble、check、build、connectedCheck、deviceCheck、lint、install、uninstall、gigningReport、androidDependencies等任务
这里写图片描述

从Eclipse迁移到Android Gradle工程
1. 直接使用Android Studio导入
2. Eclipse>Export>Generate Gradle Build Files(生成Setting和build脚本)>Android Studio>Import Project (这种方式保持了Eclipse原本的项目格式,只是重写了SourceSet)

自定义Android Gradle工程

defaultConfig 是一个ProductFlavor,如果ProductFlavor没有被特殊定的话,默认会使用defaultConfig{}块值指定的配置(包名、版本号、版本名称等)

applicationId:包名

minSdkVersion:App最低支持的Android操作系统版本

versionCode:App内部版本号,用于版本的升级AA.BB.CC(BB为版本迭代,CC为bug修复版本)

versionName:App版本名称

testApplicationId:用于配置测试App的包名,默认情况下是applicationId + “.test”,默认即可

testInstrumentationRunner:配置单元测试时使用的Runner,默认是android.testInstrumenttationTestRunner,如果要自定义Runner,修改即可。

signingConfig:配置签名信息,对生成的App签名

proguardFile:配置App ProGuard混淆所使用的ProGuard配置文件。

proguardFiles:同事配置多个混淆文件

配置签名信息
这里写图片描述

Debug模式的签名使用的就是SDK自动生成的debug证书(.andriod/debug.keystore)

构建的应用类型
这里写图片描述

applicationIdSuffix:用于配置基于默认applicationId的后缀

debuggable:是否生成一个可供调试的apk

jniDebuggable:类上

minifyEnable:是否启用Proguard混淆

multiDexEnabled:配置BuildType是否启用自动拆分多个Dex的功能。解决65535问题

shrinkResources:是否自动清理未使用的资源,默认为false

混淆:
Android SDK提供了两个Proguard配置文件,proguard-android.txt和proguard-android-optimize.txt,一个是没有优化的,另一个是优化的。

zipalign优化:是一个整理优化APK文件的工具,客提高系统和应用的运行效率,更快地读写apk中的资源,降低内存的使用。
zipAlignEnabled true 即可

Gradle高级定义
使用共享库:com.google.android.maps、android.test.runner等,是独立库,并不会被系统自动连接,需要独立进行生成使用。
这里写图片描述

如果手机系统没有需要的共享库,将不能安装该应用。

Android中,除了标准的SDK,还存在两种库:一种是add-ons库,位于add-ons目录下,大部分是第三方厂家或者公司开发的,为了让开发者使用,但是又不想暴露具体标准实现;第二类是optional可选库,位于platforms/android-xx/optional目录下,一般是为了兼容旧版本的API(org.apache.http.legacy 兼容 HttpClient)

add-ons附件库,Andriod Gradle会自动解析,自动添加到classpath里。
Optional可选库就不会了,使用需要:
这里写图片描述

批量修改生成的apk文件名

applicationVariants(仅仅适用于Android应用Gradle插件)、libraryVariants(仅适用于Andriod库Gradle插件)、testVariants(以上两种Gradle插件都使用)
这三个元素直译过来意思是变体,通俗地讲他们就是Android构建的产物。

触发这3种集合都会触发创建所有任务。
这里写图片描述

动态生成版本信息

版本:major.minor.path,第一个是主版本号,第二个是副版本号,第三个是补丁号

分模块:
这里写图片描述
这里写图片描述

从git的tag中获取
tag的名字一般就是版本名称,可以动态获取tag名称作为应用的名称。
Git命令: git describe –abbrev=0 –tags
使用Gradle的exec,Project对象里的exec方法
这里写图片描述

git tag动态获取版本名称
这里写图片描述
这里写图片描述

从属性文件中动态获取和递增
使用Properties属性,gradle进行读写。

隐藏签名文件信息
签名信息存放到服务器。

自动打包服务器代码:
这里写图片描述
如果是Jenkins,只需要在Jenkins里配置即可。
开发者直接使用debug签名即可
这里写图片描述

如果有时候需要使用正式发布的签名打正式包,比如Jenkins,给每个开发者开放一个账号,他们自己新建个Job就可以打正式的包了,打包之后可以在生成的构建里下载。

动态配置AndroidManifest文件
在构建过程中,动态修改AndroidManifest文件中的内容(友盟统计等)
可以使用manifestPlaceholder、Manifest占位符
ManifestPlaceholders是ProductFlavor的一个属性
这里写图片描述
这里写图片描述

还可以直接:
这里写图片描述
这里写图片描述

还可以使用占位符动态修改动态配置meta信息,比如ContentProvider的auth授权。

自定义BuildConfig
这里写图片描述

注意:值是用单引号括起来的,value的值是什么就写什么,要原封不动的放在单引号里。

动态添加自定义的资源
资源还可以在Gradle中定义:
实现这一功能的是resValue方法,他在BuildType和ProductFlavor这两个对象中都存在,也就是说我们可以分别针对不同渠道,或者不同的构建类型来自定义其特有的资源。
这里写图片描述

生成的资源位置,以Baidu为例,debug模式下,在build/generated/res/resValues/baidu/debug/values/generated.xml这个文件中。
这里写图片描述

个人总结:包括图片一样可以做,自定义图片名称即可,可以通过名称找图片。

Java编译选项
可以对Java源文件的编码、源文件使用的JDK版本进行调优修改。(比如编码UTF-8,配置Java源码的级别为1.6),Gradle提供了便捷入口:
这里写图片描述
这里写图片描述

Adb操作选项配置
这里写图片描述
这里写图片描述

这里写图片描述

DEX选项配置
对于生成DEX文件的过程和处理,Android Gradle插件会调用SDk中的dx命令进行处理。
有时会遇到内存不足的情况:java.lang.OutOfMemoryError:GC overhead limit exceeded
默认情况给dx分配的内存是一个G,1024MB
这里写图片描述

javaMaxHeapSize 配置最大堆内存
jumboMode属性,解决65535问题
preDexLibraries属性,是否预执行dex Libraries库工程,开启后会大大提高增量构建的速度,不过可能会影响clean构建的速度,默认为true,如需要使用dx的—multi-dex选项生成多个dex,导致和库工程有冲突的时候,需要将该选项设置为false
threadCount属性,用来配置Gradle运行dx命令时使用的线程数量,适当的线程数量可以提高dx效率
incremental 配置是否启用dx的增量模式(或许有时候不工作)
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

突破65535方法限制

Facebook给的第一个方案是:打补丁
后来官方给的方案是Multidex,Android 5.0之后的ART运行方式,天然支持App有多个DEX文件。ART在安装App的时候执行预编译,把多个DEX文件合并成一个oat文件执行。对于5.0之前的版本,虚拟机限制没个App只能有一个class.dex,要使用他们,需要使用Andriod提供的Multidex库:
Andriod Build Tools 和 Android Support Repository 到21.1,这是支持Multidex功能的最低支持版本。
要在我们的项目中使用Multidex,首先要修改Gradle build配置文件,启用Multidex,并同时配置Multidex需要的jar依赖:
这里写图片描述

开启了Multidex,会让我们的方法多于65535个的时候生成多个DEX文件,其名字为classes.dex,classes(…n).dex这样的格式。要想可运行,虚拟机需要把其他几个生成的classed记载进来,必须在App启程启动的入口控制,就是Application。直接使用MultiDexApplication或者继承它,或者重写attachBaseContext方法实现:
这里写图片描述

思考:
这里写图片描述
自动清理未使用的资源
Android Lint、Recource Shrinking(构建时,打包前,会检测所有资源,如果没有被引用,这些资源就不会被打包到apk包中,不管自己的还是第三方的都会被处理)

Resource Shrinking要集合Code Shrinking一起使用,就是ProGuard,也就是启用minifyEnabled。
这里写图片描述

自动清理未使用的资源可能会误删,因为我们再代码编写的时候,可能会使用反射引用资源文件,特别是第三方库会这么做,Gradle就区分不出来了,这种情况Gradle提供了keep方法来让我们配置哪些资源不被清理:res/raw/keep.xml
这里写图片描述

Keep.xml 有一个属性是tools:shrinkMode,用于配置自动清理资源的模式,默认是safe,是安全的,可以识别如下引用:
这里写图片描述
如果把清理模式改成strict就没办法识别了,这个资源会被认为没有被引用,而被清除掉。
这里写图片描述

resConfig使用非常广泛,不止于上面描述的语言,还包括Api Level、分辨率等。
上述姿势在打包的时候,不打包到apk中,实际并没有删除工程中的资源。

Android Gradle多项目构建
settings.gradle配置文件
这里写图片描述
这里写图片描述

库项目引用和配置
这里写图片描述

引用库项目其实是库项目发布出来的aar包,默认情况下,Android库项目发出来的包都是release版本的,当然可以通过配置来改变它,比如改成默认发布的,下面是debug版本:
这里写图片描述

还可以针对不同的flavor+buildtype配置:
这里写图片描述

同时发布多个版本的aar包以供不同项目引用:
这里写图片描述
引用方法:
这里写图片描述

库项目单独发布

搭建自己的Maven私服,推荐使用Nexus Repository Manger,版本选择2.x.x

发布Mavne:
这里写图片描述

快照版本SNAPSHOT:
比如配置成1.00-SNAPSHOT,这时候会发布到snapshot中心库,每次发布版本号不会变化,只会在版本号后按顺序号+1,如1.0.0-1、1.0.0-2、1.0.0-3等。这样的版本号,引用的时候版本号写成1.0.0-SNAPSHOT即可,Maven会帮我们下载最新(序列最大)的快照版本。这种方式适用于联调测试的时候,每次修复好测试的问题就发布一个快照版本,知道没有问题为止,然后再放出release版本,正式发布。

发布配置:
这里写图片描述

使用自己Maven服务器候中的库:
这里写图片描述
这里写图片描述

可以使用一个Maven库代替:Nexus Maven提供了一种group类型的repository,这种类型的repository可以同时集成好几个repository,把他们同意当成一个group来对外发布,比如Nexus内置的public group,就包含了release和snapshot,就可以改成:
这里写图片描述

Android Gradle多渠道构建

Android Gradle的Flavor完美解决多渠道问题。

Android Gradle中,定义了个Build Variant的概念,直译是构建变体,可以理解为构建的产物。一个Build Variant=Build Type + Product Flavor,Build Type就是我们构建的类型,比如Baidu、Google等,它们加起来就是baiduRelease、baiduDebug、googleRelease、googleDebug这几种组合的构建产出. Product Flavor是多渠道构建的基础.

Flurry多渠道和友盟多渠道构建
Flurry只需要配置不同的Flurry Key即可,可以自定义BildConfig:
这里写图片描述
使用: Flurry.init(this,FLURRY_KEY);

而友盟需要修改AndriodManifest.xml中的配置,通过配置meta-data标签来设置:
这里写图片描述
则我们可以使用manifestPlaceholders,来进行替换。

多渠道构建定制
Flavor:气味、味道,就是我们点菜说的口味。

applicationId:是ProductFlavor的属性,用于设置改渠道的包名

consumerProguardFiles:混淆文件配置
这里写图片描述
当发布库项目生成一个aar包的时候,使用consumerProguardFiles配置的混淆文件列表也会被打包到aar里一起发布,当应用项目引用这个aar包,并且启用混淆的时候,会自动使用aar包里的混淆文件对aar包代码进行混淆,这样就不用对该aar包进行混淆配置了。

ConsumerPoguardFiles方法是一直添加的,不会清空以前的混淆文件,而consumerProguardFiles属性配置的方式是每次都是新的混淆文件列表,以前配置的会先被清空。

proguardFiles:混淆使用的文件配置
signingConfig:签名配置

testApplicationId:单元测试有自己的专门apk测试包,testApplicationId是用来适配测试包的包名,使用方法与applicationId一样。
一般的testApplicatonId的值为App的包名+.test

testFunctionalTest和testHandleProfiling
testFunctionalTest表示是否为功能测试,testHandleProfiling表示是否启用分析功能。
他们主要用来控制测试包生成的AndroidManifest.xml,最终配置还要体现在AndroidManifest.xml文件中的instrumentation标签的配置上。

TestInstrumentationRunner、testInstrumentationRunnerArguments:测试相关(最终使用的都是adb shell am instrument这个命令),略

versionCode和versionName
渠道的版本号 和 版本名称

useJack
用于标记是否启用Jack和Jill这个全新的、高性能的编译器。
书上说目前还处于实验阶段,有些特性还不支持,比如注解、JDK8的特性等。
正式产品中还是不要使用。
这里写图片描述

dimension
针对不同渠道需要再细分给出的解决方案。
Dimension是productFlavor的一个属性,接受一个字符串,作为该productFlavor的维度。
需要现在flavorDimesions里面声明维度,才能在ProductFlavor中使用:
这里写图片描述
这里写图片描述
这里写图片描述

提高多渠道构建的效率
美团研究出了一个办法,利用了在apk的META-INF目录下添加文件不用重新签名的原理:
1. 利用Android Gradle打一个基本包(母包)
2. 然后基于该包复制一个,文件名要能区分出产品、打包时间、版本、渠道等
3. 然后对复制出来的apk文件进行修改,在其META-INF目录下新增空文件,但是空文件的文件名要有意义,必须包含能区分渠道的名字,如mtchannel_google
4. 重复步骤2、3生成我们所需的所有渠道包apk,可以使用Python脚本来做。

使用:在apk启动的时候,读取apk中的META-INF目录下的前缀为matchannel_文件,如果找到的话,把文件名取出来,然后就可以得到渠道标识了:
这里写图片描述
这里写图片描述
这里写图片描述

持续集成:
Jenkins
这里写图片描述
这里写图片描述

怎样更好地做持续集成
1. 需要一个统一的代码版本控制管理库(可以使用Git进行管理,企业内部,可以使用Gitlab来搭建Git代码管理平台,和Github是非常相似的)
2. 搭建类似于Jenkins的构建平台,Jenkins是把所有构建流程串起来的一个工具。
3. 单元测试、代码覆盖率,以及代码静态检查等平台工具,Android里我们可以使用jacoco作为代码覆盖率工具,单元测试使用Andriod自带的工具就可以,静态代码检查推荐Sonar(可以进行代码静态分析,还可以呈现代码覆盖率和单元测试报告)
4. 每天想代码库的主干提交代码,这样我们的代码修改才可以每天汇集到一起,进行验证。
5. 代码提交的时候,要出触发一次自动构建,这样才是持续的,才能早发现合并后的问题。
6. 发现问题要及时修改,每个参与的人都可以很快获取最近的修改后的代码。要做到这些需要每个人都清楚整个代码库的构建情况。
7. 每个开发者必须要自己现在本机测试后才能提交代码到主干,不能不测试直接提交。
8. 开发者必须每天要提交自己的代码,更新最新代码,要经常和最新的代码保持一致,避免长时间没有同步代码,造成不清楚其他开发者做了什么, 也避免了冲突。
9. 要保证每次构建都要通过,是100%通过
10. 要保证每个人构建的目标都是可以发布的产品,而不是一个测试版的甚至是半成品,这是我们构建的目标

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值