这里分享下我在日常开发中对 gradle 的常用配置规则
一、版本号配置
当项目逐渐演进的过程中,主工程依赖的 module
可能会越来越多,此时就需要统一配置各个 module
的编译参数了
在工程的根目录下新建一个 gradle
文件,命名为 config.gradle
,在此文件中统一声明工程的编译属性和依赖库的版本号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
ext { compilesdkversion = 28 minsdkversion = 15 targetsdkversion = 28 versioncode = 1 versionname = '1.0' dependencies = [ appcompatv7 : 'com.android.support:appcompat-v7:28.0.0-rc02' , constraintlayout: 'com.android.support.constraint:constraint-layout:1.1.3' , junit : 'junit:junit:4.12' , testrunner : 'com.android.support.test:runner:1.0.2' , espressocore : 'com.android.support.test.espresso:espresso-core:3.0.2' ] } |
默认情况下, app module
的 build.gradle
文件的默认配置如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
apply plugin: 'com.android.application' android { compilesdkversion 28 defaultconfig { applicationid "leavesc.hello.gradlesamples" minsdkversion 15 targetsdkversion 28 versioncode 1 versionname "1.0" testinstrumentationrunner "android.support.test.runner.androidjunitrunner" } buildtypes { release { minifyenabled false proguardfiles getdefaultproguardfile( 'proguard-android.txt' ), 'proguard-rules.pro' } } } dependencies { implementation filetree(dir: 'libs' , include: [ '*.jar' ]) implementation 'com.android.support:appcompat-v7:28.0.0-rc02' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testimplementation 'junit:junit:4.12' androidtestimplementation 'com.android.support.test:runner:1.0.2' androidtestimplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } |
这里将其改为引用 config.gradle
文件的形式
首先,需要在根目录下的 build.gradle
文件中应用 config.gradle
文件,这样在 module
配置文件中才引用得到当中的属性值
此时就可以修改应用版本号以及依赖库的声明方式了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
apply plugin: 'com.android.application' def globalconfiguration = rootproject.ext def presentationdependencies = globalconfiguration.dependencies android { compilesdkversion globalconfiguration[ "compilesdkversion" ] defaultconfig { applicationid "leavesc.hello.gradlesamples" minsdkversion globalconfiguration[ "minsdkversion" ] targetsdkversion globalconfiguration[ "targetsdkversion" ] versioncode globalconfiguration[ "versioncode" ] versionname globalconfiguration[ "versionname" ] testinstrumentationrunner "android.support.test.runner.androidjunitrunner" } buildtypes { release { minifyenabled false proguardfiles getdefaultproguardfile( 'proguard-android.txt' ), 'proguard-rules.pro' } } } dependencies { implementation filetree(include: [ '*.jar' ], dir: 'libs' ) implementation presentationdependencies.appcompatv7 implementation presentationdependencies.constraintlayout testimplementation presentationdependencies.junit androidtestimplementation presentationdependencies.testrunner androidtestimplementation presentationdependencies.espressocore } |
这样,即使以后工程中包含多个 module
,只要配置的属性都是来自于 config.gradle
文件,就可以做到统一修改编译属性与依赖库版本了
二、签名属性配置
通常,应用的签名类型会分为 release
和 debug
两类,并分别使用不同的签名文件
为了安全考虑以及实现自动化打包,可以通过 gradle
来声明签名配置,包括签名文件路径、签名别名、签名密码等
在 local.properties
文件中声明签名文件路径以及签名密码
1
2
3
4
5
|
sdk.dir=c\:\\software\\sdk key.keystorepath=..\\doc\\key.jks key.keyalias=leavesc key.keypassword= 987654321 key.storepassword= 123456789 |
根据配置可知,签名文件是放在工程的 doc
文件夹内
通过代码获取到签名的各个配置项
1
2
3
4
5
6
7
|
properties properties = new properties() properties.load(project.rootproject.file( 'local.properties' ).newdatainputstream()) def keystorepath_ = properties.getproperty( "key.keystorepath" ) def storepassword_ = properties.getproperty( "key.storepassword" ) def keyalias_ = properties.getproperty( "key.keyalias" ) def keypassword_ = properties.getproperty( "key.keypassword" ) def storefile_ = file(keystorepath_) |
配置不同的签名属性以及 build
类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
signingconfigs { release { storefile storefile_ storepassword storepassword_ keyalias keyalias_ keypassword keypassword_ v1signingenabled true v2signingenabled true } debug { storefile storefile_ storepassword storepassword_ keyalias keyalias_ keypassword keypassword_ v1signingenabled true v2signingenabled true } } buildtypes { debug { minifyenabled false proguardfiles getdefaultproguardfile( 'proguard-android.txt' ), 'proguard-rules.pro' signingconfig signingconfigs.debug } release { minifyenabled true proguardfiles getdefaultproguardfile( 'proguard-android.txt' ), 'proguard-rules.pro' signingconfig signingconfigs.release } } |
此处,我配置了两种不同的 buildtype
: debug
、 release
,并对应不同的签名文件
以后只要选定不同的 build variant
,即可打包具体签名的 apk 文件
而 local.properties
文件可以保存到服务器来实现远程打包,从而保证了隐私安全
三、多渠道打包
有时候,为了方便进行精准营销,会有生成不同渠道包的要求,此时就需要在同个应用上打上不同的渠道id(channelid),这可以通过 productflavors
来实现
先在 androidmanifest.xml
文件中配置占位符, appkey
即对应各个渠道的 id 值
1
2
3
|
<meta-data android:name= "app_key" android:value= "${appkey}" /> |
在 gradle.properties
文件中声明需要的 channelid
以及对应的 applicationid
,在此文件中声明的属性可以直接在 build.gradle
中直接获取到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#默认配置 defaultapplicationid=leavesc.hello.gradlesamples ##各个渠道的配置 #应用宝 yingyongbaochannelid= "yingyongbao" yingyongbaoapplicationid=leavesc.hello.gradlesamples.yingyongbao yingyongbaoappkey=appkey_yingyongbao #豌豆荚 wandoujiachannelid= "wandoujia" wandoujiaapplicationid=leavesc.hello.gradlesamples.wandoujia wandoujiaappkey=appkey_wandoujia #小米 xiaomichannelid= "xiaomi" xiaomiapplicationid=leavesc.hello.gradlesamples.xiaomi xiaomiappkey=appkey_xiaomi |
productflavors
可以理解为是对同个产品的不同“风味要求”,可以根据配置项生成特定风味的产品(app)
例如,此处就为不同渠道设定了不同的 applicationid
buildconfigfield
属性则用于在 buildconfig.java
文件中生成特定类型的字段,此处就生成了一个类型为 string
,名为 channelid
的字段,用于方便在应用运行过程中判断当前应用的渠道类型
manifestplaceholders
就是用于替换 androidmanifest.xml
文件中的指定占位符了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
productflavors { yingyongbao { applicationid yingyongbaoapplicationid buildconfigfield "string" , "channelid" , yingyongbaochannelid manifestplaceholders = [appkey: yingyongbaoappkey] } wandoujia { applicationid wandoujiaapplicationid buildconfigfield "string" , "channelid" , wandoujiachannelid manifestplaceholders = [appkey: wandoujiaappkey] } xiaomi { applicationid xiaomiapplicationid buildconfigfield "string" , "channelid" , xiaomichannelid manifestplaceholders = [appkey: xiaomiappkey] } } |
在主布局文件中展示当前应用的各项属性值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
@override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); setcontentview(r.layout.activity_main); stringbuilder sb = new stringbuilder(); sb.append( "applicationid: " ); sb.append(getapplicationinfo().packagename); sb.append( "\n" ); sb.append( "applicationname: " ); sb.append(getstring(getapplicationinfo().labelres)); sb.append( "\n" ); sb.append( "channelid: " ); sb.append(buildconfig.channelid); sb.append( "\n" ); try { applicationinfo appinfo = getpackagemanager().getapplicationinfo(getpackagename(), packagemanager.get_meta_data); string appkey = appinfo.metadata.getstring( "app_key" ); sb.append( "appkey: " ); sb.append(appkey); } catch (packagemanager.namenotfoundexception e) { e.printstacktrace(); } textview tv_appinfo = findviewbyid(r.id.tv_appinfo); tv_appinfo.settext(sb); imageview iv_log = findviewbyid(r.id.iv_log); iv_log.setimageresource(getapplicationinfo().icon); } |
四、打包时指定 apk 名字
为了方便标识各个测试包的版本已经打包时间,可以通过 gradle
来指定生成的 apk 文件的命名规则
例如,以下配置就根据 buildtype、flavorname
和 编译时间 来命名 apk 文件
1
2
3
4
5
6
7
8
|
applicationvariants.all { variant -> def buildtype = variant.buildtype.name def flavorname = variant.flavorname def createtime = new date().format( "yyyy-mm-dd_hh_mm_ss" , timezone.gettimezone( "gmt+08:00" )) variant.outputs.all { outputfilename = flavorname + "_" + buildtype + "_v" + defaultconfig.versionname + "_" + createtime + ".apk" } } |
五、生成属性字段与资源文件值
上边讲过, buildconfigfield
属性可用于在 buildconfig.java
文件中生成特定类型的字段,此处可以利用其来记录应用的编译时间
此外,也可以利用 resvalue
来生成一个 id 引用类型的 string
字符串
首先,声明两个方法,分别用于获取当前时间以及当前电脑的用户信息
1
2
3
4
5
6
7
|
static def buildtime() { return new date().format( "yyyy-mm-dd hh:mm:ss" ) } static def hostname() { return system.getproperty( "user.name" ) + "@" + inetaddress.localhost.hostname } |
1
2
3
4
5
6
7
8
9
10
11
|
defaultconfig { applicationid defaultapplicationid minsdkversion globalconfiguration[ "minsdkversion" ] targetsdkversion globalconfiguration[ "targetsdkversion" ] versioncode globalconfiguration[ "versioncode" ] versionname globalconfiguration[ "versionname" ] testinstrumentationrunner "android.support.test.runner.androidjunitrunner" flavordimensions '1' resvalue "string" , "build_host" , hostname() buildconfigfield "string" , "build_time" , "\"" + buildtime() + "\"" } |
用代码来获取这两个属性值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
@override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); setcontentview(r.layout.activity_main); stringbuilder sb = new stringbuilder(); sb.append( "applicationid: " ); sb.append(getapplicationinfo().packagename); sb.append( "\n" ); sb.append( "applicationname: " ); sb.append(getstring(getapplicationinfo().labelres)); sb.append( "\n" ); sb.append( "channelid: " ); sb.append(buildconfig.channelid); sb.append( "\n" ); sb.append( "buildtime: " ); sb.append(buildconfig.build_time); sb.append( "\n" ); sb.append( "builduser: " ); sb.append(getstring(r.string.build_host)); sb.append( "\n" ); try { applicationinfo appinfo = getpackagemanager().getapplicationinfo(getpackagename(), packagemanager.get_meta_data); string appkey = appinfo.metadata.getstring( "app_key" ); sb.append( "appkey: " ); sb.append(appkey); } catch (packagemanager.namenotfoundexception e) { e.printstacktrace(); } textview tv_appinfo = findviewbyid(r.id.tv_appinfo); tv_appinfo.settext(sb); imageview iv_log = findviewbyid(r.id.iv_log); iv_log.setimageresource(getapplicationinfo().icon); } |
六、替换资源文件
在多渠道打包时,除了需要在应用中打上特定的标签外,也可能需要使之使用不同的资源文件,例如应用图标和应用名称
此时可以以各个 productflavor
的名称来命名相应的文件夹,并在其中放置相应的图标文件以及声明了应用名称的 string.xml
文件,这样在多渠道打包时,gradle 就会自动引用相应的资源文件
上述所有的示例代码可以在这里获取: gradlesamples
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/leavesC/p/9624397.html