1 前言
gradle 的配置不是很简单因为很多东西其实不知道有,一般都是要用的时候才查,才去配所以在此纪录下。其中包括:
多渠道打包,
改包名,
过滤不要的渠道或者环境,
测试环境和正式环境设置不同域名
2 基础概念
defaultConfig :默认配置
buildTypes : 编译类型,默认的就是debug,release
productFlavors:渠道
buildConfigField : 配置宏,可以在gradle里配置一个值让java 代码中访问到,其中 defaultConfig buildTypes productFlavors 都可以配置buildConfigField。
举例:
比如现在要做:
1. 多渠道打包( 豌豆荚,360手机助手,应用包,小米市场, 这些渠道对应 productFlavors。
2. 比如现在给电信做项目,福建版本,浙江版本,上海版本,北京版本,这些也是对应的 productFlavors。
3. 那么每种渠道对应常见的编译类型 调试包(debug ),发布包(release) 对应的就是buildTypes 的概念。当然我们也可以新建另一个名字的编译类型其实就是另一个名字的release而已,不建议在buildTypes里加类型,要加加到productFlavors里,比较符合逻辑
4. defaultConfig 里常见的选项有
applicationId(对应包名),
minSdkVersion (最小版本)
targetSdkVersion (目标版本,6.0后与权限设置相关)
versionCode 1 (版本号,不建议写这个参数,更推荐用Mainfest.xml里写)
versionName “1.0”(版本名,不建议写这个参数,更推荐用Mainfest.xml里写)
3 多渠道打包
这个没啥好说的,基本都是以友盟为例,写gradle的脚本,去替换Mainfest.xml 里的标签达到效果:
3.1 AndroidManifest.xml 配置
<meta-data
android:name="${UMENG_CHANNEL_VALUE}"
android:value="UMENG_CHANNEL" />
3.2 gradle配置
productFlavors {
xiaomi {}
yingyongbao {}
wandoujia {}
baidu {}
c360 {}
uc {}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
//自定义生成的apk的名称
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = "your_name" + "_${variant.productFlavors[0].name}_v${getVersionNameFromManifest()}_c${getVersionCodeFromManifest()}_${variant.buildType.name}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
//过滤掉unaligned的包
variant.assemble.doLast {
variant.outputs.each { output ->
println "-----------------------------------------"
println "aligned " + output.outputFile
println "unaligned " + output.packageApplication.outputFile
File unaligned = output.packageApplication.outputFile;
File aligned = output.outputFile
if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
println "deleting " + unaligned.getName()
unaligned.delete()
}
}
}
}
3.3 gradle 中获取 AndroidManifest.xml 中的版本号,与版本名
//gradle2.2以前-------------------
//从androidManifest.xml中获取版本号
//def getVersionNameFromManifest() {
// def manifestParser = new com.android.builder.core.DefaultManifestParser()
// return manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
//}
//从androidManifest.xml中获取Code
//def getVersionCodeFromManifest() {
// def manifestParser = new com.android.builder.core.DefaultManifestParser()
// return manifestParser.getVersionCode(android.sourceSets.main.manifest.srcFile)
//}
//gralde2.2+ ----------------------------
def getVersionNameFromManifest() {
def manifestParser = new com.android.builder.core.DefaultManifestParser(android.sourceSets.main.manifest.srcFile)
return manifestParser.getVersionName()
}
//从androidManifest.xml中获取Code
def getVersionCodeFromManifest() {
def manifestParser = new com.android.builder.core.DefaultManifestParser(android.sourceSets.main.manifest.srcFile)
return manifestParser.getVersionCode()
}
3.4 修改包名,和删除指定包
参见3.2中代码
3.5 过滤器
比如过滤掉release 的版本,只打debug的版本。过滤器和applicationVariants.all 是在同一层 都在android{}里
//编译过滤器
variantFilter { variant ->
def buildType = variant.buildType.name
def flavorName = variant.getFlavors().get(0).name// 根据构建类型,自动过滤渠道
//过滤掉类型
if (buildType.equals('release')) {
println "======================="
println "variantFilter " + flavorName + " " + buildType
variant.setIgnore(true)
}
}
4 测试环境和正式环境的不同配置
一般正常的开发服务器都有份测试环境,正式环境,严格的公司还分预发布环境。每种环境的服务端不一样,很典型的体现就是接口请求的域名就不同。之前查材料的时候 看到有些人把正式环境的域名是配在release里 测试环境的域名配在debug里,这是不对的。概念混淆了,任何一个环境都是要能打出debug包调试,打出release包发布出去用的。典型的就是debug包才能看一些关键log 和按步调试。
4.1 buildConfigField 配置一个宏,代码中可以访问
buildConfigField 可以配置常见的数据类型,比如String int boolean 供java代码调用,编译后会生成一个文件BuildConfig 直接可以引用其中的配置宏,如下
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "com.xxx.xxx";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "xiaomi";
public static final int VERSION_CODE = 6;
public static final String VERSION_NAME = "1.0.6";
// Fields from default config.
public static final String DOMAIN_USER = "http://user.xxxx.com";
public static final boolean IS_JUST_TEST = false;
}
4.2 配置宏的优先级
defaultConfig, buildTypes, productFlavors 都可以配置buildConfigField。
优先级buildTypes > productFlavors > defaultConfig 就是说如果三个地方都配置同一个宏,那么最后保留的是优先级高的那个。优先级高的宏 覆盖优先级低的宏。 如果不覆盖就是并排展示
展示例子
BuildConfig:
// Fields from build type: debug
// Fields from product flavor: onlytest
// Fields from default config.
4.3 测试环境和正式环境的处理方式
我是这么处理的,把测试环境当成一个渠道,如果有预发布环境当成另一个渠道 都写在 productFlavors 中,把其它渠道其实都是发布的时候用的都是正事环境写在 defaultConfig中,如果是类似电信的分地点作为渠道的,那么也是写在 productFlavors 中比如:
defaultConfig {
buildConfigField "boolean", "IS_JUST_TEST", "false"
buildConfigField "String", "DOMAIN_NAME", "\"yourDomain\""
multiDexEnabled true
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
applicationId "com.yourname"
}
productFlavors {
onlytest {
buildConfigField "String", "DOMAIN_NAME", "\"yourTestDomain\""
buildConfigField "boolean", "IS_JUST_TEST", "true"
}
loop {}
xiaomi {}
yingyongbao {}
wandoujia {}
baidu {}
c360 {}
uc {}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
java 代码引用域名 BuildConfig.DOMAIN_NAME
java 代码需要判断是不是测试环境的用 BuildConfig.IS_JUST_TEST 当然用渠道名字 BuildConfig.FLAVOR 也可以 不过为不喜欢这个