本人用Android studio也已經一年多了,現在回過頭來寫寫gradle相關的知識點,希望能給新手帶來些許幫助,大神勿噴
1、gradle的基本配置
每次新建一個module,在build.gradle文件中,都會自動生成如下配置:
我們知道,在eclipse開發中,應用程序包名是由manifest下的package屬性決定的:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.xxxx">
然而在使用gradle構建的項目中,卻多了一個applicationId屬性,并且應用程序包名是由這個applicationId決定的:
defaultConfig {
applicationId "com.xxx.xxxx"
}
通常gradle中的 applicationId 和Manifest中的 package 是一樣的,當然也可以不一樣,官方對兩者的界定給出的解釋是:
applicationId是應用在商店的唯一標識;
package是引用資源的路徑名,也就是R文件的包名.
2、gradle的簽名配置
關于簽名的概念不懂得,可以參考這篇blog:Android從零單排之簽名打包
簽名配置的語法在項目的【Project Structure】中可以找到:
如上圖所示補全簽名信息就可以在build.gradle中自動生成簽名配置.
當然,更一般的配置方法是在build.gradle中手動書寫簽名配置:
android {
signingConfigs {
config_release {
keyAlias 'releaseKey'
keyPassword '123456'
storePassword '123456'
storeFile file('key/releaseKey.jks')
}
config_debug {
keyAlias 'debugKey'
keyPassword '123456'
storePassword '123456'
storeFile file('key/debugKey.jks')
}
}
......//省略其他配置
}
這里配置了兩個簽名,簽名文件都放在app下面的key文件夾中,所以使用的是相對路徑.
如果將簽名密碼直接寫在gradle中顯然并不是很安全的做法,我們最好還是做點保密措施:在gradle中隱藏Keystore密碼
3、 配置buildTypes
語法在項目的【Project Structure】中也能找到:
這里可配置的信息很多,一般是在buildTypes{ }里面配置兩個(release和debug):
buildTypes {
release {
signingConfig signingConfigs.config_release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.config_debug
}
}
4、 配置productFlavor
多渠道打包,關鍵就在于productFlavor:
productFlavors {
flavor_1 {
minSdkVersion 14
signingConfig signingConfigs.config_release
targetSdkVersion 23
versionCode 2
versionName '2.0.1'
applicationId 'com.huaihuai.android.one'
}
flavor_2 {
minSdkVersion 10
signingConfig signingConfigs.config_debug
versionCode 1
versionName '1.0.0'
applicationId 'com.huaihuai.android.two'
}
}
我們這里給不同渠道配置不同的applicationId,就可以打包出多個不同渠道不同包名的apk.
這樣有一個應用場景就是:包名不同的apk可以共存在一個手機上,利用這點我們可以在測試機上運行多個版本的apk以方便測試.
productFlavors{ } 與 buildTypes{ }里面的配置是多對多的關系.
比如:
android {
buildTypes {
release {...}
debug {...}
}
productFlavors {
flavor_1 {...}
flavor_2 {...}
}
}
這時的配置可以打出4個apk,分別是:
#5、打包命令
強烈推薦使用gradlew命令行進行打包,因為gradle下很多方便的配置只有以命令行的方式才能正常打包,后面會講到.
比如我們打包flavor_1渠道下對應的release和debug版本:
當然,我們也不用去背這些gradle命令,因為在Android studio的右側會有【Gradle】tab頁面,里面包含了我們常用的命令:
6、manifest占位符
在打包多個版本的時候,會遇到修改應用名稱等需求。不同的flavor有要求不同的名稱. 此時可以在Manifest文件中使用占位符,然后在build.gradle中替換占位符就行了.
首先定義占位符:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${APP_NAME}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".app.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="${APP_NAME}"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
在build.gradle中替換:
buildTypes {
release {
signingConfig signingConfigs.config_release
minifyEnabled false
manifestPlaceholders = [APP_NAME: "@string/app_name1"]
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.config_debug
manifestPlaceholders = [APP_NAME: "@string/app_name2"]
}
}
productFlavors {
flavor_1 {
minSdkVersion 14
signingConfig signingConfigs.config_release
targetSdkVersion 23
versionCode 2
versionName '2.0.1'
applicationId 'com.huaihuai.android.1'
manifestPlaceholders = [APP_NAME: "@string/app_name1"]
}
flavor_2 {
minSdkVersion 10
signingConfig signingConfigs.config_debug
versionCode 1
versionName '1.0.0'
applicationId 'com.huaihuai.android.2'
manifestPlaceholders = [APP_NAME: "@string/app_name2"]
}
}
如上,如果在productFlavors和buildTypes里面都進行了替換,那么是以productFlavors里面的為準.
如果不區分productFlavors和buildTypes的話,只是單純修改應用名稱的話,也可以在defaultConfig里進行替換:
defaultConfig {
applicationId "com.huaihuai.android"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
manifestPlaceholders = [APP_NAME: "@string/app_name"]
}
其實defaultConfig也是productFlavors的一個子集.
7、添加自定義字段
我們有時候需要運行的時候有不同的表現.
比如,release版本不顯示log信息,debug版本顯示log信息
這時候我們可以通過buildConfigField、resValue在gradle里面自定義一些字段:
buildConfigField "boolean", "showLog", '"false"'
resValue "String", "build_time", '"11110000"'
添加完畢之后,就可以在代碼中使用了:
System.out.println(BuildConfig. showLog);
System.out.println(getString(R.string.build_time))
注意兩者使用方法并不相同,resValue定義的字段更像是資源文件*.xml下定義的字段,此外它們還有以下區別:
1、buildConfigField可定義字段為基本數據類型
2、buildConfigField定義的字段會顯示在BuildConfig類中
3、resValue可定義字段有:string(待補充)
4、resValue定義的字段會顯示在generated.xml中
8、動態設置一些額外信息
假如想把當前的編譯時間、編譯的機器、最新的commit版本添加到apk,而這些信息又不好寫在代碼里,強大的gradle給了我創造可能的自信:
android {
defaultConfig {
resValue "string", "build_time", buildTime()
resValue "string", "build_host", hostName()
resValue "string", "build_revision", revision()
}
}
def buildTime() {
return new Date().format("yyyy-MM-dd HH:mm:ss")
}
def hostName() {
return System.getProperty("user.name") + "@" + InetAddress.localHost.hostName
}
def revision() {
def code = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = code
}
return code.toString()
}
這個地方,如何從命令行讀取返回結果,很有意思.
9、給自己留個”后門”: 點七下
為了調試方便,我們往往會在debug版本留一個顯示我們想看的界面(記得之前微博的一個iOS版本就泄露了一個調試界面),如何進入到一個界面,我們可以仿照android開發者選項的方式,點七下才顯示,我們來實現一個:
private int clickCount = 0;
private long clickTime = 0;
sevenClickView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (clickTime == 0) {
clickTime = System.currentTimeMillis();
}
if (System.currentTimeMillis() - clickTime > 500) {
clickCount = 0;
} else {
clickCount++;
}
clickTime = System.currentTimeMillis();
if (clickCount > 6) {
// 點七下條件達到,跳到debug界面
}
}
});
release版本肯定是不能暴露這個界面的,也不能讓人用am在命令行調起,如何防止呢,可以在release版本把這個debug界面的exported設為false.
10、自定義導出APK的名稱
兩種方式實現:
/*applicationVariants.all {
variant ->
variant.outputs.each {
output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def apkType = ""
if (variant.flavorName.equals("flavor_1")) {
apkType = "flavor_1"
} else if (variant.flavorName.equals("flavor_2")) {
apkType = "flavor_2"
}
def fileName = new File(output.outputFile.getParent(),
"app-" + apkType + "-${variant.versionName}.apk")
output.outputFile = fileName
}
}
}*/
applicationVariants.all {
variant ->
variant.outputs.each {
output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = outputFile.name.replace(".apk",
"-${defaultConfig.versionCode}-${defaultConfig.versionName}.apk")
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
這里就不多講了,大家運行測試一下就明白了.
至此,文章結束,希望此文能幫助到你,如果對此文有不同見解,歡迎直接評論!
參考文案:
Gradle的神奇之處
Android項目中如何用好構建神器Gradle?
Android 使用Android Studio + Gradle 或 命令行 進行apk簽名打包