Aandroid Srudio 構建檔案build.gradle配置
Project目錄下app下的build.gradle檔案
apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToulsVersion "25.0.2" /** * 一、預設產品偏好配置 */ defaultConfig { ... } /** * 二、自定義簽名配置 */ signingConfigs { config { ... } } /** * 三、構建型別,分為release和debug兩種 */ buildTypes { release { ... } debug { ... } } /** * 四、自定義產品偏好配置,可以定義多個偏好產品 */ productFlavors { demo { applicationId "cn.teahcourse.demo" versionName "1.0-demo" signingConfig signingConfigs.config } personal{ ... } enterprise{ ... } } /** *五、DEX檔案構建屬性配置(加快構建速度) */ dexOptions { ... } /** * 六、將一個apk拆分成多個相關配置(拆分依據:螢幕密度、系統架構) */ splits { density { ... } abi { ... } } } /** * 七、引入依賴包的祕密 */ dependencies { ... }
applicationId和package屬性值的關係
Android Studio開發工具建立module的時候,預設在build.gradle檔案生成一個applicationId,對應的屬性值是填寫的package name,如下圖:
這時候的applicationId和package屬性值一樣,applicationId表示真正的包名,而package不再被認為是包名,因為應用程式被打包成apk檔案的時候,原先在manifest宣告的package被applicationId代替,也就是說如果你的build.gradle檔案添加了applicationId屬性值,無論兩者是否一樣,打包的apk檔案的
最後,開啟AndroidManifest.xml檔案,如下圖:
結果證明:cn.teachcourse被cn.teachcourse.demo代替
正是因為打包的apk檔案的package
的屬性值被applicationId代替,也剛好說明為什麼應用程式安裝到手機後,手機上顯示的是applicationId,而不是顯示package,同時如果想在應用程式中接入第三方的API,填寫的包名也必須是applicationId,常見的例子有:
1.接入微信的支付功能
2.接入微信的分享功能
3.整合百度地圖的定位功能
那麼,AndroidManifest.xml的package到底有什麼用呢?儘管,package在打包成apk的時候被applicationId代替,但是在構建的時候package有兩方面的作用:
第一個作用:在package指定的目錄下,生成對應的R.java檔案,上面的例子,構建的時候,生成R檔案的目錄,如下圖:
app\build\generated\source\r\demo\debug\cn\teachcourse\R.java
第二個作用:在package指定的目錄下,引用對應的activity、server元件,如下圖:
<!-- 定義Activity -->
<activity android:name=".MainActivity"/>
<!-- 新增service元件 -->
<service android:name=".service.music.MusicService" />
在上面反編譯的AndroidManifest.xml檔案中,檢視對應的元件目錄,如下圖: package屬性值作用
也就是說,manifest指定的元件不管使用相對路徑還是絕對路徑,打包成apk檔案後,都變成絕對路徑,結構是:package.元件
需要特別注意的問題有:
第一個問題:程式碼中使用getPackageName()或getPackageManager()對應的方法,返回的是applicationId屬性值
第二問題:使用WebView基本存放於res/raw內的檔案時,如果applicationId不等於package,提示ClassNotFoundException異常(可能是官方的bug),TeachCourse測試後找到兩個解決的辦法
嘗試將res/raw/note.html檔案移動到assets資料夾下,更換資原始檔載入路徑
mWebView.loadUrl("file:///android_asset/note.html");
保持applicationId屬性值和package屬性值一致<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.teahcourse.demo">
...
</manifest>
怎麼配置安全的自定義簽名
自定義簽名指的是使用開發者匯出的金鑰庫對apk檔案進行簽名,關於怎麼生成自己的金鑰庫,不懂的同學,可以後面看一下TeachCourse另一篇文章《Android Studio執行時自帶簽名配置過程詳解》,文章介紹了怎麼配置Android Studio的執行時簽名,這樣做的目的:在接入一些需要自定義簽名的API時,方便直接除錯。
這裡,介紹的是安全的自定義簽名,即怎麼才讓別人看不到我們在build.gradle寫入的密碼(包括別名密碼、金鑰庫密碼),關於簽名檔案的重要性,TeachCourse在這裡就不說了。
配置安全的自定義簽名(1),步驟:
在專案的根目錄下建立一個名稱為 keystore.properties 的檔案。此檔案應當包含您的簽署資訊,如下所示:
storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation
這裡需要注意:keystore.properties中storeFile簽名檔案是相對module目錄的路徑,即將金鑰庫檔案儲存在module根目錄下 在模組的 build.gradle 檔案中,於 android {} 塊的前面新增用於載入 keystore.properties 檔案的程式碼。
...
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
...
}
注:您可以選擇將 keystore.properties 檔案儲存在其他位置(例如,儲存在模組資料夾中而不是專案的根資料夾中,或者如果您使用連續整合工具,也可以儲存在構建伺服器上)。在這種情況下,您應當修改上面的程式碼,以便使用實際 keystore.properties 檔案的位置正確初始化 keystorePropertiesFile。
您可以使用語法 keystoreProperties[‘屬性名稱’] 引用儲存在 keystoreProperties 中的屬性。修改模組 build.gradle 檔案的 signingConfigs 塊,以便使用此語法引用儲存在 keystoreProperties 中的簽署資訊。
android {
signingConfigs {
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
...
}
最後,我們就可以按照《Android Studio執行時自帶簽名配置過程詳解》介紹的方式,將signingConfigs 塊作用於release版本或debug版本
配置安全的自定義簽名(2),步驟:
第二種安全的自定義簽名的方式是:將別名、別名密碼、金鑰密碼以鍵值對的形式儲存到當前電腦的環境變數中,然後通過變數名讀取變數值,如下圖:
android {
signingConfigs {
config {
keyAlias System.getenv("KEYALIAS")
keyPassword System.getenv("KEYPWD")
storeFile file('release.jks')
storePassword System.getenv("KSTOREPWD")
}
}
...
}
KEYALIAS指的是環境變數的變數名,System.getenv(“KEYALIAS”)的讀取變數名對應的變數值,如圖:
KEYPWD,按照上圖的方式新增,如下圖:
KSTOREPWD以同樣的方式,如下圖:
需要特別注意的是:第二種自定義簽名的方式,需要先檢查Android Studio是否已配置了gradle工具的環境變數,開啟Android Studio的terminal視窗,輸入:gradle build,如下圖:
如果,你的terminal視窗提示gradle不是內部命令,操作上述步驟之前,你得新增gradle工具的環境變數,Android Studio的gradle工具預設存放路徑:
C:\Program Files\Android\Android Studio\gradle\gradle-3.2
配置gradle的環境變數,如下圖:minifyEnable定義是否壓縮程式碼,false表示不壓縮;proguardFiles定義混淆程式碼的預設混淆規則,proguard-android.txt表示系統自帶的混淆規則,proguard-rules.pro位於當前module根目錄下,用於定義開發者自己的混淆規則。
release模式需要注意的幾個特點:
- 不支援斷點除錯,debuggable預設為false
- 沒有壓縮類檔案程式碼,minifyEnabled,預設為false
- 沒有壓縮資原始檔,shrinkResources,預設為false
- 沒有指定自定義簽名檔案,預設使用系統的金鑰庫簽署apk
開發者在釋出應用程式時,需要對release模式下的屬性配置進行修改,優化apk檔案,刪除無用的程式碼和資原始檔,混淆類檔案和資源名稱,自定義簽名金鑰庫,程式碼如下:
release {
shrinkResources true
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
總結:
debug和release模式,最大的區別預設屬性配置不一樣,兩種模式支援的屬性配置還包括,如下圖:
記不住程式碼的同學,可以選中Build Types定義的模式,在可選項中改變對應屬性配置,Android Studio執行時簽名的實質將debug模式下的Signing Config設定為自定義金鑰庫檔案,但是TeachCourse隨著不斷深入學習後發現,其實debug模式下配置Signing Config是多此一舉,而只要在release模式下配置Signing Config就夠了,Android Studio的可以方便為我們生成兩種模式下對應的apk檔案,在Android Studio的左下角Build Variant中切換,如下圖:
下面介紹了產品偏好配置後,回頭再看看它們兩者之間的關係。
為什麼要定製產品的偏好配置?
什麼是產品的偏好配置呢?比如說,TeachCourse想要開發一個應用程式,包含個人版本personal和企業版本enterprise,這兩個版本之間在功能上有所區別,企業版自然比個人版功能要多一些,很明顯就是要就一個Android專案打包成兩個產品釋出,它們之間的要求如下所示:
personal:版本號為1,最低SDK版本定義為11,最高SDK定義為24,版本名稱字尾定義為-personal,applicationId字尾定義為-per,簽名檔案為自定義金鑰庫,程式碼如下:
personal {
versionCode 1
minSdkVersion 11
targetSdkVersion 24
versionNameSuffix '-personal'
applicationIdSuffix '-per'
signingConfig signingConfigs.config
}
enterprise:版本號為1000,最低SDK版本定義為11,最高SDK定義為24,版本名稱字尾定義為-profession,applicationId字尾定義為-pro,簽名檔案為自定義金鑰庫程式碼如下:
enterprise {
versionCode 1000
minSdkVersion 11
targetSdkVersion 24
versionNameSuffix '-profession'
applicationIdSuffix 'full'
signingConfig signingConfigs.config
}
同時,TeachCourse定義第三個產品偏好配置為demo,用於上傳GitHub,提供下載,程式碼如下:demo {
applicationId "cn.teahcourse.demo"
versionName "1.0-demo"
signingConfig signingConfigs.config
}
一個Android專案,配置三個偏好的產品,即使修改了專案程式碼,也可以快速編譯並打包三個apk檔案,在Android Studio的左下角Build Variant中切換,如下圖:
看上面的圖片,你是不是發現了什麼,突然間,三個偏好配置的產品,出現了6個變體,一個產品包含debug和release兩個版本,構建型別和偏好產品之間的關係是:一個偏好產品,肯定包含一個debug版本和一個release版本,可以生成變體的總數為flavors2
*,選中需要除錯的版本或選中需要釋出的版本,Android Studio自動重新構建Android專案,就可以針對指定的產品進行除錯或打包,非常的方便吧!偏好產品相關配置,如下圖:
defaultConfig也屬於其中一種偏好產品,在我們沒有定義自己的偏好產品時,我們構建和編譯的就是預設的defaultConfig這個產品,也就只包含debug和release兩個變體。
怎麼才能加快DEX檔案的生成速度?
你有沒有遇到Android Studio在每次構建的時候,都感覺花好長時間,TeachCourse就不止一次和同事抱怨說,Android Studio的編譯速度還不如Eclipse快,蝸牛的速度真受不了呀?那該怎麼辦呢?
Android Studio提供dexOption區塊以便於我們配置DEX構建屬性,加快DEX檔案的生成速度,程式碼如下:
dexOptions {
preDexLibraries true
maxProcessCount 8
javaMaxHeapSize "2048m"
}
- preDexLibraries宣告是否預先編譯依賴庫,從而加快構建速度,實質是通過延時清除已生成的依賴庫的構建檔案,從而提高構建速度,根據使用情況合理配置。
- maxProcessCount設定程序執行過程中可以使用的最大執行緒數。預設值為4。
- javaMaxHeapSize設定DEX編譯器的最大堆大小,堆或者棧都是用於存放暫時不用的垃圾,當記憶體不足時,垃圾回收機制會清除過時的快取,堆大小決定垃圾清除的頻率,影響著構建的速度
為什麼要將一個apk拆分成多個?
根據TeachCourse以往的經驗,一個apk檔案可以支援不同螢幕密度和不同ABIs的手機裝置,是因為我們進行了螢幕適配,做法:將市場主流的螢幕密度和ABIs整合到一個apk,造成的影響,如果你的應用程式本身就比較大,集成了不同螢幕密度和支援不同ABIs的程式碼,打包出來的apk檔案變得更大,考慮到流量成本和使用者體驗,減少apk檔案的大小其中一種方式將一個apk檔案拆分成多個。
Gradle能夠單獨指定只包含一種螢幕密度或一種ABI程式碼和資原始檔的apk,在build.gradle檔案中使用到splits區塊,splits區塊內同時提供了按螢幕密度拆分的density區塊和按abi拆分的abi區塊,在一個build.gradle檔案中可以同時指定兩者或兩者中的其中一者,下面分別介紹:
6.1 按螢幕密度拆分
android {
...
splits {
density {
enable true
exclude "xxxhdpi"
reset()
include "ldpi", "xxhdpi"
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}
上面是一個按螢幕密度拆分的一個例子,各個標籤的含義是:
- enable,是否基於定義的螢幕密度拆分成多個apk檔案,預設為false
- exclude,指定忽略拆分的螢幕密度列表,想要拆分成更多型別的apk檔案,該關鍵字包含的螢幕密度列表應就可能少
- reset(),重置預設拆分的螢幕密度依據,然後使用include標籤定義拆分的螢幕密度依據
- include,結合reset一起使用,定義拆分的螢幕密度依據
- compatibleScreens,指定相容的螢幕尺寸列表,區別於螢幕密度,該標籤將會在清單檔案manifest中通過注入到每一個apk檔案中,即apk檔案只能安裝到指定尺寸的手機上
按照上面在build.gradle配置完成後,點選Build APK後,將在apk資料夾內生成多個apk檔案,如下圖:
為了驗證是否在清單檔案中注入指定螢幕尺寸,反編譯其中一個apk檔案,如下圖:
按abi拆分
android {
...
splits {
abi {
enable true
reset()
include "x86", "armeabi-v7a", "mips"
universalApk false
}
}
}
上面是一個按abi拆分的一個例子,除了universal標籤不一樣外,其他標籤是一樣的,使用方法一樣,include標籤定義拆分的abi依據,關於abi介紹,參考下面連線:
同樣,點選Build APK後,將在apk資料夾內生成多個apk檔案,如下圖:
仔細觀察生成的apk檔案,會發現下面兩個規律:
- 第一個規律:apk總數=abi數量+density數量xabi數量
- 第二個規律:apk filename=modulename-screendensityABI-buildvariant.apk
關於引入依賴包你不知道的祕密
不知道你會不會有和TeachCourse一樣的想法,dependencies區塊引入的jar包的名稱長,基本無法記住,每一節又表示什麼含義?Android Studio引入依賴項有幾種方式?讓我先看下面的這個例子:
dependencies {
compile project(":mylibrary")
compile files('libs/zxing.jar')
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.1.0'
compile group: 'com.android.support', name: 'appcompat-v7', version: '25.1.0'
}
可以看到Android Studio引入依賴項的方式分為上述四種,按順序依次稱為:
1、模組依賴項
2、本地二進位制依賴項
3、本地二進位制依賴項
4、遠端二進位制依賴項
5、遠端二進位制依賴項
- compile project(‘:mylibrary’) 行聲明瞭一個名為mylibrary的本地 Android 庫模組作為依賴項,並要求構建系統在構建應用時編譯幷包含該本地模組。
- compile files(‘libs/zxing.jar’)和compile fileTree(dir: ‘libs’, include: [‘*.jar’])都稱為本地依賴項,告訴構建系統在編譯類路徑和最終的應用軟體包中包含 app/libs/ 目錄內的指定或全部 JAR 檔案。如果您有模組需要本地二進位制依賴項,請將這些依賴項的 JAR 檔案複製到專案內部的 /libs 中。
- compile ‘com.android.support:appcompat-v7:25.1.0’和compile group: ‘com.android.support’, name: ‘appcompat-v7’, version: ‘25.1.0’都稱為遠端二進位制依賴項,通過指定其 JCenter 座標,針對 Android 支援庫的 25.1.0 版本聲明瞭一個依賴項。預設情況下,Android Studio 會將專案配置為使用頂級構建檔案中的 JCenter 儲存區。當您將專案與構建配置檔案同步時,Gradle 會自動從 JCenter 中抽取依賴項。或者,您也可以通過使用 SDK 管理器下載和安裝特定的依賴項。
第五種可以清楚看出每一節表示的含義,在Android Studio引入遠端二進位制依賴項,通常的做法是在Library Dependency視窗中搜索,搜尋到最新版本的依賴項,如下圖:
似乎無法搜尋到低版本的依賴項,如果想要引入低版本的,那該怎麼辦呢?如果先前不瞭解遠端二進位制依賴項的含義,可能想不到修改version的辦法,現在就變得很簡單了。
總結:
本篇文章在閱讀Android Studio使用者指南多篇相關文件後完成的,想要更詳細深入學習gradle指令的同學,可以繼續研讀Gradle官網文件,部分內容在TeachCourse開發的專案沒有對應的需求,暫時也沒有用到,是否使用更多應該根據專案實際情況而定,但可以作為使用者開發的例子,先分享和收藏,以備不時之需。