热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

你该知道的Gradle配置知识总结

这篇文章主要给大家介绍了关于Gradle配置的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友可以参考学习,下面随着小编来一起学习学习吧。

前言

本文主要介绍了关于Gradle配置的相关知识,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

参考链接:https://developer.android.com/studio/build/index.html

本片文章的内容全部参考自上面的链接,其中有些内容是直接翻译的,有些内容是结合自己的经验总结的,可能有理解错误的地方,非常希望大家能指正出来,在交流中进步。

Gradle 编译过程


编译流程图

上图展示了一个典型的 App 编译过程,主要分为以几步:

  • 编译器将源代码(包括依赖库)转化为 DEX 文件,编译资源文件(res 以及 assets 文件下的资源)。
  • APK Packager 整合所有的 DEX 文件和编译过的资源文件,并且对 APK 进行签名。
  • 签名文件必须使用 Debug 版或者 Release 版,使用 Debug Keystore 生成的 app 被用来测试和分析,使用 Release Keystore 生成的 app 可以进行发布供其他用户使用。
  • 在生成最终的 APK 之前,APK Packager 会使用 zipalign 工具优化整个 app ,以便 app 在使用的过程中更加节省内存。

自定义编译配置

Android Studio 的 gradle 插件方便我们在以下几个方面配置我们的编译选项:

Build Types - 编译类型

编译类型,包括我们最熟悉的 release 和 debug 两种类型,我们可以根据这两种类型定义出更多的类型。配置对应的 build.gradle 文件在 moudle 下,需要添加新的或者修改 Build Type ,只需要在 android{ ... }里面操作。

一个示例如下:

android {
 ...
 defaultConfig {...}
 buildTypes {
 release {
  //开启混淆
  minifyEnabled true
  //混淆规则文件
  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }

 debug {
  //apk的后缀
  applicationIdSuffix ".debug"
 }

 //debug的一个扩展
 jnidebug {
  // 复制debug的属性和签名配置
  initWith debug
  applicationIdSuffix ".jnidebug"
  //开启Jni调试
  jniDebuggable true
 }
 }
}

其中 initWith 可以方便我们继承其他的配置,只需要添加需要的部分。

Product Flavors - 构建不同版本

配置 apk 的版本信息,可以为每一个版本指定不同的 applicationId 和版本名称。关于 applicationId ,可以把它也理解为包名,不过和 Manifest 文件中的包名作用不同,它是用来给应用商店和设备区分不同的 app ,而 Manifest 中的 pakage 属性用来在源代码中引用 R 类和其他类。即同一份代码 applicationId 可以让它变成不同的 app 。

示例配置如下:

android {
 ...
 defaultConfig {...}
 buildTypes {...}
 productFlavors {
 demo {
  applicationId "com.example.myapp.demo"
  versionName "1.0-demo"
 }
 full {
  applicationId "com.example.myapp.full"
  versionName "1.0-full"
 }
 }
}

通过上面的配置之后,如果 buildTypes 里面配置了两个编译类型,假如是 debug 和 release ,将会产生四个 apk 文件,每一种 buildType 都会和每种 flavor 进行组合拼接,进而产生不同的变种版本(Build Variant),上面对应的四个不同的变种版本分别是:demoDebug、demoRelease、fullDebug、fullRelease。

Mutiple Manifest Files - 合并多个清单文件

配置多个 Manifest 文件。经常会在项目中依赖其他项目,这个时候就会有多个 Manifest 文件,那在编译的时候该如何处理呢?这个时候需要进行合并,而且还必须有一套相应的合并规则解决和避免合并冲突。对于不同的 Manifest 文件中同一个属性的不同值,在合并的时候还需要优先级来进行判断,用高优先级的去覆盖低优先级的。

关于优先级定义如下:

  • 最高优先级:buildType 的设置
  • 次高优先级:productFlavor 的设置
  • 中等优先级:在 src/main 目录下的 Manifest 文件
  • 最低优先级:各种依赖和第三方库的设置

合并规则:概括来说是这样:

  • 合并之前,先将每个 module 里面的 buildType 内容写到 Manifest 里面去,比如你在 buildType 里面的 minSdkVersion 和targetSdkVersion 以及 versionCode 和 VersionName 等等(此时合并后的 Manifest 文件可以在 app/intermediates/manifests/* 目录下查看)。
  • 对于同一个属性,当高优先级和低优先级都为非默认值时,如果可以匹配,那直接合并,不能匹配,就会产生冲突(这种是针对两个不同的 module 来说),下面会专门给出例子。
  • 不管高优先级还是低优先级,如果其中一个没有设置该属性或者设置为默认的属性值,而另外一个设置了非默认的属性值,则合并的结果就是非默认的属性值,在项目编译后,可以查看 Manifest 的合并记录,该文件目录为:app/intermediates/outputs/logs/manifest*.txt。

示例:现在给出一些例子说明上述规则,我的主 module 名为 app ,新建一个依赖的 module 叫 uisdk ,现在分别给出两个 module 的 build.gradle 文件:

app/build.gradle

apply plugin: 'com.android.application'

android {
 compileSdkVersion 24
 buildToolsVersion "24.0.0"

 defaultConfig {
 applicationId "com.example.rth.study"
 minSdkVersion 15
 targetSdkVersion 24
 versionCode 1
 versionName "1.0"
 }
 buildTypes {
 release {
  minifyEnabled false
  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }
 }
 productFlavors {
 demo {
  minSdkVersion 7
  applicationId "com.rth.app"
 }
 }
}

dependencies {
 compile fileTree(include: ['*.jar'], dir: 'libs')
 testCompile 'junit:junit:4.12'
 compile 'com.android.support:appcompat-v7:24.0.0'
 compile project(':uisdk')
}

uisdk/build.gradle

apply plugin: 'com.android.library'

android {
 compileSdkVersion 24
 buildToolsVersion "24.0.0"

 defaultConfig {
 minSdkVersion 8
 targetSdkVersion 24
 versionCode 1
 versionName "1.0"
 }
 buildTypes {
 release {
  minifyEnabled false
  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }
 }
}

dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 testCompile 'junit:junit:4.12'
 compile 'com.android.support:appcompat-v7:24.0.0'
}

在 app/build.gradle 里面,defaultConfig 的 minSdkVersion 为15,但我在变种版本(productFlavors 里的 demo)里设置的 minSdkVersion 为7,最终 app 的 Manifest 的 minSdkVersion 就为7,再看 uisdk 里面的 build.gradle ,minSdkVersion 为8,就是说 app 这个 module 和 uisdk 这个 module library 在同一个属性上使用了不同的非默认值,而且 library 的 Manifest 属于最低优先级,它设置的值又比优先级比它高的值还要高,就会出错,出错信息的描述也很清晰:

Error:Execution failed for task ':app:processDemoDebugManifest'.
Manifest merger failed : uses-sdk:minSdkVersion 7 cannot be smaller than version 8 declared in library 
...
Suggestion: use tools:overrideLibrary="com.example.uisdk" to force usage

根据错误信息,我们有两种方式解决这个问题:

  • 把 app 里面的值调高,或者把 uisdk 里面的值调低。
  • 就像上面建议的那样,使用 overrideLibrary 这个标签。该标签的作用在名字上已经体现出来了,就是直接覆盖 library 里面的设置,现在我们在 app/src/main/Manifest 里面加上这么一句:

就能编译通过了,这适用于比较特殊的情况,就是在依赖库里可能要适用一些新特性,这些特性在 app 的 minSdkVersion 下不能使用,而且 app 的 minSdkVersion 已经不能更改了。

标记选择器(Marker Selectors) :选择器的功能可以让一些属性在某些 libary 里面无效,比如就拿上面的例子来说,我想让 uisdk 只处理 ui 上的东西,不想让他具有网络访问的功能,那么我可以这么设置:

其中 tools:node 标签表示删除该权限,tools:selector 标签选择在哪个依赖库里执行 tools:node 表示的动作。

可以看出这些配置还是挺灵活的。

Configure dependencies - 配置依赖

这个应该是最熟悉的了,项目中经常要依赖第三方库,一个典型了例子如下:

android {...}
...
dependencies {
 //将本地 module library 编译到项目中
 compile project(":mylibrary")
 //编译远程依赖
 compile 'com.android.support:appcompat-v7:23.4.0'
 //编译本地 jar 包
 compile fileTree(dir: 'libs', include: ['*.jar'])
}

上面主要用到的方式是 compile ,gradle 支持6种编译方式:

  • compile:对所有 buildType 以及 flavors 进行编译并打包到 apk 。
  • provided:和 compile 相似,但只在编译时使用,几只参与编译,不打包到最终 apk 。
  • apk:只会打包到 apk 中,不参与编译,所以不能在项目代码中使用相应库中的方法。
  • test compile:相比于 compile ,仅仅针对单元测试的代码编译打包。
  • debug compile:仅针对 debug 模式编译打包。
  • release compile:仅针对 release 模式编译打包。

另外在进行 sdk 开发时,一般为了减小 sdk 体积,一些依赖库会用 provided 的方式,同时需要注意的是,对于远程依赖,compile 和 provided 的效果一样,都不会打包到 jar 包或者 arr 包中,但对于本地的 jar 包或者 arr 包的依赖,compile 和 provided 就有区别了。

Configure Sigining - 配置签名

在用 gradle 配置 release 版本的签名信息时,需要下面三个步骤:

  • 生成一个 keystore ,一个二进制文件保存一些私钥,这个必须好好保存。
  • 生成一个私钥,用于开发者或者公司与这个 app 建立对应关系。
  • 将生成的信息配置到 moudle 层的 build.gradle 里。

示例如下:

android {
...
defaultConfig {...}
signingConfigs {
 release {
  storeFile file("myreleasekey.keystore")
  storePassword "password"
  keyAlias "MyReleaseKey"
  keyPassword "password"
 }
}
buildTypes {
 release {
  ...
  signingConfig signingConfigs.release
 }
}
}

上面的配置中直接显示了一些敏感信息,比如各种密码,一种更加安全的方式是通过环境变量的方式获取:

storePassword System.getenv("KSTOREWD");
keyPassword System.getenv("KEYPWD");

或者如果使用命令行的方式编译,还可以让用户在命令行输入密码:

storePassword System.console().readLine("\nKeystore password: ")
keyPassword System.console().readLine("\nKey password: ")

暂时就总结到这么多了,再次说明,如果发现理解错的地方欢迎指正!!!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • Vue 2 中解决页面刷新和按钮跳转导致导航栏样式失效的问题
    本文介绍了如何通过配置路由的 meta 字段,确保 Vue 2 项目中的导航栏在页面刷新或内部按钮跳转时,始终保持正确的 active 样式。具体实现方法包括设置路由的 meta 属性,并在 HTML 模板中动态绑定类名。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • 本文总结了汇编语言中第五至第八章的关键知识点,涵盖间接寻址、指令格式、安全编程空间、逻辑运算指令及数据重复定义等内容。通过详细解析这些内容,帮助读者更好地理解和应用汇编语言的高级特性。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • QBlog开源博客系统:Page_Load生命周期与参数传递优化(第四部分)
    本教程将深入探讨QBlog开源博客系统的Page_Load生命周期,并介绍一种简洁的参数传递重构方法。通过视频演示和详细讲解,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文探讨了如何像程序员一样思考,强调了将复杂问题分解为更小模块的重要性,并讨论了如何通过妥善管理和复用已有代码来提高编程效率。 ... [详细]
  • python的交互模式怎么输出名文汉字[python常见问题]
    在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就进入到Python交互模式,它的提示符是>>>,此时我们可以使用print() ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
author-avatar
华东师大中北文艺部
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有