摘要:

每周一次,深入学习Android教程,TeachCourse今天带来的一篇关于Android Studio构建文件build.gradle的相关配置,重点学习几个方面的内容:1、applicationIdpackage属性值的关系,2、怎么配置安全的自定义签名,3、两种构建类型的区别,4、为什么要定制产品的偏好配置?,5、怎么才能加快DEX文件的生成速度,6、为什么要将一个apk拆分成多个?,7、关于引入依赖包你不知道的秘密。通过这篇文章的学习,你会对build.gradle文件有一个全新的认识,可以将TeachCourse文章提到的相关说明作为文档参考,方便在另一个module中引入,代码如下:

apply plugin: 'com.android.application'

android {
compileSdkVersion 24
buildToolsVersion "25.0.2"
/**
* 一、默认产品偏好配置
*/
defaultConfig {
...
}
/**
* 二、自定义签名配置
*/
signingConfigs {
config {
...
}
}
/**
* 三、构建类型,分为release和debug两种
*/
buildTypes {
release {
...
}
debug {
...
}
}
/**
* 四、自定义产品偏好配置,可以定义多个偏好产品
*/
productFlavors {
demo {
applicationId "cn.teahcourse.demo"
versionName "1.0-demo"
signingConfig signingConfigs.config
}
personal{
...
}
enterprise{
...
}
}
/**
*五、DEX文件构建属性配置(加快构建速度)
*/
dexOptions {
...
}
/**
* 六、将一个apk拆分成多个相关配置(拆分依据:屏幕密度、系统架构)
*/
splits {
density {
...
}
abi {
...
}
}
}
/**
* 七、引入依赖包的秘密
*/
dependencies {
...
}

一、applicationIdpackage属性值的关系

Android Studio开发工具创建module的时候,默认在build.gradle文件生成一个applicationId,对应的属性值是填写的package name,如下图:

这时候的applicationIdpackage属性值一样,刚开始接触Android Studio的时候,TeachCourse就听说applicationId表示真正的包名,而package不再被认为是包名,因为应用程序被打包成apk文件的时候,原先在manifest声明的packageapplicationId代替,也就是说如果你的build.gradle文件添加了applicationId属性值,无论两者是否一样,打包的apk文件的package属性值等于applicationId,如果不信,TeachCourse先来做过实验,将applicationId改为cn.teachcourse.demo,将package改为cn.teachcourse,然后将module打包成apk文件,使用反编译工具apktool.exe,如下图:

最后,打开AndroidManifest.xml文件,如下图:

结果证明:cn.teachcoursecn.teachcourse.demo代替

正是因为打包的apk文件的package的属性值被applicationId代替,也刚好说明为什么应用程序安装到手机后,手机上显示的是applicationId,而不是显示package,同时如果想在应用程序中接入第三方的API,填写的包名也必须是applicationId,常见的例子有:1.接入微信的支付功能,2.接入微信的分享功能,3.集成百度地图的定位功能

那么,AndroidManifest.xmlpackage到底有什么用呢?尽管,package在打包成apk的时候被applicationId代替,但是在构建的时候package有两方面的作用:

第一个作用:package指定的目录下,生成对应的R.java文件,上面的例子,构建的时候,生成R文件的目录,如下图:

app\build\generated\source\r\demo\debug\cn\teachcourse\R.java

第二个作用:package指定的目录下,引用对应的activityserver组件,如下图:

<!-- 定义Activity -->
<activity android:name=".MainActivity"/> <!-- 添加service组件 -->
<service android:name=".service.music.MusicService" />

在上面反编译的AndroidManifest.xml文件中,查看对应的组件目录,如下图:

也就是说,manifest指定的组件不管使用相对路径还是绝对路径,打包成apk文件后,都变成绝对路径,结构是:package.组件

需要特别注意的问题有:
第一个问题:代码中使用getPackageName()getPackageManager()对应的方法,返回的是applicationId属性值

第二问题:使用WebView基本存放于res/raw内的文件时,如果applicationId不等于package,提示ClassNotFoundException异常(可能是官方的bug),TeachCourse测试后找到两个解决的办法

  1. 尝试将res/raw/note.html文件移动到assets文件夹下,更换资源文件加载路径
mWebView.loadUrl("file:///android_asset/note.html");
  1. 保持applicationId属性值和package属性值一致
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.teahcourse.demo">
...
</manifest>

二、怎么配置安全的自定义签名

自定义签名指的是使用开发者导出的密钥库对apk文件进行签名,关于怎么生成自己的密钥库,不懂的同学,可以后面看一下TeachCourse另一篇文章《Android Studio运行时自带签名配置过程详解》,文章介绍了怎么配置Android Studio的运行时签名,这样做的目的:在接入一些需要自定义签名的API时,方便直接调试。

这里,介绍的是安全的自定义签名,即怎么才让别人看不到我们在build.gradle写入的密码(包括别名密码、密钥库密码),关于签名文件的重要性,TeachCourse在这里就不说了。

** 2.1 配置安全的自定义签名(1),步骤:**

  1. 在项目的根目录下创建一个名称为 keystore.properties 的文件。此文件应当包含您的签署信息,如下所示:
storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation

这里需要注意:keystore.propertiesstoreFile签名文件是相对module目录的路径,即将密钥库文件保存在module根目录下

  1. 在模块的 build.gradle 文件中,于 android {} 块的前面添加用于加载 keystore.properties 文件的代码。
...
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
...
}

注:您可以选择将 keystore.properties 文件存储在其他位置(例如,存储在模块文件夹中而不是项目的根文件夹中,或者如果您使用连续集成工具,也可以存储在构建服务器上)。在这种情况下,您应当修改上面的代码,以便使用实际 keystore.properties 文件的位置正确初始化 keystorePropertiesFile。

  1. 您可以使用语法 keystoreProperties['属性名称'] 引用存储在 keystoreProperties 中的属性。修改模块 build.gradle 文件的 signingConfigs 块,以便使用此语法引用存储在 keystoreProperties 中的签署信息。
android {
signingConfigs {
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
...
}
  1. 最后,我们就可以按照《Android Studio运行时自带签名配置过程详解》介绍的方式,将signingConfigs 块作用于release版本或debug版本

** 2.2 配置安全的自定义签名(2),步骤:**

  1. 第二种安全的自定义签名的方式是:将别名、别名密码、密钥密码以键值对的形式保存到当前电脑的环境变量中,然后通过变量名读取变量值,如下图:
android {
signingConfigs {
config {
keyAlias System.getenv("KEYALIAS")
keyPassword System.getenv("KEYPWD")
storeFile file('release.jks')
storePassword System.getenv("KSTOREPWD")
}
}
...
}
  1. KEYALIAS指的是环境变量的变量名,System.getenv("KEYALIAS")的读取变量名对应的变量值,如图:

  2. KEYPWD,按照上图的方式添加,如下图:

  3. KSTOREPWD以同样的方式,如下图:

需要特别注意的是:第二种自定义签名的方式,需要先检查Android Studio是否已配置了gradle工具的环境变量,打开Android Studio的terminal窗口,输入:gradle build,如下图:

如果,你的terminal窗口提示gradle不是内部命令,操作上述步骤之前,你得添加gradle工具的环境变量,Android Studio的gradle工具默认存放路径:

C:\Program Files\Android\Android Studio\gradle\gradle-3.2

配置gradle的环境变量,如下图:

三、两种构建类型的区别

每一个APP至少包含debugrelease两种构建类型,debug定义APP的调试版本,debug模式的几个特点:

  1. 支持断点调试和log信息打印,debuggable属性值为true
  2. 使用系统默认的密钥库签署apk文件
  3. 没有对apk文件进行代码和资源文件的优化(包括文件压缩、冗余文件删除)
  4. 没有对代码进行混淆

release定义APP的发布版本,创建项目module中的build.gradle文件,代码如下:

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

minifyEnable定义是否压缩代码,false表示不压缩;proguardFiles定义混淆代码的默认混淆规则,proguard-android.txt表示系统自带的混淆规则,proguard-rules.pro位于当前module根目录下,用于定义开发者自己的混淆规则。

release模式需要注意的几个特点:

  1. 不支持断点调试,debuggable默认为false
  2. 没有压缩类文件代码,minifyEnabled,默认为false
  3. 没有压缩资源文件,shrinkResources,默认为false
  4. 没有指定自定义签名文件,默认使用系统的密钥库签署apk

开发者在发布应用程序时,需要对release模式下的属性配置进行修改,优化apk文件,删除无用的代码和资源文件,混淆类文件和资源名称,自定义签名密钥库,代码如下:

release {
shrinkResources true
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}

总结:debugrelease模式,最大的区别默认属性配置不一样,两种模式支持的属性配置还包括,如下图:

记不住代码的同学,可以选中Build Types定义的模式,在可选项中改变对应属性配置,Android Studio运行时签名的实质将debug模式下的Signing Config设置为自定义密钥库文件,但是TeachCourse随着不断深入学习后发现,其实debug模式下配置Signing Config多此一举,而只要在release模式下配置Signing Config就够了,Android Studio的可以方便为我们生成两种模式下对应的apk文件,在Android Studio的左下角Build Variant中切换,如下图:

下面介绍了产品偏好配置后,回头再看看它们两者之间的关系。

四、为什么要定制产品的偏好配置?

什么是产品的偏好配置呢?比如说,TeachCourse想要开发一个应用程序,包含个人版本personal和企业版本enterprise,这两个版本之间在功能上有所区别,企业版自然比个人版功能要多一些,很明显就是要就一个Android项目打包成两个产品发布,它们之间的要求如下所示:

personal:版本号为1,最低SDK版本定义为11,最高SDK定义为24,版本名称后缀定义为-personal,applicationId后缀定义为-per,签名文件为自定义密钥库,代码如下:

personal {
versionCode 1
minSdkVersion 11
targetSdkVersion 24
versionNameSuffix '-personal'
applicationIdSuffix '-per'
signingConfig signingConfigs.config
}

enterprise:版本号为1000,最低SDK版本定义为11,最高SDK定义为24,版本名称后缀定义为-profession,applicationId后缀定义为-pro,签名文件为自定义密钥库代码如下:

enterprise {
versionCode 1000
minSdkVersion 11
targetSdkVersion 24
versionNameSuffix '-profession'
applicationIdSuffix 'full'
signingConfig signingConfigs.config
}

同时,TeachCourse定义第三个产品偏好配置为demo,用于上传GitHub,提供下载,代码如下:

demo {
applicationId "cn.teahcourse.demo"
versionName "1.0-demo"
signingConfig signingConfigs.config
}

一个Android项目,配置三个偏好的产品,即使修改了项目代码,也可以快速编译并打包三个apk文件,在Android Studio的左下角Build Variant中切换,如下图:

看上面的图片,你是不是发现了什么,突然间,三个偏好配置的产品,出现了6个变体,一个产品包含debugrelease两个版本,构建类型和偏好产品之间的关系是:一个偏好产品,肯定包含一个debug版本和一个release版本,可以生成变体的总数为flavors*2,选中需要调试的版本或选中需要发布的版本,Android Studio自动重新构建Android项目,就可以针对指定的产品进行调试或打包,非常的方便吧!

偏好产品相关配置,如下图:

defaultConfig也属于其中一种偏好产品,在我们没有定义自己的偏好产品时,我们构建和编译的就是默认的defaultConfig这个产品,也就只包含debugrelease两个变体。

五、怎么才能加快DEX文件的生成速度?

你有没有遇到Android Studio在每次构建的时候,都感觉花好长时间,TeachCourse就不止一次和同事抱怨说,Android Studio的编译速度还不如Eclipse快,蜗牛的速度真受不了呀?那该怎么办呢?

Android Studio提供dexOption区块以便于我们配置DEX构建属性,加快DEX文件的生成速度,代码如下:

  dexOptions {
preDexLibraries true
maxProcessCount 8
javaMaxHeapSize "2048m"
}
  • preDexLibraries声明是否预先编译依赖库,从而加快构建速度,实质是通过延时清除已生成的依赖库的构建文件,从而提高构建速度,根据使用情况合理配置。
  • maxProcessCount设置进程运行过程中可以使用的最大线程数。默认值为4。
  • javaMaxHeapSize设置DEX编译器的最大堆大小,堆或者栈都是用于存放暂时不用的垃圾,当内存不足时,垃圾回收机制会清除过时的缓存,堆大小决定垃圾清除的频率,影响着构建的速度

六、为什么要将一个apk拆分成多个?

根据TeachCourse以往的经验,一个apk文件可以支持不同屏幕密度和不同ABIs的手机设备,是因为我们进行了屏幕适配,做法:将市场主流的屏幕密度和ABIs集成到一个apk,造成的影响,如果你的应用程序本身就比较大,集成了不同屏幕密度和支持不同ABIs的代码,打包出来的apk文件变得更大,考虑到流量成本和用户体验,减少apk文件的大小其中一种方式将一个apk文件拆分成多个。

Gradle能够单独指定只包含一种屏幕密度或一种ABI代码和资源文件的apk,在build.gradle文件中使用到splits区块,splits区块内同时提供了按屏幕密度拆分density区块和按abi拆分abi区块,在一个build.gradle文件中可以同时指定两者或两者中的其中一者,下面分别介绍:

** 6.1 按屏幕密度拆分**

android {
...
splits { density {
enable true
exclude "xxxhdpi"
reset()
include "ldpi", "xxhdpi"
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}

上面是一个按屏幕密度拆分的一个例子,各个标签的含义是:

  • enable,是否基于定义的屏幕密度拆分成多个apk文件,默认为false
  • exclude,指定忽略拆分的屏幕密度列表,想要拆分成更多类型的apk文件,该关键字包含的屏幕密度列表应就可能少
  • reset(),重置默认拆分的屏幕密度依据,然后使用include标签定义拆分的屏幕密度依据
  • include,结合reset一起使用,定义拆分的屏幕密度依据
  • compatibleScreens,指定兼容的屏幕尺寸列表,区别于屏幕密度,该标签将会在清单文件manifest中通过<compatible-screens>注入到每一个apk文件中,即apk文件只能安装到<compatible-screens>指定尺寸的手机上

按照上面在build.gradle配置完成后,点击Build APK后,将在apk文件夹内生成多个apk文件,如下图:

为了验证是否在清单文件中注入指定屏幕尺寸,反编译其中一个apk文件,如下图:

** 6.2 按abi拆分**

android {
...
splits { abi { enable true
reset()
include "x86", "armeabi-v7a", "mips"
universalApk false
}
}
}

上面是一个按abi拆分的一个例子,除了universal标签不一样外,其他标签是一样的,使用方法一样,include标签定义拆分的abi依据,关于abi介绍,参考下面连接:

https://developer.android.google.cn/ndk/guides/abis.html

同样,点击Build APK后,将在apk文件夹内生成多个apk文件,如下图:

仔细观察生成的apk文件,会发现下面两个规律:

  • 第一个规律:apk总数=abi数量+density数量xabi数量
  • 第二个规律:apk filename=modulename-screendensityABI-buildvariant.apk

关于引入依赖包你不知道的秘密

不知道你会不会有和TeachCourse一样的想法,dependencies区块引入的jar包的名称长,基本无法记住,每一节又表示什么含义?Android Studio引入依赖项有几种方式?让我先看下面的这个例子:

dependencies {
compile project(":mylibrary")
compile files('libs/zxing.jar')
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.1.0'
compile group: 'com.android.support', name: 'appcompat-v7', version: '25.1.0'
}

可以看到Android Studio引入依赖项的方式分为上述四种,按顺序依次称为:1、模块依赖项,2、本地二进制依赖项,3、本地二进制依赖项,4、远程二进制依赖项,5、远程二进制依赖项

  • compile project(':mylibrary') 行声明了一个名为mylibrary的本地 Android 库模块作为依赖项,并要求构建系统在构建应用时编译并包含该本地模块。
  • compile files('libs/zxing.jar')compile fileTree(dir: 'libs', include: ['*.jar'])都称为本地依赖项,告诉构建系统在编译类路径和最终的应用软件包中包含 app/libs/ 目录内的指定或全部 JAR 文件。如果您有模块需要本地二进制依赖项,请将这些依赖项的 JAR 文件复制到项目内部的 中。
  • compile 'com.android.support:appcompat-v7:25.1.0'compile group: 'com.android.support', name: 'appcompat-v7', version: '25.1.0'都称为远程二进制依赖项,通过指定其 JCenter 坐标,针对 Android 支持库的 25.1.0 版本声明了一个依赖项。默认情况下,Android Studio 会将项目配置为使用顶级构建文件中的 JCenter 存储区。当您将项目与构建配置文件同步时,Gradle 会自动从 JCenter 中抽取依赖项。或者,您也可以通过使用 SDK 管理器下载和安装特定的依赖项。

第五种可以清楚看出每一节表示的含义,在Android Studio引入远程二进制依赖项,通常的做法是在Library Dependency窗口中搜索,搜索到最新版本的依赖项,如下图:

似乎无法搜索到低版本的依赖项,如果想要引入低版本的,那该怎么办呢?如果先前不了解远程二进制依赖项的含义,可能想不到修改version的办法,现在就变得很简单了。

总结:

本篇文章在阅读Android Studio用户指南多篇相关文档后完成的,想要更详细深入学习gradle指令的同学,可以继续研读Gradle官网文档,部分内容在TeachCourse开发的项目没有对应的需求,暂时也没有用到,是否使用更多应该根据项目实际情况而定,但可以作为用户开发的例子,先分享和收藏,以备不时之需。

参考资料:
https://developer.android.google.cn/studio/build/application-id.html
https://developer.android.google.cn/studio/build/optimize-your-build.html
https://developer.android.google.cn/studio/build/dependencies.html
https://developer.android.google.cn/studio/build/build-variants.html

版权声明:本文著作权归TeachCourse所有,未经许可禁止转载,谢谢支持!
转载请注明出处:http://teachcourse.cn/2385.html

Android开发之深入理解Android Studio构建文件build.gradle配置的更多相关文章

  1. Android开发之深入理解Android 7.0系统权限更改相关文档

    http://www.cnblogs.com/dazhao/p/6547811.html 摘要: Android 6.0之后的版本增加了运行时权限,应用程序在执行每个需要系统权限的功能时,需要添加权限 ...

  2. Android开发工具全面转向Android Studio(2)——AS project/module的CRUD

    本文有些地方可能需要衔接Android开发工具全面转向Android Studio(1)——准备开发环境,读起来效果会更好. 这个世界很奇妙,所有的东西离不开CRUD,即增删改查.即使人本身也遵循这个 ...

  3. Android开发工具全面转向Android Studio(3)——AS project/module的目录结构(与Eclipse对比)

    如果AS完全还没摸懂的,建议先看下Android开发工具全面转向Android Studio(2)——AS project/module的CRUD. 注:以下以Windows平台为标准,AS以目前最新 ...

  4. 配置cordova的android开发环境(无android studio)

    原文:配置cordova的android开发环境(无android studio) 趁元旦放假想试一下cordova,不想安装庞大的android studio,所以想最小化安装,居然花了一整天的时间 ...

  5. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  6. Android开发(八)——Android组件

    参考: [1] Android开发教程:理解Intent和Intent Filter.http://liuzhichao.com/p/506.html

  7. android开发如何获取res/raw和assets文件夹的路径

    ---恢复内容开始--- android开发如何获取res/raw和assets文件夹的路径,主要分为两种情况: 1.如果你只是拷贝动作,那么你只需要得到res/raw和assets文件输入流就可以, ...

  8. 收集整理Android开发所需的Android SDK、开发中用到的工具、Android开发教程、Android设计规范,免费的设计素材等。

    AndroidDevTools Android Dev Tools官网地址:www.androiddevtools.cn 收集整理Android开发所需的Android SDK.开发中用到的工具.An ...

  9. Eclipse搭建Android开发环境并运行Android项目

    Eclipse搭建Android开发环境并运行Android项目 (详细) 安装环境: window 10 64位 安装工具: JDK.Eclipse.SDK.ADT 安装步骤: 1.JAVA JDK ...

随机推荐

  1. Docker从入门到飞升:基础配置安装

    导读 Docker近几年非常火,因为它是容器虚拟化,更能够充分提高硬件资源的使用率.其实利用率高不算什么,它最大的优势是能给让运维人员或者开发人员快速部署和交付资源,大大提高了工作效率.几乎所有的大企 ...

  2. window.scroll原生滚动

    window.scroll({ top: , behavior: 'smooth' }) js原生已经支持模拟滚动的效果啦~~~

  3. 20190311 Windows上ZooKeeper伪集群的实现

    1. 复制并修改conf/zoo.cfg文件 以zoo1.cfg为例: dataDir=E:\\Develop\\zookeeper\\3.4.6\\zookeeper-3.4.6\\data1 da ...

  4. Linux发行版Debian操作系统破译密码

    Linux发行版Debian操作系统破译密码 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 其实玩过Linux的小伙伴,对破解服务器密码都应该有所了解,典型的两个代表,我觉得一个是 ...

  5. dubbo面试问题

    为什么用微服务: 为什么zookeeper能作为注册中心: 使用分布式碰到的bug, zookeeper有集群吗?怎么实现的: zookeeper宕机还能访问吗: 服务失效踢出zookeeper中临时 ...

  6. WebStrom直接启动VUE项目

    点Run即可启动

  7. Winform窗体设计工具源码

    源代码:QQ群616945527,博客资源

  8. TCP/IP详解 卷1 第十八章 TCP的建立与终止

    第十八章 TCP的建立与终止 tcpdump Tcpdump可以将网络中传送的数据报完截获下来进行分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.not等逻辑语句来帮助你去掉 ...

  9. JDBC preparedStatement分页和统计,批处理和事务

    一个类:DriverManager 四个接口:Connection.PreparedStatement .ResultSet.Statement 连接不上数据库出错的原因 1.数据库监听服务的配置不正 ...

  10. Sqoop异常:Please set $ACCUMULO_HOME to the root of your Accumulo installation.

    shell-init: 获取当前目录时出错: getcwd: 无法访问父目录: 没有那个文件或目录chdir: 获取当前目录时出错: getcwd: 无法访问父目录: 没有那个文件或目录chdir: ...