ADT已经不在继续更新了。自然而然的,Android Studio成了新贵。虽说还是有一些别的IDE和别的方式去编写和构建Android,但由于谷歌的维护和升级,AS成了绝大多数Android开发者的选择。对于小团队来说(本人就是在小小小团队),AS + GRADLE 成了现阶段主流。
这是记录,所以概念型的东西就不做介绍了。
需求
由于团队本身有好多服务器(*开发,灰度,线上*),再加上有很多三方的引用(如:我们团队IM引用了环信),另外还有一些日志系统的调控等,再加上长时间不同人员对代码开发,导致这些配置非常混乱,散落于不同的类,还有一些在AndroidManifies.xml
等文件中,所以导致导报经常会出现一些莫名其妙的错误。
需求:实现 > 能合理地配置这些,并使用配置文件进行统一管理 >的需求。
目标如下:
只需更改一处(一行)就能实现不同需求打包的切换!(最重要)
简单
不影响Studio相关联的
gradle
文件(build.gradle
一旦改变,就会导致重新编译),但又可以及时更改相关配置。
配置工程
配置BuildConfig
BuildConfig
这个类是工程自动构建生成的。可以具体看一下这个类。
/** * Automatically generated file. DO NOT MODIFY */package ****;public final class BuildConfig { public static final boolean DEBUG = Boolean.parseBoolean("true"); public static final String APPLICATION_ID = "**.builddemo"; public static final String BUILD_TYPE = "debug"; public static final String FLAVOR = ""; public static final int VERSION_CODE = 1; public static final String VERSION_NAME = "1.0"; }
注释说:这个类是自动生成的,别动,动了也没什么用~~~
然后可以看到,这里DEBUG
,APPLICATION_ID
,BUILD_TYPE
,FLAVOR
,VERSION_CODE
,VERSION_NAME
这些常量,这些常量有的是我们在AndroidManifest.xml
中配置的,有些是我们在module下的build.grade
中配置的(当然,这些其实全部可以在build.gradle
中进行配置)
就像这个样子:
android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "**.builddemo" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard- rules.pro' } } productFlavors { } }
由于工程中需要versionCode
参数,所以BuildConfig
便提供了很大的便利。
Tip: defaultConfig{} 这个闭包就是配置工程参数的,也就是直接对应
BuildConfig
的
既然如此,如果能给BuildConfig
配置自定义的参数,那么需求就解决了一半了!
显然,Android团队也肯定会留下一些自定义的API,保证大家能 “ 随便乱搞”。
下面是自定义API写法和使用
defaultConfig { ... // 自定义的方法就是 buildConfigField ,这种是groovy写法 // 三个参数分别是 type (类型) , name (命名) , value(值) buildConfigField 'int' , 'SEVER_CONFIG' , "1" // 当然写成这种更容易看懂,这种写法更像java。 // 三个参数分别是 type (类型) , name (命名) , value(值) buildConfigField("int" , "SEVER_CONFIG" , "1") }
重新构建后,可以看到
public final class BuildConfig { public static final boolean DEBUG = Boolean.parseBoolean("true"); public static final String APPLICATION_ID = "**.builddemo"; public static final String BUILD_TYPE = "debug"; public static final String FLAVOR = ""; public static final int VERSION_CODE = 1; public static final String VERSION_NAME = "1.0"; // Fields from default config. public static final int SEVER_CONFIG = 1; }
可以看到int SEVER_CONFIG = 1;
正好对应 'int' , 'SEVER_CONFIG' , "1"
注意, “1” 对应的是 1 , ’ “1” ‘ 对应的是 “1”
是不是很简单。
简单看一下原理吧。
原来是本身构建的时候,android会将闭包转化成相关类,并调用方法。可以看一下buildConfigField
这个方法
// -- DSL Methods. TODO remove once the instantiator does what I expect it to do. /** * Adds a new field to the generated BuildConfig class. * * The field is generated as: * * <type> <name> = <value>; * * This means each of these must have valid Java content. If the type is a String, then the * value should include quotes. * * @param type the type of the field * @param name the name of the field * @param value the value of the field */ public void buildConfigField( @NonNull String type, @NonNull String name, @NonNull String value) { ClassField alreadyPresent = getBuildConfigFields().get(name); if (alreadyPresent != null) { String flavorName = getName(); if (BuilderConstants.MAIN.equals(flavorName)) { logger.info( "DefaultConfig: buildConfigField '{}' value is being replaced: {} -> {}", name, alreadyPresent.getValue(), value); } else { logger.info( "ProductFlavor({}): buildConfigField '{}' " + "value is being replaced: {} -> {}", flavorName, name, alreadyPresent.getValue(), value); } } addBuildConfigField(AndroidBuilder.createClassField(type, name, value)); }
这是ProductFlavor
这个类里的方法,不详细说了,大家其实直接看注释就ok了。
解决AndroidManifest.xml
的Meta-data
等
拿AndroidManifest.xml
的Meta-data
出来说,其实别的字段也是一样的。
还是build.gradle
中的配置
defaultConfig { applicationId "zhulonglong.builddemo" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" buildConfigField 'int' , 'SEVER_CONFIG' , "1" manifestPlaceholders = [ CHANNEL_VALUE : "QQ" ] }
对应的AndroidManifest.xml
的Meta-data
数据是
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> ... <meta-data android:name="CHANNEL" android:value="${CHANNEL_VALUE}"/></application>
${}
是替代符,在defaultConfig
中manifestPlaceholders
便是对应的AndroidManifest.xml配置文件。
合并,新建config.gradle
统一管理所有的配置
创建一个config.gradle
的好处:
无缝衔接
gradle
构建系统android studio 方便查看更改,且不会引起重新构建(IDE 自动识别的都是
build.gradle
文件,对于别的gradle文件不会在乎)
我创建的config.grade
是在项目根录下的。
def DEV = 0def ONLINE = 2ext{ SEVER_CONFIG = ONLINE CHANNEL_DEV = "CHANNEL_DEV" CHANNEL_ONLINE = "CHANNEL_ONLINE" if (SEVER_CONFIG == DEV){ CHANNEL_NAME = CHANNEL_DEV }else { CHANNEL_NAME = CHANNEL_ONLINE } }
ext
保证了别的gradle
能顺利使用这个属性
在需要的build.gradle
中导入config.gradle
。
apply from: rootProject.getRootDir().getAbsolutePath() + "/config.gradle"println "Project Name " + getName() println "Project Path " + getPath() android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "**.builddemo" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" buildConfigField 'int' , 'SEVER_CONFIG' , "${SEVER_CONFIG}" manifestPlaceholders = [ CHANNEL_VALUE : "${CHANNEL_NAME}" ] } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { } }
然后就可以直接引用这个属性了。
如:
buildConfigField 'int' , 'SEVER_CONFIG' , "${SEVER_CONFIG}"
SEVER_CONFIG
就是在config.gradle
中定义的。
到此为止,目的达到了。
所有的配置都在文件config.gradle
中进行更改。当然,还需要在里面定义一个总开关,将具体参数配置分块。
在代码中可以直接使用BuildConfig
进行相关使用。
当然,更改config.gradle
不会进行重新构建,是不是棒棒哒!!!