Android開發之深刻理解Android Studio構建文件build.gradle配置

摘要:

每週一次,深刻學習Android教程,TeachCourse今天帶來的一篇關於Android Studio構建文件build.gradle的相關配置,重點學習幾個方面的內容:一、applicationIdpackage屬性值的關係,二、怎麼配置安全的自定義簽名,三、兩種構建類型的區別,四、爲何要定製產品的偏好配置?,五、怎麼才能加快DEX文件的生成速度,六、爲何要將一個apk拆分紅多個?,七、關於引入依賴包你不知道的祕密。經過這篇文章的學習,你會對build.gradle文件有一個全新的認識,能夠將TeachCourse文章提到的相關說明做爲文檔參考,方便在另外一個module中引入,代碼以下:html

apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "25.0.2" /** * 1、默認產品偏好配置 */ defaultConfig { ... } /** * 2、自定義簽名配置 */ signingConfigs { config { ... } } /** * 3、構建類型,分爲release和debug兩種 */ buildTypes { release { ... } debug { ... } } /** * 4、自定義產品偏好配置,能夠定義多個偏好產品 */ productFlavors { demo { applicationId "cn.teahcourse.demo" versionName "1.0-demo" signingConfig signingConfigs.config } personal{ ... } enterprise{ ... } } /** *5、DEX文件構建屬性配置(加快構建速度) */ dexOptions { ... } /** * 6、將一個apk拆分紅多個相關配置(拆分依據:屏幕密度、系統架構) */ splits { density { ... } abi { ... } } } /** * 7、引入依賴包的祕密 */ dependencies { ... } 

1、applicationIdpackage屬性值的關係

Android Studio開發工具建立module的時候,默認在build.gradle文件生成一個applicationId,對應的屬性值是填寫的package name,以下圖:java

applicationId屬性值

這時候的applicationIdpackage屬性值同樣,剛開始接觸Android Studio的時候,TeachCourse就據說applicationId表示真正的包名,而package再也不被認爲是包名,由於應用程序被打包成apk文件的時候,原先在manifest聲明的packageapplicationId代替,也就是說若是你的build.gradle文件添加了applicationId屬性值,不管二者是否同樣,打包的apk文件的package屬性值等於applicationId,若是不信,TeachCourse先來作過實驗,將applicationId改成cn.teachcourse.demo,將package改成cn.teachcourse,而後將module打包成apk文件,使用反編譯工具apktool.exe,以下圖:android

apktool反編譯工具

最後,打開AndroidManifest.xml文件,以下圖:nginx

package被applicationId代替

結果證實:cn.teachcoursecn.teachcourse.demo代替django

正是由於打包的apk文件的package的屬性值被applicationId代替,也恰好說明爲何應用程序安裝到手機後,手機上顯示的是applicationId,而不是顯示package,同時若是想在應用程序中接入第三方的API,填寫的包名也必須是applicationId,常見的例子有:1.接入微信的支付功能,2.接入微信的分享功能,3.集成百度地圖的定位功能緩存

那麼,AndroidManifest.xmlpackage到底有什麼用呢?儘管,package在打包成apk的時候被applicationId代替,可是在構建的時候package有兩方面的做用:安全

第一個做用:package指定的目錄下,生成對應的R.java文件,上面的例子,構建的時候,生成R文件的目錄,以下圖:ruby

app\build\generated\source\r\demo\debug\cn\teachcourse\R.java

第二個做用:package指定的目錄下,引用對應的activityserver組件,以下圖:bash

<!-- 定義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測試後找到兩個解決的辦法

  1. 嘗試將res/raw/note.html文件移動到assets文件夾下,更換資源文件加載路徑
mWebView.loadUrl("file:///android_asset/note.html");
  1. 保持applicationId屬性值和package屬性值一致
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.teahcourse.demo"> ... </manifest>

2、怎麼配置安全的自定義簽名

自定義簽名指的是使用開發者導出的密鑰庫對apk文件進行簽名,關於怎麼生成本身的密鑰庫,不懂的同窗,能夠後面看一下TeachCourse另外一篇文章《Android Studio運行時自帶簽名配置過程詳解》,文章介紹了怎麼配置Android Studio的運行時簽名,這樣作的目的:在接入一些須要自定義簽名的API時,方便直接調試。

這裏,介紹的是安全的自定義簽名,即怎麼才讓別人看不到咱們在build.gradle寫入的密碼(包括別名密碼、密鑰庫密碼),關於簽名文件的重要性,TeachCourse在這裏就不說了。

** 2.1 配置安全的自定義簽名(1),步驟:**

  1. 在項目的根目錄下建立一個名稱爲 keystore.properties 的文件。此文件應當包含您的簽署信息,以下所示:
storePassword=myStorePassword keyPassword=mykeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation

這裏須要注意:keystore.propertiesstoreFile簽名文件是相對module目錄的路徑,即將密鑰庫文件保存在module根目錄下
密鑰庫配置

  1. 在模塊的 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。

  1. 您可使用語法 keystoreProperties['屬性名稱'] 引用存儲在 keystoreProperties 中的屬性。修改模塊 build.gradle 文件的 signingConfigs 塊,以便使用此語法引用存儲在 keystoreProperties 中的簽署信息。
android {
    signingConfigs {
        config {
            keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } ... }
  1. 最後,咱們就能夠按照《Android Studio運行時自帶簽名配置過程詳解》介紹的方式,將signingConfigs 塊做用於release版本或debug版本

** 2.2 配置安全的自定義簽名(2),步驟:**

  1. 第二種安全的自定義簽名的方式是:將別名、別名密碼、密鑰密碼以鍵值對的形式保存到當前電腦的環境變量中,而後經過變量名讀取變量值,以下圖:
android { signingConfigs { config { keyAlias System.getenv("KEYALIAS") keyPassword System.getenv("KEYPWD") storeFile file('release.jks') storePassword System.getenv("KSTOREPWD") } } ... }
  1. KEYALIAS指的是環境變量的變量名,System.getenv("KEYALIAS")的讀取變量名對應的變量值,如圖:
    讀取環境變量值

  2. KEYPWD,按照上圖的方式添加,以下圖:
    添加KEYPWD環境變量

  3. KSTOREPWD以一樣的方式,以下圖:
    添加KSTOREPWD環境變量

須要特別注意的是:第二種自定義簽名的方式,須要先檢查Android Studio是否已配置了gradle工具的環境變量,打開Android Studio的terminal窗口,輸入:gradle build,以下圖:

檢查gradle環境變量

若是,你的terminal窗口提示gradle不是內部命令,操做上述步驟以前,你得添加gradle工具的環境變量,Android Studio的gradle工具默認存放路徑:

C:\Program Files\Android\Android Studio\gradle\gradle-3.2

配置gradle的環境變量,以下圖:

添加gradle根目錄

添加gradle到path變量中

3、兩種構建類型的區別

每個APP至少包含debugrelease兩種構建類型,debug定義APP的調試版本,debug模式的幾個特色:

  1. 支持斷點調試和log信息打印,debuggable屬性值爲true
  2. 使用系統默認的密鑰庫簽署apk文件
  3. 沒有對apk文件進行代碼和資源文件的優化(包括文件壓縮、冗餘文件刪除)
  4. 沒有對代碼進行混淆

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模式須要注意的幾個特色:

  1. 不支持斷點調試,debuggable默認爲false
  2. 沒有壓縮類文件代碼,minifyEnabled,默認爲false
  3. 沒有壓縮資源文件,shrinkResources,默認爲false
  4. 沒有指定自定義簽名文件,默認使用系統的密鑰庫簽署apk

開發者在發佈應用程序時,須要對release模式下的屬性配置進行修改,優化apk文件,刪除無用的代碼和資源文件,混淆類文件和資源名稱,自定義簽名密鑰庫,代碼以下:

release { shrinkResources true minifyEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config }

總結:debugrelease模式,最大的區別默認屬性配置不同,兩種模式支持的屬性配置還包括,以下圖:

debug和release相關配置

debug和release相關配置

記不住代碼的同窗,能夠選中Build Types定義的模式,在可選項中改變對應屬性配置,Android Studio運行時簽名的實質將debug模式下的Signing Config設置爲自定義密鑰庫文件,可是TeachCourse隨着不斷深刻學習後發現,其實debug模式下配置Signing Config畫蛇添足,而只要在release模式下配置Signing Config就夠了,Android Studio的能夠方便爲咱們生成兩種模式下對應的apk文件,在Android Studio的左下角Build Variant中切換,以下圖:

切換debug或release構建類型

下面介紹了產品偏好配置後,回頭再看看它們二者之間的關係。

4、爲何要定製產品的偏好配置?

什麼是產品的偏好配置呢?好比說,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個變體,一個產品包含debugrelease兩個版本,構建類型和偏好產品之間的關係是:一個偏好產品,確定包含一個debug版本和一個release版本,能夠生成變體的總數爲flavors*2,選中須要調試的版本或選中須要發佈的版本,Android Studio自動從新構建Android項目,就能夠針對指定的產品進行調試或打包,很是的方便吧!

偏好產品相關配置,以下圖:

產品偏好配置

defaultConfig也屬於其中一種偏好產品,在咱們沒有定義本身的偏好產品時,咱們構建和編譯的就是默認的defaultConfig這個產品,也就只包含debugrelease兩個變體。

5、怎麼才能加快DEX文件的生成速度?

你有沒有遇到Android Studio在每次構建的時候,都感受花好長時間,TeachCourse就不止一次和同事抱怨說,Android Studio的編譯速度還不如Eclipse快,蝸牛的速度真受不了呀?那該怎麼辦呢?

Android Studio提供dexOption區塊以便於咱們配置DEX構建屬性,加快DEX文件的生成速度,代碼以下:

dexOptions { preDexLibraries true maxProcessCount 8 javaMaxHeapSize "2048m" }
  • preDexLibraries聲明是否預先編譯依賴庫,從而加快構建速度,實質是經過延時清除已生成的依賴庫的構建文件,從而提升構建速度,根據使用狀況合理配置。
  • maxProcessCount設置進程運行過程當中可使用的最大線程數。默認值爲4。
  • javaMaxHeapSize設置DEX編譯器的最大堆大小,堆或者棧都是用於存放暫時不用的垃圾,當內存不足時,垃圾回收機制會清除過期的緩存,堆大小決定垃圾清除的頻率,影響着構建的速度

6、爲何要將一個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中經過<compatible-screens>注入到每個apk文件中,即apk文件只能安裝到<compatible-screens>指定尺寸的手機上

按照上面在build.gradle配置完成後,點擊Build APK後,將在apk文件夾內生成多個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介紹,參考下面鏈接:

https://developer.android.google.cn/ndk/guides/abis.html

一樣,點擊Build APK後,將在apk文件夾內生成多個apk文件,以下圖:

按abi拆分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引入依賴項的方式分爲上述四種,按順序依次稱爲:一、模塊依賴項,二、本地二進制依賴項,三、本地二進制依賴項,四、遠程二進制依賴項,五、遠程二進制依賴項

  • compile project(':mylibrary') 行聲明瞭一個名爲mylibrary的本地 Android 庫模塊做爲依賴項,並要求構建系統在構建應用時編譯幷包含該本地模塊。
  • compile files('libs/zxing.jar')compile fileTree(dir: 'libs', include: ['*.jar'])都稱爲本地依賴項,告訴構建系統在編譯類路徑和最終的應用軟件包中包含 app/libs/ 目錄內的指定或所有 JAR 文件。若是您有模塊須要本地二進制依賴項,請將這些依賴項的 JAR 文件複製到項目內部的 中。
  • 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

相關文章
相關標籤/搜索