Gradle for Android

第四篇( 構(gòu)建變體 )

當(dāng)你在開發(fā)一個(gè)app,通常你會(huì)有幾個(gè)版本每界。大多數(shù)情況是你需要一個(gè)開發(fā)版本焦履,用來測試app和弄清它的質(zhì)量,然后還需要一個(gè)生產(chǎn)版本忽洛。這些版本通常有不同的設(shè)置绘面,例如不同的URL地址欺税。更可能的是你可能需要一個(gè)免費(fèi)版和收費(fèi)版本〗伊В基于上述情況晚凿,你需要處理不同的版本:開發(fā)免費(fèi)版,開發(fā)付費(fèi)版本瘦馍,生產(chǎn)免費(fèi)版歼秽,生產(chǎn)付費(fèi)版,而針對不同的版本不同的配置情组,這極大增加的管理難度燥筷。

Gradle有一些方便的方法來管理這些問題。我們很早之前談過debug和release版本院崇,現(xiàn)在我們談到另外一個(gè)概念肆氓,不同的產(chǎn)品版本。構(gòu)建版本和生產(chǎn)版本通车装辏可以合并谢揪,構(gòu)建版本和生產(chǎn)版本的合并版叫做構(gòu)建變種。

這一章我們將學(xué)習(xí)構(gòu)建版本捐凭,它能使得開發(fā)更有效率拨扶,并且學(xué)習(xí)如何使用它們。然后我們會(huì)討論構(gòu)建版本和生產(chǎn)版本的不同茁肠,以及如何將其合并患民。我們會(huì)探討簽名機(jī)制,如何針對不同的變種簽名等垦梆。

在這一章匹颤,我們遵循如下規(guī)則:

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

構(gòu)建版本

在Gradle的Android插件中仅孩,一個(gè)構(gòu)建版本意味著定義一個(gè)app或者依賴庫如何被構(gòu)建。每個(gè)構(gòu)建版本都要特殊的一面惋嚎,比如是否需要debug杠氢,application id是什么站刑,是否不需要的資源被刪除等等另伍。你可以定義一個(gè)構(gòu)建版本通過buildTypes方法。例如:

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

這個(gè)文件定義了該模塊是release版本绞旅,然后定義了proguard的位置摆尝。該release版本不是唯一的構(gòu)建版本,默認(rèn)情況下因悲,還有個(gè)debug版本堕汞。Android studio把它視為默認(rèn)構(gòu)建版本。

創(chuàng)建自己的構(gòu)建版本

當(dāng)默認(rèn)的構(gòu)建版本不夠用的時(shí)候晃琳,創(chuàng)建版本也是很容易的一件事讯检,創(chuàng)建構(gòu)建版本你只需要在buildTypes寫入自己的版本。如下所示:

android { 
       buildTypes { 
           staging { 
               applicationIdSuffix ".staging" 
               versionNameSuffix "-staging" 
               buildConfigField "String", 
                  "API_URL", "\"http://staging.example.com/api\"" 
            } 
       }
 }

我們定義了一個(gè)staging版本卫旱,該版本定義了一個(gè)新的application id人灼,這讓其與debug和release版本的applicationID不同。假設(shè)你使用了默認(rèn)的配置顾翼,那么applicationID將會(huì)是這樣的:

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

這意味著你可以在你的設(shè)備上安裝staging版本和release版本投放。staging版本也有自己的版本號(hào)。buildConfigField定義了一個(gè)新的URL地址适贸。你不必事事都去創(chuàng)建灸芳,所以最可能的方式是去繼承已有的版本。

android { 
    buildTypes { 
        staging.initWith(buildTypes.debug) 
        staging { 
            applicationIdSuffix ".staging" 
            versionNameSuffix "-staging" 
            debuggable = false 
        } 
    }
}

initWith()方法創(chuàng)建了一個(gè)新的版本的同時(shí)拜姿,復(fù)制所有存在的構(gòu)建版本烙样,類似繼承。我們也可以復(fù)寫該存在版本的所有屬性蕊肥。

Source sets

當(dāng)你創(chuàng)建了一個(gè)新的構(gòu)建版本谒获,Gradle也創(chuàng)建了新的source set。默認(rèn)情況下晴埂,該文件夾不會(huì)自動(dòng)為你創(chuàng)建究反,所有你需要手工創(chuàng)建。

 app
└── src
├── debug
│ ├── java 
    │ │ └── com.package 
    │ │
│ ├── res
│ │ └── layout
│         │ └── activity_main.xml│ └── AndroidManifest.xml├── main│ ├── java│ │ └── com.package│ ││ ├── res└── MainActivity.java└── Constants.java│ ││ ││ ││ └── AndroidManifest.xml├── staging│ ├── java│ │ └── com.package├── drawable└── layout└── activity_main.xml│ ││ ├── res│ │ └── layout│ │ └── activity_main.xml│ └── AndroidManifest.xml└── release ├── java │ └── com.package │ └── Constants.java └── AndroidManifest.xml 

注意:當(dāng)你添加一個(gè)Java類的時(shí)候儒洛,你需要知道以下過程精耐,當(dāng)你添加了CustomLogic.java到staging版本,你可以添加相同的類到debug和release版本琅锻,但是不能添加到main版本卦停。如果你添加了向胡,會(huì)拋出異常。

當(dāng)使用不同的source sets的時(shí)候惊完,資源文件的處理需要特殊的方式僵芹。Drawables和layout文件將會(huì)復(fù)寫在main中的重名文件,但是values文件下的資源不會(huì)小槐。gradle將會(huì)把這些資源連同main里面的資源一起合并拇派。

舉個(gè)例子,當(dāng)你在main中創(chuàng)建了一個(gè)srings.xml的時(shí)候:

<resources>
    <string name="app_name">TypesAndFlavors</string> 
    <string name="hello_world">Hello world!</string>
</resources>

當(dāng)你在你的staing版本也添加了rings.xml:

<resources> 
   <string name="app_name">TypesAndFlavors STAGING</string>
</resources>

然后合并的strings.xml將會(huì)是這樣的:

<resources> 
    <string name="app_name">TypesAndFlavors STAGING</string> 
    <string name="hello_world">Hello world!</string>
</resources>

當(dāng)你創(chuàng)建一個(gè)新的構(gòu)建版本而不是staging凿跳,最終的strings.xml將會(huì)是main目錄下的strings.xml件豌。
manifest也和value文件下的文件一樣。如果你為你的構(gòu)建版本創(chuàng)建了一個(gè)manifest文件控嗜,那么你不必要去拷貝在main文件下的manifest文件茧彤,你需要做的是添加標(biāo)簽。Android插件將會(huì)為你合并它們疆栏。
我們將在會(huì)之后的章節(jié)講到合并的更多細(xì)節(jié)曾掂。

依賴包

每一個(gè)構(gòu)建版本都有自己的依賴包,gradle自動(dòng)為每一個(gè)構(gòu)建的版本創(chuàng)建不同的依賴配置壁顶。如果你想為debug版本添加一個(gè)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'
}

你可以結(jié)合不同的構(gòu)建版本著不同的構(gòu)建配置,就像這種方式博助,這讓你的不同版本的不同依賴包成為可能险污。

product flavors


和構(gòu)建版本不同,product flavors用來為一個(gè)app創(chuàng)建不同版本富岳。典型的例子是蛔糯,一個(gè)app有付費(fèi)和免費(fèi)版。product flavors極大簡化了基于相同的代碼構(gòu)建不同版本的app窖式。
如果你不確定你是否需要一個(gè)新的構(gòu)建版本或者product flavors蚁飒,你應(yīng)該問你自己,你是否需要內(nèi)部使用和外部使用的apk萝喘。如果你需要一個(gè)完全新的app去發(fā)布淮逻,和之前的版本完全隔離開,那么你需要product flavors阁簸。否則你只是需要構(gòu)建版本爬早。

創(chuàng)建product flavors

創(chuàng)建product flavors非常的容易。你可以在productFlavors中添加代碼:

android { 
     productFlavors {
          red { 
               applicationId 'com.gradleforandroid.red' versionCode 3 
          } 
         blue { 
             applicationId 'com.gradleforandroid.blue' 
             minSdkVersion 14 versionCode 4 
         } 
    }
}

product flavors和構(gòu)建版本的配置不同启妹。因?yàn)閜roduct flavors有自己的ProductFlavor類筛严,就像defaultConfig,這意味著你的所有productFlavors都分享一樣的屬性饶米。

Source sets

就像構(gòu)建版本一樣桨啃,product Flavors也有自己的代碼文件夾车胡。創(chuàng)建一個(gè)特殊的版本就像創(chuàng)建一個(gè)文件夾那么簡單。舉個(gè)例子照瘾,當(dāng)你有的生產(chǎn)版本的blue flavors有一個(gè)不同的app圖標(biāo)匈棘,該文件夾需要被叫做blueRelease。

多個(gè)flavors構(gòu)建變體

在一些例子中析命,你可能需要?jiǎng)?chuàng)建一些product flavors的合并版本主卫。舉個(gè)例子,client A和client B可能都想要一個(gè)free和paid的版本碳却,而他們又都是基于一樣的代碼队秩,但是有不一樣的顏色等笑旺。創(chuàng)建四個(gè)不同的flavors意味著有重復(fù)的配置昼浦。合并flavors最簡單的做法可能是使用flavor dimensions,就像這樣:

android { 
   flavorDimensions "color", "price" 
   productFlavors { 
       red { 
           flavorDimension "color" 
       } 
       blue { 
           flavorDimension "color" 
       } 
       free { 
         flavorDimension "price" 
       } 
       paid { 
         flavorDimension "price" 
       } 
   }
}

當(dāng)你添加了flavor dimensions筒主,你就需要為每個(gè)flavor添加flavorDimension关噪,否則會(huì)提示錯(cuò)誤。flavorDimensions定義了不同的dimensions乌妙,當(dāng)然其順序也很重要使兔。當(dāng)你合并二個(gè)不同的flavors時(shí),他們可能有一樣的配置和資源藤韵。例如上例:

  • blueFreeDebug and blueFreeRelease
  • bluePaidDebug and bluePaidRelease
  • redFreeDebug and redFreeRelease
  • redPaidDebug and redPaidRelease

構(gòu)建變體


構(gòu)建變體是構(gòu)建版本和生產(chǎn)版本的結(jié)合體虐沥。當(dāng)你創(chuàng)建了一個(gè)構(gòu)建版本或者生產(chǎn)版本,同樣的泽艘,新的變體也會(huì)被創(chuàng)建欲险。舉個(gè)例子,當(dāng)你有debug和release版本匹涮,你創(chuàng)建了red和blue的生產(chǎn)版本天试,那么變體將會(huì)有四個(gè):



你可以在Android studio的左下角找到它,或者通過VIEW|Tool Windows|Build Variants打開它然低。該視圖列出了所有的變體喜每,并且允許你去切換它們。改變他們將會(huì)影響到你按Run按鈕雳攘。

如果你沒有product flavors带兜,那么變體只是簡單的包含構(gòu)建版本,就算你沒有定義任何構(gòu)建版本吨灭,Android studio也會(huì)默認(rèn)為你創(chuàng)建debug版本的刚照。

tasks

android插件回味每一個(gè)變體創(chuàng)建不同的配置。一個(gè)新的Android項(xiàng)目會(huì)有debug和release版本沃于,所有你可以使用assembleDebug和assembleRelease涩咖,當(dāng)然當(dāng)你使用assemble命令海诲,會(huì)二者都執(zhí)行。當(dāng)你添加了一個(gè)新的構(gòu)建版本檩互,新的task也會(huì)被創(chuàng)建特幔。例如:

  • assembleBlue uses the blue flavor configuration and assembles both BlueRelease and BlueDebug.
  • assembleBlueDebug combines the flavor configuration with the build type configuration, and the flavor settings override the build type settings.

Source sets

構(gòu)建變體也可以有自己的資源文件夾,舉個(gè)例子闸昨,你可以有src/blueFreeDebug/java/蚯斯。
資源文件和manifest的合并
在打包app之前,Android插件會(huì)合并main中的代碼和構(gòu)建的代碼饵较。當(dāng)然拍嵌,依賴項(xiàng)目也可以提供額外的資源,它們也會(huì)被合并循诉。你可能需要額外的Android權(quán)限針對debug變體横辆。舉個(gè)例子,你不想在main中申明這個(gè)權(quán)限茄猫,因?yàn)檫@可能導(dǎo)致一些問題狈蚤,所以你可以添加一個(gè)額外的mainfest文件在debug的文件夾中,申明額外的權(quán)限划纽。
資源和mainfests的優(yōu)先級(jí)是這樣的:



如果一個(gè)資源在main中和在flavor中定義了脆侮,那么那個(gè)在flavor中的資源有更高的優(yōu)先級(jí)。這樣那個(gè)在flavor文件夾中的資源將會(huì)被打包到apk勇劣。而在依賴項(xiàng)目申明的資源總是擁有最低優(yōu)先級(jí)靖避。

創(chuàng)建構(gòu)建變體

gradle讓處理構(gòu)建變體變得容易。

android { 
    buildTypes { 
        debug { 
            buildConfigField "String", "API_URL", 
              "\"http://test.example.com/api\"" 
        } 
        staging.initWith(android.buildTypes.debug) 
        staging { 
            buildConfigField "String", 
                "API_URL", "\"http://staging.example.com/api\""
           applicationIdSuffix ".staging" 
        }
     } 
    productFlavors { 
        red { 
            applicationId "com.gradleforandroid.red" 
            resValue "color", "flavor_color", "#ff0000" 
        } 
        blue { 
            applicationId "com.gradleforandroid.blue" 
            resValue "color", "flavor_color", "#0000ff" 
        } 
    }
}

在這個(gè)例子中比默,我們創(chuàng)建了4個(gè)變體幻捏,分別是blueDebug,blueStaging退敦,redDebug粘咖,redStaging。每一個(gè)變體都有其不同的api url以及顏色侈百。例如:


變體過濾器

忽略某個(gè)變體也是可行的瓮下。這樣你可以加速你的構(gòu)建當(dāng)使用assemble的時(shí)候,這樣你列出的tasks將不會(huì)執(zhí)行那么你不需要的變體钝域。你可以使用過濾器讽坏,在build.gradle中添加代碼如下所示:

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

在這個(gè)例子中,我們檢查下:



你可以看到blueFreeRelease和bluePaidRelease被排除在外例证,如果你運(yùn)行g(shù)radlew tasks路呜,你會(huì)發(fā)現(xiàn)所有的關(guān)于上述變體的tasks不再存在。

簽名配置

在你發(fā)布你的應(yīng)用之前,你需要為你的app私鑰簽名胀葱。如果你有付費(fèi)版和免費(fèi)版漠秋,你需要有不同的key去簽名不同的變體。這就是配置簽名的好處抵屿。配置簽名可以這樣定義:

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

在這個(gè)例子中庆锦,我們創(chuàng)建了2個(gè)不同的簽名配置。debug配置是as默認(rèn)的轧葛,其使用了公共的keystore和password搂抒,所以沒有必要為debug版本創(chuàng)建簽名配置了。staging配置使用了initWith()方法尿扯,其會(huì)復(fù)制其他的簽名配置求晶。這意味著staging和debug的key是一樣的。

release配置使用了storeFile衷笋,定義了key alias和密碼芳杏。當(dāng)然這不是一個(gè)好的選擇,你需要在 Gradle properties文件中配置右莱。
當(dāng)你定義了簽名配置后蚜锨,你需要應(yīng)用它們。構(gòu)建版本都有一個(gè)屬性叫做signingConfig慢蜓,你可以這么干:

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

上例使用了buildTypes,但是你可能需要對每個(gè)版本生成不同的驗(yàn)證郭膛,你可以這么定義:

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

當(dāng)然晨抡,你在flavor中定義這些,最好會(huì)被重寫则剃,所以最好的做法是:

android { 
    buildTypes { 
        release { 
            productFlavors.red.signingConfig signingConfigs.red 
            productFlavors.blue.signingConfig signingConfigs.blue 
        } 
     }
}

總結(jié)

在這一章耘柱,我們討論了構(gòu)建版本和生產(chǎn)版本,以及如何結(jié)合它們棍现。這將會(huì)是非常有用的工具调煎,當(dāng)你需要不同的url以及不同的keys,而你們有相同的代碼和資源文件己肮,但是有不同的類型以及版本士袄,構(gòu)建版本和生產(chǎn)版本將會(huì)讓你的生活更美好。
我們也談?wù)摿撕灻渲靡约叭绾问褂盟麄儭?br> 下一章谎僻,你將會(huì)學(xué)習(xí)到多模塊構(gòu)建娄柳,因?yàn)楫?dāng)你想把你的代碼分成一個(gè)依賴包或者依賴項(xiàng)目的時(shí)候,或者你想把Android wear模塊放在你的應(yīng)用的時(shí)候艘绍,這將非常重要赤拒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挎挖,更是在濱河造成了極大的恐慌这敬,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕉朵,死亡現(xiàn)場離奇詭異鹅颊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)墓造,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門堪伍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人觅闽,你說我怎么就攤上這事帝雇。” “怎么了蛉拙?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵尸闸,是天一觀的道長。 經(jīng)常有香客問我孕锄,道長吮廉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任畸肆,我火速辦了婚禮宦芦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘轴脐。我一直安慰自己调卑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布大咱。 她就那樣靜靜地躺著恬涧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碴巾。 梳的紋絲不亂的頭發(fā)上溯捆,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機(jī)與錄音厦瓢,去河邊找鬼提揍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛旷痕,可吹牛的內(nèi)容都是我干的碳锈。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼欺抗,長吁一口氣:“原來是場噩夢啊……” “哼售碳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤贸人,失蹤者是張志新(化名)和其女友劉穎间景,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺智,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倘要,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了十拣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片封拧。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夭问,靈堂內(nèi)的尸體忽然破棺而出泽西,到底是詐尸還是另有隱情,我是刑警寧澤缰趋,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布捧杉,位于F島的核電站,受9級(jí)特大地震影響秘血,放射性物質(zhì)發(fā)生泄漏味抖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一灰粮、第九天 我趴在偏房一處隱蔽的房頂上張望仔涩。 院中可真熱鬧,春花似錦谋竖、人聲如沸红柱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至韧骗,卻和暖如春嘉抒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袍暴。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工些侍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人政模。 一個(gè)月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓岗宣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親淋样。 傳聞我的和親對象是個(gè)殘疾皇子耗式,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 開發(fā)應(yīng)用時(shí), 通常會(huì)有幾個(gè)不同的版本。最常見的是有一個(gè)測試用的臨時(shí)版本和一個(gè)生產(chǎn)版本刊咳。這些版本通常有不同的設(shè)置彪见,比...
    sollian閱讀 2,382評論 0 2
  • 當(dāng)你在開發(fā)一個(gè)app,通常你會(huì)有幾個(gè)版本。大多數(shù)情況是你需要一個(gè)開發(fā)版本娱挨,用來測試app和弄清它的質(zhì)量余指,然后還需要...
    justCode_閱讀 436評論 0 2
  • 當(dāng)你在開發(fā)一個(gè)app,通常你會(huì)有幾個(gè)版本。大多數(shù)情況是你需要一個(gè)開發(fā)版本跷坝,用來測試app和弄清它的質(zhì)量酵镜,然后還需要...
    雪殘閱讀 408評論 0 0
  • 現(xiàn)在你已經(jīng)知道了Gradle是如何工作的,如何創(chuàng)建你自己的任務(wù)和插件柴钻,如何運(yùn)行測試淮韭,以及如何設(shè)置持續(xù)集成,你差不多...
    sollian閱讀 1,099評論 0 5
  • 秋風(fēng)攜著剪刀顿颅, 悄悄溜進(jìn)樹林缸濒, 我見一片樹葉, 從空中優(yōu)雅的落下粱腻。 我捧在手中庇配, 覓覽她昨日的姿色? 方知春夏秋冬...
    喜亭_bf8f閱讀 190評論 5 7