Android 詳解Gradle(3.1.4)實現多渠道打包

DeMonnnnnn發表於2018-08-31

環境

文章的執行環境為:
AndroidStudio版本:3.1.4
Gradle版本:3.1.4

前言

在日常開發中,不同平臺,不同客戶,我們需要打包不同的版本,有可能還要進行一些顯示上的改動。
如果多達幾十個版本,我們一個個替換更改,是很讓人抓狂的。
因此我們可以通過build.gradle配置,實現多渠道打包,一勞永逸。

問題

僅通過build.gradle配置,不能在程式碼中用if-else、swith等實現如下四個問題:
1、在同一臺手機上能夠同時安裝debug版本和release版本;
2、在同一臺手機上的debug版本和release版本能夠在首頁上顯示自己是debug版本還是release版本;
3、在同一臺手機上能夠同時安裝公司debug版本、公司release版本、醫院debug版本、醫院release版本;
4、在同一臺手機上的公司debug版本、公司release版本、醫院debug版本、醫院release版本能夠在首頁上顯示自己是什麼版本;

由於不能使用if-else,所以就無法使用BuildConfig.DEBUG來判斷debug還是release。

程式碼及目錄

GitHub: https://github.com/Demo-DeMon/MultiChannelPackaging
這裡寫圖片描述

效果圖

這裡寫圖片描述

實現

MainActivity

如上效果圖,主介面只有兩個TextView。
第一個顯示當前版本,通過資原始檔的string值來控制不同版本顯示。
第二個顯示當前包名,使用getPackageName()獲取。

public class MainActivity extends AppCompatActivity {
    TextView tvPackage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvPackage = findViewById(R.id.tv_package);
        tvPackage.setText("當前包名:" + getPackageName());

    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/home_text"
        android:textColor="#000000"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/tv_package"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textColor="#000000"
        android:textSize="18sp" />
</LinearLayout>

資原始檔的適配

為了達到不同版本顯示不同的內容,我們可以對資原始檔進行適配。
配置資原始檔路徑,可動態指定不同版本資原始檔。
如上目錄所示,我們可以建立格式如:res-版本 來控制不同版本使用不同的資原始檔。
版本問題解決了,那麼怎麼來判斷debug還是release?
在build.gradle定義資原始檔值,可以在程式中像其他string值一樣被引用。
如果不明白的可以檢視這兩篇文章:
Gradle實現多渠道打包(不同資原始檔打不同的包)
Android 同時安裝debug release版, 並且顯示不同名字

公司版本(C)的strings.xml
<resources>
    <string name="app_name">Demo(C)</string>
    <string name="text_release">Company_release</string>
    <string name="text_debug">Company_debug</string>
</resources>
醫院版本(H)的strings.xml
<resources>
    <string name="app_name">Demo(H)</string>
    <string name="text_release">Hospital_release</string>
    <string name="text_debug">Hospital_debug</string>
</resources>
配置build.gradle
android {
    ...
   //配置資原始檔路徑,可動態指定不同版本資原始檔
    sourceSets {
        //用各自對應的資原始檔路徑
        company.res.srcDirs = ['src/main/res-company']
        hospital.res.srcDirs = ['src/main/res-hospital']
        ...
    }

    buildTypes {
       //在build.gradle定義資原始檔值,可以在程式中像其他string值一樣被引用
       //格式resValue 型別, key(不能與strings.xml檔案中的相同), value(可以直接使用strings.xml檔案中的值)
        debug {
            ...
            resValue "string", "home_text", "@string/text_debug"
            ...
        }
        release {
            ...
            resValue "string", "home_text", "@string/text_release"
            ...
        }
    }
   ....
}

多渠道配置

flavor維度,3.0以上,必須每個渠道版本必須增加,此處以版本號作為維度值
詳情見:https://blog.csdn.net/syif88/article/details/75009663/

android {
    ...
 //多渠道配置,可以配置多個,此處只配置兩個
    productFlavors {
        company {
            //修改包名,能夠同時安裝多個渠道版本
            applicationId "com.demon.multichannelpackaging.company"
            versionCode 1
            versionName "0.1"
            //flavor維度,3.0以上,必須每個渠道版本必須增加,此處以版本號作為維度值
            //詳情見:https://blog.csdn.net/syif88/article/details/75009663/
            flavorDimensions "versionCode"
        }
        hospital {
            //修改包名,能夠同時安裝多個渠道版本
            applicationId "com.demon.multichannelpackaging.hospital"
            versionCode 1
            versionName "0.1"

            flavorDimensions "versionCode"
        }
    }
    ...
   }

多渠道打包配置

android {
    ...
//版本比較多時,自定義匯出的APK名稱,不同的渠道編出的APK的檔名應該是不一樣的
    //Android外掛3.0遷移指南所示:
    //用all()而不是each()
    //如果您只更改檔名(這是您的情況),請使用outputFileName而不是output.outputFile
    applicationVariants.all { variant ->
        variant.outputs.all() { output ->
            def flavor = variant.productFlavors[0]
            def fileName = "${variant.flavorName}_${flavor.versionCode}.${variant.versionName}.apk"
            /*//預設打包方式,打包到app的子目錄下
            outputFileName = fileName*/
            //修改打包路徑,工程apkpackage資料夾下
            //也可以在打包時手動選擇對應目錄
            def des = output.packageApplication.outputDirectory.toPath().relativize(rootDir.toPath()).toFile()
            outputFileName = new File("$des/apkpackage", fileName)
        }
    }
    ...
 }

build.gradle完整程式碼

程式碼註釋些的很多,請自行檢視。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    dexOptions {
        javaMaxHeapSize "2g"
        preDexLibraries = false
    }

    defaultConfig {
        applicationId "com.demon.multichannelpackaging"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
    //配置資原始檔路徑,可動態指定不同版本資原始檔
    sourceSets {
        //用各自對應的資原始檔路徑
        company.res.srcDirs = ['src/main/res-company']
        hospital.res.srcDirs = ['src/main/res-hospital']
        //多渠道打包目錄配置
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

    //版本比較多時,自定義匯出的APK名稱,不同的渠道編出的APK的檔名應該是不一樣的
    //Android外掛3.0遷移指南所示:
    //用all()而不是each()
    //如果您只更改檔名(這是您的情況),請使用outputFileName而不是output.outputFile
    applicationVariants.all { variant ->
        variant.outputs.all() { output ->
            def flavor = variant.productFlavors[0]
            def fileName = "${variant.flavorName}_${flavor.versionCode}.${variant.versionName}.apk"
            /*//預設打包方式,打包到app的子目錄下
            outputFileName = fileName*/
            //修改打包路徑,工程apkpackage資料夾下
            //也可以在打包時手動選擇對應目錄
            def des = output.packageApplication.outputDirectory.toPath().relativize(rootDir.toPath()).toFile()
            outputFileName = new File("$des/apkpackage", fileName)
        }
    }
    //debug和release版本的簽名配置
    signingConfigs {
        debug {
            storeFile file("DeMon.jks")
            keyAlias = 'key'
            keyPassword = '123456'
            storePassword = '123456'
        }

        release {
            storeFile file("DeMon.jks")
            keyAlias = 'key'
            keyPassword = '123456'
            storePassword = '123456'
        }

    }
    buildTypes {
        //指定打包時的簽名,如果有不同的簽名可放在productFlavors不同專案下執行,不過一般都會相同
        debug {
            //顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            //apk包名稱字尾,用來區分release和debug
            versionNameSuffix "-debug"
            //修改包名,能夠同時安裝debug和release
            applicationIdSuffix ".debug"
            //在build.gradle定義資原始檔值,可以在程式中像其他string值一樣被引用
            //格式resValue 型別, key(不能與strings.xml檔案中的相同), value(可以直接使用strings.xml檔案中的值)
            resValue "string", "home_text", "@string/text_debug"
            minifyEnabled false
            signingConfig signingConfigs.debug
        }
        release {
            //不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            versionNameSuffix "-release"
            //修改包名,能夠同時安裝debug和release
            applicationIdSuffix ".release"
            resValue "string", "home_text", "@string/text_release"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release

        }
    }
    //多渠道配置,可以配置多個,此處只配置兩個
    productFlavors {
        company {
            //修改包名,能夠同時安裝多個渠道版本
            applicationId "com.demon.multichannelpackaging.company"
            versionCode 1
            versionName "0.1"
            //flavor維度,3.0以上,必須每個渠道版本必須增加,此處以版本號作為維度值
            //詳情見:https://blog.csdn.net/syif88/article/details/75009663/
            flavorDimensions "versionCode"
        }
        hospital {
            //修改包名,能夠同時安裝多個渠道版本
            applicationId "com.demon.multichannelpackaging.hospital"
            versionCode 1
            versionName "0.1"

            flavorDimensions "versionCode"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0-rc02'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}

參考

Gradle實現多渠道打包(不同資原始檔打不同的包)
Android 同時安裝debug release版, 並且顯示不同名字
https://blog.csdn.net/syif88/article/details/75009663/

相關文章