04.Gradle

转载Android面试题之Gradle配置篇

0. Gradle是什么

Gradle是一个自动化构建工具
兼容Maven等仓库
基于Groovy的特定领域语言来声明名目设置

1. GradleWraper

Gradle Wrapper是一个脚本文件
它会在没有安装Gradle的情况下为我们下载Gradle,之后我们就可以使用gradlew命令,像使用gradle一样来使用Gradle了
GradleWraper简化了gradle的安装部署

2. Gradle文件结构

settings.gradle:整个Project的配置文件,可以设置包含哪些module
build.gradle (Project的gradle文件):整个Project的配置文件
build.gradle(Module):Module的配置文件
gradle.properties:可以在 gradle.properties 文件中配置一些变量

3. Gradle命令

gradlew clean: 清除app目录下的build文件夹
gradlew check: 执行lint检查
gradlew assemble:打release和debug包
gradlew build : 执行check和assemble
gradlew assembleRelease/gradlew assembleDebug:打全部渠道的Release或者debug包

4. Gradle常见配置

指定仓库

    repositories {
        jcenter()
    }

指定依赖

    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }

设置脚本的运行环境

    buildscript{
    }

声明引用的插件

    apply plugin: 'com.android.application'

设置编译android项目的参数

    android {
        // 编译SDK的版本
        compileSdkVersion 22
        // build tools的版本
        buildToolsVersion "23.0.1"
     
        //aapt配置
        aaptOptions {
            //不用压缩的文件
            noCompress 'pak', 'dat', 'bin', 'notice'
            //打包时候要忽略的文件
            ignoreAssetsPattern "!.svn:!.git"
            //分包
            multiDexEnabled true
            //--extra-packages是为资源文件设置别名:意思是通过该应用包名+R,com.android.test1.R和com.android.test2.R都可以访问到资源
            additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
        }
     
        //默认配置
        defaultConfig {
            //应用的包名
            applicationId "com.example.heqiang.androiddemo"
            minSdkVersion 21
            targetSdkVersion 22
            versionCode 1
            versionName "1.0"
        }
     
        //编译配置
        compileOptions {
            // java版本
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
     
        //源文件目录设置
        sourceSets {
            main {
                 //jni lib的位置
                 jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
                 //定义多个资源文件夹,这种情况下,两个资源文件夹具有相同优先级,即如果一个资源在两个文件夹都声明了,合并会报错。
                 res.srcDirs = ['src/main/res', 'src/main/res2']
                 //指定多个源文件目录
                 java.srcDirs = ['src/main/java', 'src/main/aidl']
            }
        }
     
        //签名配置
        signingConfigs {
            debug {
                keyAlias 'androiddebugkey'
                keyPassword 'android'
                storeFile file('keystore/debug.keystore')
                storePassword 'android'
            }
        }
     
        buildTypes {
            //release版本配置
            release {
                debuggable false
                // 是否进行混淆
                minifyEnabled true
                //去除没有用到的资源文件,要求minifyEnabled为true才生效
                shrinkResources true
                // 混淆文件的位置
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
                signingConfig signingConfigs.debug
                //ndk的一些相关配置,也可以放到defaultConfig里面。
                //指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
                ndk {
                    abiFilter "armeabi"
                }
            }
            //debug版本配置
            debug {
                debuggable true
                // 是否进行混淆
                minifyEnabled false
                //去除没有用到的资源文件,要求minifyEnabled为true才生效
                shrinkResources true
                // 混淆文件的位置
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
                signingConfig signingConfigs.debug
                //ndk的一些相关配置,也可以放到defaultConfig里面。
                //指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
                ndk {
                    abiFilter "armeabi"
                }
            }
        }
        // lint配置 
        lintOptions {
          //移除lint检查的error
          abortOnError false
          //禁止掉某些lint检查
          disable 'NewApi'
        }
    }  

android中还可以有以下配置: productFlavors{ } 产品风格配置,ProductFlavor类型;testOptions{ } 测试配置,TestOptions类型; dexOptions{ } dex配置,DexOptions类型;packagingOptions{ } PackagingOptions类型;jacoco{ } JacocoExtension类型。 用于设定 jacoco版本;splits{ } Splits类型。

5. 几种依赖的区别

compile:我们最常用的依赖,编译时提供并打包进apk
provided:编译时提供但不打包进apk
在gradlew 3.0 中complie过期了,用implementation和api替代
api = compile
implemention:将该依赖隐藏在内部,而不对外部公开

6. 为什么会有两套repositories和dependencies

buildscript里面的那个是插件初始化环境用的,用于设定插件的下载仓库
android 中是工程依赖的一些模块和远程library的下载仓库的

7. 排除依赖传递,解决依赖冲突

exclude: 设置不编译指定的模块,排除指定模块的依赖
transitive:用于自动处理子依赖项,默认为true,gradle自动添加子依赖项。设置为false排除所有的传递依赖
force:强制设置某个模块的版本。

8. Gradle打包时的Proguard

通过在buildTypes中配置minifyEnable来开启和关闭proguard
通过proguardFiles 来配置混淆参数与keep的内容
混淆的作用:
压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute)。
优化(Optimize):对字节码进行优化,移除无用的指令。
混淆(Obfuscate):使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名。
预检(Preveirfy):在Java平台上对处理后的代码进行预检,确保加载的class文件是可执行的。

9. 依赖中的动态版本声明

    dependencies {
        //依赖最新的1.x版本
        compile "org.codehaus.cargo:cargo-ant:1.+"
    }

10. 多渠道打包1

在AndroidManifest.xml配置mete-data

    <meta-data
        android:name="UMENG_CHANNEL"
        android:value="Channel_ID" />

配置Flavors:

    android {  
        productFlavors {
            xiaomi {
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
            }
            _360 {
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
            }
            baidu {
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
            }
            wandoujia {
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
            }
        }  
    }

或者批量修改

    android {  
        productFlavors {
            xiaomi {}
            _360 {}
            baidu {}
            wandoujia {}
        }  
     
        productFlavors.all { 
            flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
        }
    }

在APP内读取 mete-data 配置确定渠道
然后用 ./gradlew assembleRelease 这条命令会把Product Flavor下的所有渠道的Release版本都打出来。

11. 多渠道打包2

因为以上方法需要多次编译,速度较慢,当渠道变多之后不适合多渠道打包
改进的方法1 : apk反编译后重写AndroidManifest文件,再重新编译签名
改进的方法2 : 如果在META-INF目录内添加空文件,可以不用重新签名应用。因此,通过为不同渠道的应用添加不同的空文件,可以唯一标识一个渠道

12. 多渠道打包3

在采用V2签名后,以上方法不再适用
考虑到V2签名的特点(对APK Signing Block是不进行验证的),我们向V2签名后的APK签名区块写入渠道号,实现多渠道打包

15. 其他用途

因为v1签名可以在不改变签名情况下二次打包,我们可以在gradle中对dex文件进行自己的签名

16. 哪些不做混淆

Android系统组件
JNI
反射
WebView的JS调用
内部类
Annottation
enum
范型
序列化
第三方

17. Gradle 生命周期

初始化阶段:会去读取根工程中setting.gradle中的include信息,决定有哪几个工程加入构建, 创建project实例,比如下面有三个工程: include ':app', ':lib1', ':lib2
配置阶段:,会去执行所有工程的build.gradle脚本,配置project对象,一个对象由多个任务组成, 此阶段也会去创建、配置task及相关信息。
运行阶段:根据gradle命令传递过来的task名称,执行相关依赖任务

18. 如何通过Gradle配置差异较大(20%差异)的多渠道包

通过配置productFlavors,将区别代码放置在对应的问价下,gradle会自动打出相应包

少年与爱永不老去,即便披荆斩棘,丢失怒马鲜衣。
posted @   契阔  阅读(112)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示