建议先阅读 关于AS中的Gradle
gradle编译过程
- 将源码转化为
DEX
文件编译资源文件 -
APK Packager
整合DEX
文件和资源文件 对apk进行签名 -
APK Packager
会使用zipalign
工具优化整个app
节省内存
自定义编译
Build Types
关于release和debug的配置就在此编译类型中进行
栗子:
android {
...
defaultConfig {...}
buildTypes {
release {
//开启混淆
minifyEnabled true
//混淆规则文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
//apk的后缀
applicationIdSuffix ".debug"
}
//debug的一个扩展
jnidebug {
// 复制debug的属性和签名配置 相当于继承了debug
initWith debug
applicationIdSuffix ".jnidebug"
//开启Jni调试
jniDebuggable true
}
}
}
注意initWith
的使用
Product Flavors
此编译类型负责构建不用版本:为每个版本指定不同的applicationid
和版本名称
同一套代码可以生成不同的app
applicationid
可以理解成包名 作用是给应用商店和不同设备区分不同的app 但是与Manifest
中作用不同 Manifest
中的作用是用来在源代码中引用R类和其他类
栗子:
android {
...
defaultConfig {...}
buildTypes {...}
productFlavors {
demo1 {
applicationId "com.example.myapp.demo1"
versionName "1.0-demo"
}
demo2 {
applicationId "com.example.myapp.demo2"
versionName "2.0-demo"
}
}
}
上述的配置会生成4个apk
每一种flavor都会对应生成 release
和 debug
版本
Mutiple Manifest Files
合并多个清单文件
项目中可能会存在多个清单文件 这个时候需要将他们进行合并 此时需要定义规则解决合并冲突
此时可能存在一种情况:
不同的Manifest
中同一属性可能存在不同值 合并的时候需要进行优先级对判断
优先级从高到低依次是:
buildType
productFlavor
- app下的
Manifest
文件 - 依赖的第三方的设置
合并规则:
将每个
module
里面的buildType
写入到Manifest
中 比如说minSdkVersion
targetSdkVersion
versionCode
VersionName
这些属性
合并后的Manifest
文件可以在app/intermediates/manifests/*
目录下查看同一属性 如果优先级从高到低都是非默认值并且不可以匹配 会产生冲突 此时有两种方式可以解决 具体见下面的栗子
无论高低优先级 如果其中一个设置了默认的属性值或者没设置 另外一个设置了非默认的属性值 则合并后的结果就是此非默认的属性值 项目编译后可以查看合并记录:
app/intermediates/outputs/logs/manifest*.txt
栗子:
主 module
: app
依赖的 module
: mysdk
app/build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.example.ckc.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.ckc.app"
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile project(':mysdk')
}
mysdk/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 中 minSdkVersion
属性的默认值定义的是15 但在变种中定义的是7 那么编译后app中的 Manifest
中对应的值就是7
mysdk中对应的默认值是8 由于mysdk的优先级比较低 所以此时就会产生冲突 解决的方案:
- 提高app中的值 或者降低mysdk的值 但是某种情况下属性值由于项目要求不能随意修改 此时就出现了第二种方案
-
overrideLibrary
标签:直接覆盖library中的设置 具体使用:
<uses-sdk tools:overrideLibrary="com.example.mysdk"/>
tools:overrideLibrary
也可以用在 application
标签上
Marker Selectors
标记选择器 让一些属性在某些 libary 上失效 比如我想让 mysdk 这个模组禁掉网络访问的权限 那么就可以这样设置:
<uses-permission android:name="android.permission.INTERNET"
tools:node="remove" //删除该权限
tools:selector="com.example.mysdk" //目标模组
/>
Configure dependencies
配置依赖
gradle
支持6种配置方式:
-
compile
:对所有buildType
以及flavors
进行编译并打包到 apk -
provided
:和compile
相似,但只在编译时使用,几只参与编译,不打包到最终 apk -
test compile
:仅仅针对单元测试的代码编译打包 -
debug compile
:仅针对debug
模式编译打包 -
release compile
:仅针对release
模式编译打包 -
provided
: 一些依赖库会用到 对于远程依赖provided
和compile
效果是一样的 都不会打包到jar
或者aar
中 但是本地依赖两者是有区别的:provided
只会在编译时起效果 不会打包到apk中 但是compile
会
Configure Sigining
配置签名
gradle
配置 release
签名需要三步:
- 生成一个
keyStore
这个保存私钥的一个二进制文件 - 生成一个私钥 建立开发者和公司的关系
- 将生成的信息配置到 主项目app的 build.gradle 中
栗子:
android {
...
defaultConfig {...}
signingConfigs {
release {
storeFile file("myreleasekey.keystore") //此文件一般放在release文件夹下
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: ")