Gradle for Android ( 構建變體 )

来源:https://www.cnblogs.com/tangZH/archive/2019/06/21/10999060.html
-Advertisement-
Play Games

有時候我們一個app需要有不同的版本,不同的版本又會使用不同的配置,我們可以使用gradle進行管理。 Build types Product flavors Build variants Signing configurations 一、構建版本Build types: 常見的構建版本有debug ...


有時候我們一個app需要有不同的版本,不同的版本又會使用不同的配置,我們可以使用gradle進行管理。


  • Build types
  • Product flavors
  • Build variants
  • Signing configurations

 


 

一、構建版本Build types:

常見的構建版本有debug與release。

buildTypes {
 release {
   minifyEnabled false
   proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
 }
}

 

自定義構建版本:

custom {
    applicationIdSuffix ".custom"
    versionNameSuffix ".custom"
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.readerDaquanConfig
}

除了debug構建版本不需要簽名外,其它的都是需要配置簽名的,不然無法運行在手機上,該版本定義了新的applicationId與版本號。不同構建版本的applicationId如下:

  • Debug: com.package
  • Release: com.package
  • Staging: com.package.staging

 

也可以採用繼承的方式:

custom.initWith(buildTypes.debug)
custom {
   applicationIdSuffix ".custom"
   versionNameSuffix ".custom"
   minifyEnabled false
   proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
   signingConfig signingConfigs.readerDaquanConfig
}

custom繼承debug構建版本的配置,custom中的配置會覆蓋debug的配置。

 

在BuildConfig中添加變數

custom {
applicationIdSuffix ".custom"
versionNameSuffix ".custom"
buildConfigField("String", "name","\"custom app\"")
buildConfigField("int", "id", "0")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.readerDaquanConfig
}

之後我們可以看到:

註意如果要添加的是String,那麼雙一號裡面需要再一個雙引號標識字元串"\"custom app\"",斜桿是對裡面雙引號進行轉義。

 

Source sets

當創建了一個新的build type之後,Gradle也會創建一個新的source set。預設的source set目錄會放在相同的Build Type的目錄下。當你創建一個新的build type時,該目錄不會自動創建,你必須在你使用代碼與資源前自己為每一個build type創建source set目錄。 三種buildType的目錄結構如下:
app
└── src
├── debug
│ ├── java
│ │   └── com.package
│ ├── res
│ │ └── layout
│ │       └── activity_main.xml
│ └── AndroidManifest.xml
├── main
│ ├── java
│ │   └── com.package
│ ├── res
└── MainActivity.java
└── Constants.java
│ └── AndroidManifest.xml
├── custom
│ ├── java
│ │   └── com.package
├── drawable
└── layout
└── activity_main.xml
│ ├── res
│ │ └── layout
│ │       └── activity_main.xml
│ └── AndroidManifest.xml
└── release
    ├── java
    │   └── com.package
    │       └── Constants.java
    └── AndroidManifest.xml

假如我們自己建立custom的source set 

 

我們使用不同的構建版本便會使用不同的source set。當使用不同的source sets的時候,資源文件的處理需要特殊的方式。Drawables和layout文件將會覆寫在main中的重名文件,但是values文件下的資源不會。gradle將會把這些資源連同main裡面的資源一起合併。(如果出現資源重覆異常,請clean一下工程)

例如,在main中的string.xml為:

<resources>
    <string name="app_name">BuildTypeProject</string>
    <string name="hello_name">BuildTypeHello</string>
</resources>

在custom版本中為:

<resources>
    <string name="app_name">BuildTypeCustomProject</string>
</resources>

當我們構建custom版本的時會合併為:

<resources>
    <string name="app_name">BuildTypeCustomProject</string>
    <string name="hello_name">BuildTypeHello</string>
</resources>

當你創建一個新的構建版本而不是custom,最終的strings.xml將會是main目錄下的strings.xml。

manifest也和value文件下的文件一樣。如果你為你的構建版本創建了一個manifest文件,那麼你不必要去拷貝在main文件下的manifest文件,你需要做的是添加標簽。Android插件將會為你合併它們。

 

但是需要註意,當我們添加.java文件到custom版本中,你可以添加相同的類到debug和release版本,但是不能添加到main版本。如果你添加了,會拋出異常。這時候我們如果構建custom版本,那麼便會使用custom對應source set中的.java文件。

 


 

依賴包

每一個構建版本都有自己的依賴包,gradle自動為每一個構建的版本創建不同的依賴配置。如果你想為debug版本添加一個logging框架,你可以這麼做:

dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   compile 'com.android.support:appcompat-v7:22.2.0'
   debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}

 


product flavors

不同的生產版本。

product flavors極大簡化了基於相同的代碼構建不同版本的app。

創建product flavors

 

android {
    productFlavors {
       vivo {
            applicationId "vivo"
            versionCode 1
            minSdkVersion 15
        }
        oppo {
            applicationId "oppo"
            versionCode 2
            minSdkVersion 15
        }
    }
}

這時候AS 3.0以上會報錯ERROR: All flavors must now belong to a named flavor dimension

沒有給它們設置一個風味維度,我們可以加上

flavorDimensions "default"

flavorDimensions "default"
android {
    productFlavors {
       vivo {
            applicationId "vivo"
            versionCode 1
            minSdkVersion 15
        }
        oppo {
            applicationId "oppo"
            versionCode 2
            minSdkVersion 15
        }
    }
}

給這些產品版本預設一個風味維度,具體有何作用,等會會講。

 

這時候我們會在左下角的視窗看到這麼多個變體:

 

如果找不到該視窗,可以在這裡打開:

 由於我們之前在custom構建版本上設置了applicationIdSuffix ".custom",所以,當我們運行oppoCustom版本的時候,applicationId為oppo.custom

 

Source Set

product Flavors也有自己的代碼文件夾。創建一個特殊的版本就像創建一個文件夾那麼簡單。如下圖所示:

但是值得註意的是,我們無法再vivo文件夾里相同的包中添加構建版本已經有的.java文件,添加了會報異常。而對於資源文件,我們可以添加構建版本裡面有的文件,但是這個產品版本所對應的目錄的優先順序低於Build type,也就是說,當Custom目錄有一張圖片,vivo目錄也有一張圖片,那麼當我們運行打包vivoCustom版本的時候,使用的是custom裡面的圖片。除非我們建立的文件夾是vivoCustom,那麼它的優先順序便會是最高的。

 

Multiflavor variants

在某些情況下,你可能希望創建一些聯合的Product Flavors,這個時候便要使用到我們剛剛所說的flavorDimensions 了。

設想一下,假如我們需要打包兩個渠道的app:vivo和oppo,而這兩個渠道的app各自有付費版與免費版,那麼我們就需要用到多維度了。

 

首先定義兩個維度:渠道channel,付費與免費:money

flavorDimensions "channel","money"

flavorDimensions "channel","money"
android {
    productFlavors {
       vivo {
            dimension "channel"
            applicationId "vivo"
            versionCode 1
            minSdkVersion 15
        }
        oppo {
            dimension "channel"
            applicationId "oppo"
            versionCode 2
            minSdkVersion 15
        }
        free {
            dimension "money"
        }
        vip {
            dimension "money"
        }
    }
}

當你添加了flavor dimensions,你就需要為每個flavor添加dimension,否則會提示錯誤。

之後我們可以看到這麼多個變體:

 

 而我們定義多個維度的順序是很重要的,因為當你在各個維度各自定義了同一個常量的值,比如:buildConfigField("String", "name","\"custom app\""),總是以第一維度的為準。

 


 

Build variants

構建變體

構建變體是構建版本和生產版本的結合體。當你創建了一個構建版本或者生產版本,同樣的,新的變體也會被創建。

像我們上圖便有這麼多的變體:

 

我們可以在這個視窗進行切換,然後運行不同的變體。

tasks

Android Plugin會為每一個配置的Build Variant創建Tasks。一個新的Android App擁有Debug和Release兩種Build Types,所以預設的就會有兩個Task,一個是assembleDebug一個是assembleRelease來構建不同的APK。當添加一個新的Build Type的時候,一個新的Task也就會被創建,一旦你開始添加Flavors,一整套Tasks就會被創建,因為每一個BuildType的Tasks都會為每個Product Flavor聯合。  

Source sets

構建變體也可以有自己的資源文件夾,舉個例子,你可以有src/vivoVipCustom/java/。原理與上面的類似


 

Resource and mainfest merging

Android Plugin需要在打包前對Main的SourceSet以及BuildType的SourceSet進行一次Merge。而且Library工程也會提供額外的資源,它們也會被Merge,例如Manifest.xml等等。也會在其中聲明一些許可權等。

Resource和Manifest.xml的優先順序順序如下:

如果一個資源在main中和在flavor中定義了,那麼那個在flavor中的資源有更高的優先順序。這樣那個在flavor文件夾中的資源將會被打包到apk。而在依賴項目申明的資源總是擁有最低優先順序。

 

當然,如果你建立的目錄是變體的目錄入:vivoVipCustom,那麼它的優先順序自然是高於Build type


 

創建構建變體

關於如何構建變數,上面已經說了,不再重覆。

 

flavorDimensions "channel","money"
android {
    productFlavors {
       vivo {
            dimension "channel"
            applicationId "vivo"
            versionCode 1
            minSdkVersion 15
        }
        oppo {
            dimension "channel"
            applicationId "oppo"
            versionCode 2
            minSdkVersion 15
        }
        free {
            dimension "money"
            resValue "color", "colorfree", "#ff8888"
        }
        vip {
            dimension "money"
            resValue "color", "colorfree", "#ff0000"
        }
    }
}

 

resValue "color", "colorfree", "#ff8888"表示添加顏色名為colorfree的顏色


變體過濾器

忽略某個變體也是可行的。這樣你可以加速你的構建當使用assemble的時候,這樣你列出的tasks將不會執行那麼你不需要的變體。你可以使用過濾器,在build.gradle中添加代碼如下所示:

android.variantFilter { variant ->
    if(variant.buildType.name.equals('release')) {
        variant.getFlavors().each() { flavor ->
            if (flavor.name.equals('vivo')) { variant.setIgnore(true);
            }
        }
    }
}

發現相關的變體不見了:

 


Signing Configurations


在你發佈你的應用之前,你需要為你的app私鑰簽名。如果你有付費版和免費版,你需要有不同的key去簽名不同的變體。這就是配置簽名的好處。配置簽名可以這樣定義:

 

android {
       signingConfigs {
           custom.initWith(signingConfigs.debug)
           release {
               storeFile file("release.keystore")
               storePassword"secretpassword"
               keyAlias "gradleforandroid"
               keyPassword "secretpassword"
           }
      }
}

在這個例子中,我們創建了2個不同的簽名配置。debug配置是as預設的,其使用了公共的keystore和password,所以沒有必要為debug版本創建簽名配置了。custom配置使用了initWith()方法,其會複製其他的簽名配置。這意味著custom和debug的key是一樣的。

release配置使用了storeFile,定義了key alias和密碼。當然這不是一個好的選擇,你需要在 Gradle properties文件中配置。

 

當你定義了簽名配置後,你需要應用它們。構建版本都有一個屬性叫做signingConfig,你可以這麼乾:

android {
       buildTypes {
           release {
               signingConfig signingConfigs.release
           } 
       }
}

 

上例使用了buildTypes,但是你可能需要對每個版本生成不同的驗證,你可以這麼定義:

android {
       productFlavors {
           vivo{
               signingConfig signingConfigs.release
           }
       }
}

 

當簽名一個Flavor版本的時候,你需要重寫BuildType中的簽名配置。當需要使用相同的BuildType不同版本的Flavors的簽名時,可以通過下述方式:

android {
       buildTypes {
           release {
               productFlavors.vivo.signingConfig signingConfigs.vivo
               productFlavors.oppo.signingConfig signingConfigs.oppo
           } 
       }
}

上面這個例子展示瞭如何在vivo和oppo的Release版本使用不同的簽名,但是卻不影響Debug和Custom的BuildType。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 問題:生產環境的資料庫可能比較大,如果直接進行全備而不壓縮的話,備份集就會占用了大量磁碟空間。給備份文件的存放管理帶來不便。 解決方案:通過with compression顯式啟用備份壓縮,指定對此備份執行備份壓縮,覆蓋伺服器級預設設置。適用於 SQL Server 2008和更高版本。因為相同數據 ...
  • 給定一個 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。 (例如,將所有 f 值更改為 m,反之亦然)。 要求只使用一個更新(Update)語句,並且沒有中間的臨時表。 註意,您必只能寫一個 Update 語句,請不要編寫任何 Select 語句。 例如 : 運行你所編寫的更 ...
  • 第一部分 Telegraf 部署和配置 Telegraf 是實現 數據採集 的工具。Telegraf 具有記憶體占用小的特點,通過插件系統開發人員可輕鬆添加支持其他服務的擴展。 在平臺監控系統中,可以使用 Telegraf 採集多種組件的運行信息,而不需要自己手寫腳本定時採集,大大降低數據獲取的難度; ...
  • 多行文本換行: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- -- Author: Insus.NET -- Create date: 2019-06-21 -- Update date: 2019-06-21 -- Description: ...
  • mysql5.0.3以後,n都表示字元數(varchar(n)) 檢索效率 char varchar text 當varchar長度超過255之後,跟text一致,但是設置varchar(n)的話,可以防止惡意使用text撐爆資料庫 |類型名稱|說明|存儲需求| | | | | |CHAR ...
  • 都知道大數據薪資高,前景好。而大數據又需要Java基礎。對於稍微懂些Java的童鞋來說,到底如何轉行大數據呢?今天小編給你一個大數據工程師具體的學習路線圖。【ps:無java基礎也可以學習大數據】 ...
  • 編寫一個 SQL 查詢,查找 Person 表中所有重覆的電子郵箱。 示例 : 根據以上輸入,你的查詢應返回以下結果: 說明 :所有電子郵箱都是小寫字母。 題解: 方法一 :使用 和臨時表 演算法 重覆的電子郵箱存在多次。要計算每封電子郵件的存在次數,我們可以使用以下代碼。 以此作為臨時表,我們可以得 ...
  •   手持小米9,之前更新了新版本的Magisk Manager之後,發現手機再打開會一直卡在進入界面無法啟動(如下圖顯示)   逛了逛Github、XDA、Stack Overflow等論壇,大致結論是Magisk Manager自身的問題,軟體更新導致打不開 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...