摘要:
每周一次,深入學習Android教程,TeachCourse今天帶來的一篇關於Android Studio構建文件build.gradle
的相關配置,重點學習幾個方面的內容:1、applicationId
和package
屬性值的關系,2、怎么配置安全的自定義簽名,3、兩種構建類型的區別,4、為什么要定制產品的偏好配置?,5、怎么才能加快DEX文件的生成速度,6、為什么要將一個apk拆分成多個?,7、關於引入依賴包你不知道的秘密。通過這篇文章的學習,你會對build.gradle
文件有一個全新的認識,可以將TeachCourse文章提到的相關說明作為文檔參考,方便在另一個module中引入,代碼如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "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
屬性值一樣,剛開始接觸Android Studio的時候,TeachCourse就聽說applicationId
表示真正的包名,而package
不再被認為是包名,因為應用程序被打包成apk文件的時候,原先在manifest聲明的package
被applicationId
代替,也就是說如果你的build.gradle
文件添加了applicationId
屬性值,無論兩者是否一樣,打包的apk文件的package
屬性值等於applicationId
,如果不信,TeachCourse先來做過實驗,將applicationId
改為cn.teachcourse.demo
,將package
改為cn.teachcourse
,然后將module打包成apk文件,使用反編譯工具apktool.exe,如下圖:
最后,打開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文件中,查看對應的組件目錄,如下圖:
也就是說,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在這里就不說了。
** 2.1 配置安全的自定義簽名(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.2 配置安全的自定義簽名(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
的環境變量,如下圖:
三、兩種構建類型的區別
每一個APP至少包含debug
和release
兩種構建類型,debug
定義APP的調試版本,debug
模式的幾個特點:
- 支持斷點調試和log信息打印,
debuggable
屬性值為true
- 使用系統默認的密鑰庫簽署apk文件
- 沒有對apk文件進行代碼和資源文件的優化(包括文件壓縮、冗余文件刪除)
- 沒有對代碼進行混淆
release
定義APP的發布版本,創建項目module中的build.gradle
文件,代碼如下:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
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版本,可以生成變體的總數為flavors*2
,選中需要調試的版本或選中需要發布的版本,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文件,默認為falseexclude
,指定忽略拆分的屏幕密度列表,想要拆分成更多類型的apk文件,該關鍵字包含的屏幕密度列表應就可能少reset()
,重置默認拆分的屏幕密度依據,然后使用include
標簽定義拆分的屏幕密度依據include
,結合reset
一起使用,定義拆分的屏幕密度依據compatibleScreens
,指定兼容的屏幕尺寸列表,區別於屏幕密度,該標簽將會在清單文件manifest
中通過<compatible-screens>
注入到每一個apk文件中,即apk文件只能安裝到<compatible-screens>
指定尺寸的手機上
按照上面在build.gradle
配置完成后,點擊Build APK
后,將在apk文件夾內生成多個apk文件,如下圖:
為了驗證是否在清單文件中注入指定屏幕尺寸,反編譯其中一個apk文件,如下圖:
** 6.2 按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開發的項目沒有對應的需求,暫時也沒有用到,是否使用更多應該根據項目實際情況而定,但可以作為用戶開發的例子,先分享和收藏,以備不時之需。
參考資料:
https://developer.android.google.cn/studio/build/application-id.html
https://developer.android.google.cn/studio/build/optimize-your-build.html
https://developer.android.google.cn/studio/build/dependencies.html
https://developer.android.google.cn/studio/build/build-variants.html
版權聲明:本文著作權歸TeachCourse所有,未經許可禁止轉載,謝謝支持!
轉載請注明出處:http://teachcourse.cn/2385.html