Android面試題之Gradle配置篇

一隻有交流障礙的醜程式猿發表於2018-05-04

本文是Android面試題整理中的一篇,結合右下角目錄食用更佳

0. Gradle是什麼

  1. Gradle是一個自動化構建工具
  2. 相容Maven等倉庫
  3. 基於Groovy的特定領域語言來宣告名目設定

1. GradleWraper

  1. Gradle Wrapper是一個指令碼檔案
  2. 它會在沒有安裝Gradle的情況下為我們下載Gradle,之後我們就可以使用gradlew命令,像使用gradle一樣來使用Gradle了
  3. GradleWraper簡化了gradle的安裝部署

2. Gradle檔案結構

  1. settings.gradle:整個Project的配置檔案,可以設定包含哪些module
  2. build.gradle (Project的gradle檔案):整個Project的配置檔案
  3. build.gradle(Module):Module的配置檔案
  4. gradle.properties:可以在 gradle.properties 檔案中配置一些變數

3. Gradle命令

  1. gradlew clean: 清除app目錄下的build資料夾
  2. gradlew check: 執行lint檢查
  3. gradlew assemble:打release和debug包
  4. gradlew build : 執行check和assemble
  5. gradlew assembleRelease/gradlew assembleDebug:打全部渠道的Release或者debug包

4. Gradle常見配置

指定倉庫

repositories {
        jcenter()
    }
複製程式碼

指定依賴

dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }
複製程式碼

設定指令碼的執行環境

buildscript{}
複製程式碼

宣告引用的外掛

apply plugin: 'com.android.application'

複製程式碼

設定編譯android專案的引數

android {
    // 編譯SDK的版本
    compileSdkVersion 22
    // build tools的版本
    buildToolsVersion "23.0.1"

    //aapt配置
    aaptOptions {
        //不用壓縮的檔案
        noCompress 'pak', 'dat', 'bin', 'notice'
        //打包時候要忽略的檔案
        ignoreAssetsPattern "!.svn:!.git"
        //分包
        multiDexEnabled true
        //--extra-packages是為資原始檔設定別名:意思是通過該應用包名+R,com.android.test1.R和com.android.test2.R都可以訪問到資源
        additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
    }

    //預設配置
    defaultConfig {
        //應用的包名
        applicationId "com.example.heqiang.androiddemo"
        minSdkVersion 21
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }

    //編譯配置
    compileOptions {
        // java版本
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

    //原始檔目錄設定
    sourceSets {
        main {
             //jni lib的位置
             jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
             //定義多個資原始檔夾,這種情況下,兩個資原始檔夾具有相同優先順序,即如果一個資源在兩個資料夾都宣告瞭,合併會報錯。
             res.srcDirs = ['src/main/res', 'src/main/res2']
             //指定多個原始檔目錄
             java.srcDirs = ['src/main/java', 'src/main/aidl']
        }
    }

    //簽名配置
    signingConfigs {
        debug {
            keyAlias 'androiddebugkey'
            keyPassword 'android'
            storeFile file('keystore/debug.keystore')
            storePassword 'android'
        }
    }

    buildTypes {
        //release版本配置
        release {
            debuggable false
            // 是否進行混淆
            minifyEnabled true
            //去除沒有用到的資原始檔,要求minifyEnabled為true才生效
            shrinkResources true
            // 混淆檔案的位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            signingConfig signingConfigs.debug
            //ndk的一些相關配置,也可以放到defaultConfig裡面。
            //指定要ndk需要相容的架構(這樣其他依賴包裡mips,x86,arm-v8之類的so會被過濾掉)
            ndk {
                abiFilter "armeabi"
            }
        }
        //debug版本配置
        debug {
            debuggable true
            // 是否進行混淆
            minifyEnabled false
            //去除沒有用到的資原始檔,要求minifyEnabled為true才生效
            shrinkResources true
            // 混淆檔案的位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            signingConfig signingConfigs.debug
            //ndk的一些相關配置,也可以放到defaultConfig裡面。
            //指定要ndk需要相容的架構(這樣其他依賴包裡mips,x86,arm-v8之類的so會被過濾掉)
            ndk {
                abiFilter "armeabi"
            }
        }
    }
    // lint配置 
    lintOptions {
      //移除lint檢查的error
      abortOnError false
      //禁止掉某些lint檢查
      disable 'NewApi'
    }
}

複製程式碼

android中還可以有以下配置: productFlavors{ } 產品風格配置,ProductFlavor型別;testOptions{ } 測試配置,TestOptions型別; dexOptions{ } dex配置,DexOptions型別;packagingOptions{ } PackagingOptions型別;jacoco{ } JacocoExtension型別。 用於設定 jacoco版本;splits{ } Splits型別。

5. 幾種依賴的區別

  1. compile:我們最常用的依賴,編譯時提供並打包進apk
  2. provided:編譯時提供但不打包進apk
  3. 在gradlew 3.0 中complie過期了,用implementation和api替代
  4. api = compile
  5. implemention:將該依賴隱藏在內部,而不對外部公開

6. 為什麼會有兩套repositories和dependencies

  1. buildscript裡面的那個是外掛初始化環境用的,用於設定外掛的下載倉庫
  2. android 中是工程依賴的一些模組和遠端library的下載倉庫的

7. 排除依賴傳遞,解決依賴衝突

  1. exclude: 設定不編譯指定的模組,排除指定模組的依賴
  2. transitive:用於自動處理子依賴項,預設為true,gradle自動新增子依賴項。設定為false排除所有的傳遞依賴
  3. force:強制設定某個模組的版本。

8. Gradle打包時的Proguard

  1. 通過在buildTypes中配置minifyEnable來開啟和關閉proguard
  2. 通過proguardFiles 來配置混淆引數與keep的內容
  3. 混淆的作用:
    1. 壓縮(Shrink):檢測並移除程式碼中無用的類、欄位、方法和特性(Attribute)。
    2. 優化(Optimize):對位元組碼進行優化,移除無用的指令。
    3. 混淆(Obfuscate):使用a,b,c,d這樣簡短而無意義的名稱,對類、欄位和方法進行重新命名。
    4. 預檢(Preveirfy):在Java平臺上對處理後的程式碼進行預檢,確保載入的class檔案是可執行的。

9. 依賴中的動態版本宣告

dependencies {
    //依賴最新的1.x版本
    compile "org.codehaus.cargo:cargo-ant:1.+"
}
複製程式碼

10. 多渠道打包1

  1. 在AndroidManifest.xml配置mete-data
<meta-data
    android:name="UMENG_CHANNEL"
    android:value="Channel_ID" />
複製程式碼
  1. 配置Flavors:

android {  
    productFlavors {
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        _360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
        }
        baidu {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
        }
        wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }
    }  
}

    
或者批量修改

android {  
    productFlavors {
        xiaomi {}
        _360 {}
        baidu {}
        wandoujia {}
    }  

    productFlavors.all { 
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }
}

複製程式碼
  1. 在APP內讀取 mete-data 配置確定渠道
  2. 然後用 ./gradlew assembleRelease 這條命令會把Product Flavor下的所有渠道的Release版本都打出來。

11. 多渠道打包2

  1. 因為以上方法需要多次編譯,速度較慢,當渠道變多之後不適合多渠道打包
  2. 改進的方法1 : apk反編譯後重寫AndroidManifest檔案,再重新編譯簽名
  3. 改進的方法2 : 如果在META-INF目錄內新增空檔案,可以不用重新簽名應用。因此,通過為不同渠道的應用新增不同的空檔案,可以唯一標識一個渠道

12. 多渠道打包3

  1. 在採用V2簽名後,以上方法不再適用
  2. 考慮到V2簽名的特點(對APK Signing Block是不進行驗證的),我們向V2簽名後的APK簽名區塊寫入渠道號,實現多渠道打包

15. 其他用途

因為v1簽名可以在不改變簽名情況下二次打包,我們可以在gradle中對dex檔案進行自己的簽名

16. 哪些不做混淆

  1. Android系統元件
  2. JNI
  3. 反射
  4. WebView的JS呼叫
  5. 內部類
  6. Annottation
  7. enum
  8. 範型
  9. 序列化
  10. 第三方

17. Gradle 生命週期

  1. 初始化階段:會去讀取根工程中setting.gradle中的include資訊,決定有哪幾個工程加入構建, 建立project例項,比如下面有三個工程: include ':app', ':lib1', ':lib2
  2. 配置階段:,會去執行所有工程的build.gradle指令碼,配置project物件,一個物件由多個任務組成, 此階段也會去建立、配置task及相關資訊。
  3. 執行階段:根據gradle命令傳遞過來的task名稱,執行相關依賴任務

18. 如何通過Gradle配置差異較大(20%差異)的多渠道包

通過配置productFlavors,將區別程式碼放置在對應的問價下,gradle會自動打出相應包

相關文章