Google推荐使用的Android Studio是采用Gradle来构建项目的。Gradle是用了一种基于Groovy的领域特定语言(DSL,Domain Specific Language)来声明项目设置。因此有必要稍微了解一些使用Gradle编译Android App的常见配置方式。
由于Android studio创建的项目中可以包含多个module,像compileSdkVersion就需要为每一个module中设置,实在是麻烦了,使用统一配置,就如同一个全局变量,修改定义的地方,所有使用的地方都生效了。
<1> 在项目的根目录下创建一个config.gradle(名字随意)文件
config.gradle里的数据根据项目需要进行设置。如:
ext {
android = [
compileSdkVersion: 26,
buildToolsVersion: '26.0.2',
minSdkVersion : 14,
targetSdkVersion : 26
]
dependencies = [
appcompatV7 : 'com.android.support:appcompat-v7:26.1.0',
design : 'com.android.support:design:26.1.0',
junit : 'junit:junit:4.12',
constraint : 'com.android.support.constraint:constraint-layout:1.0.2'
]
}
<2> 在工程的根目录下的build.gradle的顶部声明config.gradle文件,如:
apply from: "config.gradle"
<3> 在app或者其它module中使用全局参数,修改后的app的build.gradle 如下:
//定义两个变量
def configInfo = rootProject.ext.android
def libraryInfo = rootProject.ext.dependencies
android {
compileSdkVersion configInfo.compileSdkVersion
buildToolsVersion configInfo.buildToolsVersion
defaultConfig {
applicationId "com.test.demo.test"
minSdkVersion configInfo.minSdkVersion
targetSdkVersion configInfo.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "versionCode"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation libraryInfo.appcompatV7
implementation libraryInfo.constraint
implementation libraryInfo.design
implementation libraryInfo.junit
}
<1> 在gradle.properties配置:
signing_keyAlias=androidreleasekey
signing_keyPassWord=android
signging_storeFile=../release.keystore //签名文件的路径
signging_storePassword=123
<2> 在app或者其它module中使用签名
android {
compileSdkVersion configInfo.compileSdkVersion
buildToolsVersion configInfo.buildToolsVersion
defaultConfig {
applicationId "com.test.demo.test"
minSdkVersion configInfo.minSdkVersion
targetSdkVersion configInfo.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "versionCode"
}
//签名配置
signingConfigs {
releaseConfig {
keyAlias "${signing_keyAlias}"
keyPassword "${signing_keyPassWord}"
storeFile file(signging_storeFile)
storePassword "${signging_storePassword}"
}
}
buildTypes {
release {
minifyEnabled false
signingConfig signingConfigs.releaseConfig
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
举个列子:在调试代码的时候希望显示Log日志信息,但是当发布时不希望显示Log信息。可以通过配置buildTypes来达到在release版本中自动关闭Log的效果
<1> 首先在buildTypes中添加buildConfigField:
buildTypes {
release {
minifyEnabled false
buildConfigField "boolean", "IS_SHOW_LOG", NOT_SHOW_LOG
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
buildConfigField "boolean", "IS_SHOW_LOG", SHOW_LOG
}
}
buildConfigField 各参数含义:
String type 要创建的字段类型,如上面的boolean
String name 要创建的字段名,如上面的IS_SHOW_LOG
String value 创建此字段的值,如上面的NOT_SHOW_LOG(false)
配置的buildConfigField参数,编译后会在\app\build\generated\source\buildConfig文件夹下会自动生成对应版本对应module的BuildConfig.java文件,该文件可以在代码中直接使用。
<2> 在项目中打印log的类中使用,比如编写一个MyLogUtils.java类
public class MyLog {
public static int v(String tag, String msg) {
if (BuildConfig.IS_SHOW_LOG) {
return Log.v(tag, msg);
} else {
return -1;
}
}
}
productFlavors顾名思义,就是用来分别定义产品不同的特性,使用它可以用一套代码创建不同的产品。
设置productFlavors的方法就是在app中的build.gradle中加入productFlavors结构:
android{
......
productFlavors{
productA{
//这里定义产品A的特性
}
productB{
//这里定义产品B的特性
}
//更多产品 ...
}
......
}
productFlavors的应用场景
<1> 不同包名的apk
通过设置不同的applicationId就可以编译出不同包名的APK
productFlavors{
demo1{
applicationId "com.gavinandre.product.a"
versionName "version-a-1.0"
}
demo2{
applicationId "com.gavinandre.product.b"
versionName "version-b-1.0"
}
//更多产品 ...
}
<2> 不同渠道包的产品
由于国内引用市场较多,因此需要为不同市场打包相应的包,以友盟为例:
productFlavors{
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "c360"]
}
uc {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "uc"]
}
}
或者
productFlavors {
wandoujia {}
baidu {}
360 {}
uc {}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
<3> 不同依赖库的产品
productFlavors还支持自定义依赖,不同的apk只编译自己需要的依赖库,不需要编译对自己无用的依赖库
dependencies {
....
demo1Compile "com.android.support:appcompat-v7:25.1.1"
demo2Compile "com.android.support:support-v4:25.1.1"
}
使用productFlavors里定义的产品名+Compile关键字来替代compile关键字
<4> 不同代码和资源的产品
gradle中有一个sourceSet概念,不同APK可以设置不同的sourceSet,通常src/main目录是ide自动帮我们创建的文件夹,因此我们可以在src目录下创建demo1/demo2这样的目录,目录名需要和productFlavors中定义的产品名对应。这样src/demo1/java文件内可以放不同的代码,src/demo2/res文件夹内可以放不同的资源文件,同时也可以定义不同的AndroidManifest文件,比如申请不同的权限之类。
注意:默认的main文件夹里存在的文件在其他适配目录中不允许出现相同文件名的文件,如果差异化特别大可以将文件抽取出来单独放到各个差异包下,main文件下不创建差异文件。
./gradlew assembleDebug
编译并生成Debug包,包含productFlavors下所有定义的产品或渠道包
./gradlew assembleRelease
编译并生成Release包,包含productFlavors下所有定义的产品或渠道包
./gradlew assembleWandoujia
编译并生成Release和Debug包,仅生成productFlavors下定义的wandoujia渠道
./gradlew assembleWandoujiaRelease
编译并生成Release包,仅生成productFlavors下定义的wandoujia渠道
apk生成目录在rootProject/app/build/outputs/apk目录下