Android應用構(gòu)建-BuildType ProductFlavor

個人原創(chuàng),歡迎指正

場景:

用同一套核心代碼來維護多個訂制的app
現(xiàn)開發(fā)出一套Android app一疯, 在此app基礎上撼玄,復制出另一個app, 兩個app之間略微有一些不同之處墩邀。
將不同環(huán)境的APP安裝在同一設備中掌猛。

使用Gradle構(gòu)建的優(yōu)點:

提高效率,產(chǎn)品未成熟,包括需求上的修改及各種BUG荔茬,用一套代碼來維護废膘,可以減少不必要的重復勞動
免除傳統(tǒng)的重復修改環(huán)境,打包慕蔚,安裝繁瑣的流程丐黄,期間漏改在所難免。而使用Gradle構(gòu)建孔飒,只需選擇環(huán)境-安裝灌闺。快捷坏瞄,方便桂对,不出錯。

實現(xiàn)需求:

  • 兩個APP鸠匀, 用一套代碼來維護蕉斜,不同之處在于應用名稱,圖標缀棍,包名蛛勉,部分跳轉(zhuǎn)邏輯,部分頁面睦柴,部分頁面顯示文字诽凌。

  • 三個環(huán)境: 開發(fā), 測試坦敌, 生產(chǎn)侣诵, 每個環(huán)境的版本,版本號狱窘,圖標不同

  • 命名規(guī)則:ProductFlavor_產(chǎn)品版本號_日期_BuildType.apk
    whgc_1.0.0_20190624_Dev.apk
    whgc_1.0.0_20190624_Test.apk
    whgc_1.0.0_20190624_Release.apk

  • 各環(huán)境APP可安裝在同一手機

環(huán)境

AndroidStudio 3.4
Gradle插件:3.4.0
Gradle:5.1.1

三個環(huán)境 實現(xiàn)步驟:

  • 新建項目
    app: build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.minicup.test"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    ...
}
  • app: build目錄結(jié)構(gòu)


    image.png
  • 執(zhí)行assemble任務

  • 任務執(zhí)行后在build目錄中生成相應文件


    image.png

assemble任務會自動創(chuàng)建debug和release兩個目錄
這里的debug和release目錄對應build.gradle中buildTypes的配置

可項目中buildTypes中明明只有release,并沒有debug杜顺,原因是這里的release和debug是系統(tǒng)默認的兩個構(gòu)建類型,即使沒有配置蘸炸,系統(tǒng)依然會生成這兩個目錄
修改一下build.gradle,將release配置也刪除躬络,再次運行assemble任務,發(fā)現(xiàn)同樣生成了release和debug兩個目錄

android {
    buildTypes {
    }
}

接下來在buildTypes中添加個dev 類型

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

同步后首先看到變化如下:


image.png

image.png

再次執(zhí)行assemble任務:


image.png

以上符合預期搭儒。

自此在buildTypes中穷当,我們可以配置三種環(huán)境,解決關于三個環(huán)境的需求

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

也可以這樣配置

android {
    ...
    buildTypes {
//            常用配置:
//            signingConfig,
//            buildConfigField,
//            versionNameSuffix
//            multiDexEnabled,
//            zipAlignEnabled,
//            applicationIdSuffix
        debug{
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        appDev{
            initWith(debug)
        }

        appTest{
            initWith(debug)
        }

        appRelease {
            initWith(debug)
        }
    }
}

assemble后的結(jié)果


image.png

我們也可以打開ProjectStructure,在這里配置所有可以配置的東西


image.png

assemble是構(gòu)建所有buildTypes productFlavors嵌套配置生成的目錄淹禾。
buildTypes中的配置命名不能以test開頭馁菜, //BuildType names cannot start with 'test'
除了debug,其他構(gòu)建類型都是release類型的,因此铃岔,在沒有設置簽名配置時汪疮,會生成含有unsigned的標志。
所有的module必須有同樣的構(gòu)建類型,即使是空的

為三個環(huán)境指定簽名文件智嚷,及不同的BASE_URL

先生成jks文件卖丸,后配置build.gradle

android {
    signingConfigs {
        release {
            storeFile file('app.jks')
            storePassword '123456'
            keyAlias = 'app'
            keyPassword '123456'
        }
    }
   
    ...

    buildTypes {
        debug{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/debug\""
        }

        appDev{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""
            signingConfig signingConfigs.release
        }

        appTest{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""
            signingConfig signingConfigs.release
        }

        appRelease {
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""
            signingConfig signingConfigs.release
        }
    }
}

編譯后,生成相應的BuildConfig,里面的內(nèi)容與我們配置的一致


image.png

運行APP


image.png

EventLog

11:07   Executing tasks: [:app:assembleDebug]
11:07   Gradle build finished in 4 s 175 ms
11:07   Install successful

默認運行app時盏道,執(zhí)行的是assembleDebug任務稍浆。
通過設置BuildVariants來切換任務。


image.png

切換為appDev構(gòu)建類型后運行app的效果:


image.png

EventLog

11:19   Executing tasks: [:app:assembleAppDev]
11:19   Gradle build finished in 6 s 488 ms
11:19   Install successful

對應的構(gòu)建類型BuildConfig中生成了不同的值摇天,運行 appTest, appRelease也得到相應的結(jié)果。

但在運行APP時出現(xiàn)一個問題恐仑,也是上面我們需要解決的需求之一泉坐, 三種BuildTypes運行時,生成的APP會被替換掉裳仆,最后運行三種BuildTypes在手機中只生成一個APP腕让。如何讓開發(fā),測試歧斟,生產(chǎn)環(huán)境的APP存在于同一個手機上纯丸。為了解決這個問題,我們先來看看如何為不同的環(huán)境指定不同的應用名稱及圖標静袖,用以安裝后展示效果

為三個環(huán)境指定不同的應用名稱觉鼻,應用圖標

按照開發(fā)-測試-生產(chǎn)的順序準備三張應用圖標


ic_launcher_dev.png
ic_launcher_test.png
ic_launcher_release.png

strings.xml

<resources>
    <string name="app_name">test</string>
    <string name="app_name_dev">DEV</string>
    <string name="app_name_test">TEST</string>
    <string name="app_name_release">RELEASE</string>
</resources>
android {
    ...
    buildTypes {

        debug{
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/debug\""
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher",
                    app_label : "@string/app_name"
            ]
        }

        release{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/release\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher",
                    app_label : "@string/app_name"
            ]
        }

        appDev{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_dev",
                    app_label : "@string/app_name_dev"
            ]
        }

        appTest{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_test",
                    app_label : "@string/app_name_test"
            ]
        }

        appRelease {
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_release",
                    app_label : "@string/app_name_release"
            ]
        }
    }
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.minicup.test">

    <application
        android:allowBackup="true"
        android:icon="${app_icon}"
        android:label="${app_label}"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

通過設置不同的BuildVariants獲得的結(jié)果:

BuildType.appDev
BuildType.appTest
BuildType.appRelease

以上結(jié)果針對BuildType的應用名稱,應用圖標队橙,及打開APP中的BASE_URL都一一對應坠陈。接下來讓三種BuildType運行在一臺機器上。

三種不同的BuildType捐康,安裝在同一設備上仇矾。

android {
    ...
    buildTypes {
         ...
        appDev{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_dev",
                    app_label : "@string/app_name_dev"
            ]
            applicationIdSuffix = ".dev"
        }

        appTest{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_test",
                    app_label : "@string/app_name_test"
            ]
            applicationIdSuffix = ".test"
        }

        appRelease {
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@mipmap/ic_launcher_release",
                    app_label : "@string/app_name_release"
            ]
            applicationIdSuffix = ".release"
        }
    }
}

切換三種BuildType,安裝APP到設備中:


image.png

實現(xiàn)一套代碼維護兩個應用解总,每個應用都有dev,test,release三個構(gòu)建類型贮匕,兩個應用的圖標,名稱花枫,包名不同

  • app build.gradle 指定不同productFlavor下的包名,及不同buildType下的圖標,名稱及包名后綴
apply plugin: 'com.android.application'

android {
    signingConfigs {
        release {
            storeFile file('appDev.jks')
            storePassword '123456'
            keyAlias = 'appDev'
            keyPassword '123456'
        }
    }
    compileSdkVersion 28

    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        flavorDimensions "default" 
    }
    buildTypes {
        appDev{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appDev\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@drawable/ic_launcher_dev",
                    app_label : "@string/app_name_dev"
            ]
            applicationIdSuffix = ".dev"
        }

        appTest{
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appTest\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@drawable/ic_launcher_test",
                    app_label : "@string/app_name_test"
            ]
            applicationIdSuffix = ".test"
        }

        appRelease {
            buildConfigField "String", "BASE_URL", "\"http://192.168.0.1:8080/appRelease\""
            signingConfig signingConfigs.release
            manifestPlaceholders  = [
                    app_icon :"@drawable/ic_launcher_release",
                    app_label : "@string/app_name_release"
            ]
            applicationIdSuffix = ".release"
        }
    }

    productFlavors {
        orange {
            applicationId "com.minicup.orange"
        }

        green {
            applicationId "com.minicup.green"
        }

    }

    //去掉默認的debug及release兩個buildType
    variantFilter { variant ->
        if(variant.buildType.name.equals('release') || variant.buildType.name.equals('debug')) {
            variant.setIgnore(true)
        }
    }
}

...

*創(chuàng)建以下的目錄結(jié)構(gòu),不同productFlavor對應相應的圖標,名稱


image.png

green目錄下的圖標及名稱:


ic_launcher_dev.xml
ic_launcher_test.xml
ic_launcher_release.xml
<resources>
    <string name="app_name_dev">DEV_G</string>
    <string name="app_name_test">TEST_G</string>
    <string name="app_name_release">RELEASE_G</string>
</resources>

orange目錄下的圖標及名稱:


ic_launcher_dev.xml
ic_launcher_test.xml
ic_launcher_release.xml
<resources>
    <string name="app_name_dev">DEV_O</string>
    <string name="app_name_test">TEST_O</string>
    <string name="app_name_release">RELEASE_O</string>
</resources>
  • MainActivity
public class MainActivity extends AppCompatActivity {
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.textView);
        mTextView.setText(BuildConfig.FLAVOR + " "+ BuildConfig.BUILD_TYPE);
    }
}
  • 同步項目刻盐,查看BuildVariant, 生成了兩個應用對應的構(gòu)建類型 2(productFlavor)*3(buildType)=6(buildVariant)


    image.png
  • 執(zhí)行assemble任務:


    image.png
  • 驗證APP,將生成的6個APP安裝到設備中


    image.png
  • 不同的productFlavor,不同的buildType生成的應用可安裝到同一個設備
  • 同一個productFlavor的不同buildType劳翰,根據(jù)之前配置生成不同名稱隙疚,不同圖標,不同包名的app
image.png
image.png
image.png
image.png
image.png
image.png

設置生成APP的文件名稱

    productFlavors {
        orange {
            applicationId "com.minicup.orange"
            versionCode 2
            versionName "2.2"
        }

        green {
            applicationId "com.minicup.green"
            versionCode 3
            versionName "3.3"
        }
    }


    applicationVariants.all { variant ->
        variant.outputs.all { output ->
                //產(chǎn)品名稱_產(chǎn)品版本號_日期_軟件環(huán)境
                outputFileName  = "${variant.productFlavors[0].name}_" +
                        "v${variant.versionName}_" +
                        "${releaseTime()}_" +
                        "${variant.buildType.name}" +
                        ".apk"
        }
    }


def releaseTime(){
    return new Date().format("yyyy-MM-dd")
}

執(zhí)行assemble任務:

image.png

集成JPush時磕道,遇到的問題

按照以上方法配置JPush時供屉,打好的包,不能同時安裝在同一個設備中


image.png

目前只能準備兩臺設備,同一設備只能安裝同一buildtype的應用

參考:
https://developer.android.google.cn/studio/build/index.html
http://google.github.io/android-gradle-dsl/current/index.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伶丐,一起剝皮案震驚了整個濱河市悼做,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哗魂,老刑警劉巖肛走,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異录别,居然都是意外死亡朽色,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門组题,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葫男,“玉大人,你說我怎么就攤上這事崔列∩液郑” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵赵讯,是天一觀的道長盈咳。 經(jīng)常有香客問我,道長边翼,這世上最難降的妖魔是什么鱼响? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮组底,結(jié)果婚禮上热押,老公的妹妹穿的比我還像新娘。我一直安慰自己斤寇,他們只是感情好桶癣,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娘锁,像睡著了一般牙寞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莫秆,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天间雀,我揣著相機與錄音,去河邊找鬼镊屎。 笑死惹挟,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的缝驳。 我是一名探鬼主播连锯,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼归苍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了运怖?” 一聲冷哼從身側(cè)響起拼弃,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摇展,沒想到半個月后谱煤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體图柏,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年虚倒,在試婚紗的時候發(fā)現(xiàn)自己被綠了踪旷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逞盆。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡刊懈,死狀恐怖虹茶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踱启,我是刑警寧澤报账,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布研底,位于F島的核電站埠偿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏榜晦。R本人自食惡果不足惜冠蒋,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乾胶。 院中可真熱鬧抖剿,春花似錦、人聲如沸识窿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喻频。三九已至缩宜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甥温,已是汗流浹背锻煌。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姻蚓,地道東北人宋梧。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像狰挡,于是被迫代替她去往敵國和親捂龄。 傳聞我的和親對象是個殘疾皇子释涛,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

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

  • 說明 本文主要介紹和Gradle關系密切、相對不容易理解的配置跺讯,偏重概念介紹枢贿。部分內(nèi)容是Android特有的(例如...
    jzj1993閱讀 15,649評論 1 62
  • Gradle 是一款構(gòu)建系統(tǒng)工具,它的 DSL 基于 Groovy 實現(xiàn)刀脏。Gradle 構(gòu)建的大部分功能都是通過插...
    任教主來也閱讀 3,061評論 3 6
  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項局荚,請點擊這里進行查閱:DSL參考 1.1新構(gòu)建系統(tǒng)...
    Chuckiefan閱讀 12,142評論 8 72
  • Android Gradle為我們提供了大量的DSL,我們使用這些DSL定義配置我們的工程以滿足我們項目中不同的需...
    acc8226閱讀 972評論 0 7
  • 版權(quán)聲明:本文為博主原創(chuàng)文章愈污,未經(jīng)博主允許不得轉(zhuǎn)載耀态。 https://blog.csdn.net/zhaoyanj...
    勤奮的pangdunhu閱讀 2,044評論 0 1