Android官方多渠道方案詳解

簡介

實際應用開發中,不可避免的會接觸到多渠道打包,不過其實你們經常使用的多渠道打包其實分爲兩種。第一:只是須要簡單的渠道標識,而後經過標識代碼裏作一些必要的邏輯處理,這種狀況如今網上有不少開源的方案,能夠作到快速打包,這裏就不在多作介紹了。第二:須要對代碼、資源、依賴、配置等作到更深度的定製,好比爲不一樣的應用市場設置不一樣的啓動頁和logo,這種狀況就能夠採用官方的ProductFlavors,下面也會詳細介紹這種方案。
簡單總結下這兩種方案,第一種打包速度快,可是不夠靈活,第二種有很強的定製性,可是因爲每次回從新編譯並簽名因此在打包速度上慢不少,你們能夠根據需求自由選擇不一樣的方案,或者搭配使用。java

方案介紹

構建配置

首先須要在module中的build.gradle配置你須要的渠道,渠道中能夠修改一些defaultConfig中的配置android

android {
    ···
    defaultConfig {
        minSdkVersion 19
        versionCode 1
        ...
    }
    
    // 渠道的維度,支持不一樣維度的渠道
    flavorDimensions "channel"
    productFlavors {
        common {
            dimension "channel"
        }
        xiaomi {
            minSdkVersion '21'
            versionCode 20000  + android.defaultConfig.versionCode
            versionNameSuffix "-minApi21"
            dimension "channel"
        }
        huawei {
            minSdkVersion '23'
            versionCode 20000  + android.defaultConfig.versionCode
            versionNameSuffix "-minApi23"
            dimension "channel"
        }
    }
    
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

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

複製代碼

Gradle 會經過上面的配置建立維度 * 維度中的渠道 * 構建類型數量的構建變體。在 Gradle 爲對應構建變體的APK 命名時,首先是渠道,以後是構建類型。以上面的構建配置爲例,Gradle 可使用如下命名方案建立共6個構建變體:app

構建變體:[common, xiaomi, huawei][debug, release]
對應 APK:app-[common, xiaomi, huawei]-[debug, release].apkpost

過濾變體

Gradle 會爲每一個可能的組合建立構建變體。都在Android Studio -> Build Variants中顯示出來,不過某些特定的構建變體在您的項目環境中並沒必要要,也可能沒有意義。您能夠在build.gradle 文件中建立一個變體過濾器,以移除某些構建變體配置。測試

android {
    ···
    variantFilter { variant ->
        def names = variant.flavors*.name
        def buildTypeName = variant.buildType.name
        println (names + "==" + buildTypeName)
        // 這樣就會移除 commonDebug的變體
        if (buildTypeName.contains("debug") && names.contains("common")) {
            setIgnore(true)
        }
    }
    ...
}

複製代碼

dependencies依賴

現實場景中有的時候不一樣的渠道,提供的功能也不盡相同,這樣就須要對不一樣的渠道引入不一樣的組件包(前提App已經進行了組件拆分),以下簡單配置就能夠實現gradle

configurations {
    // Gradle沒有提供此細粒度級別的依賴方式,須要本身配置下否則會報錯
    xiaomiDebugImplementation {}
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation('com.android.support:appcompat-v7:26.1.0')

    // 能夠控制 xiaomi渠道下 的 debug 構建類型纔去引入此包
    xiaomiDebugImplementation('com.xxx:xxx:1.6.0')
    debugImplementation('com.xxx:xxx:1.6.0')
    commonImplementation('com.xxx:xxx:1.6.0')
}
複製代碼

不一樣渠道的獨立簽名

同上面需求,對於功能不一樣的安裝包,大機率是要獨立的簽名,經過簡單的配置同樣能夠實現,不過對於debug的構建類型,是不支持定製簽名的,具體緣由未知...ui

signingConfigs {
    test11 {
        storeFile file("../test11.keystore")
        storePassword 'test11'
        keyAlias 'test11'
        keyPassword 'test11'
    }
    test22 {
        storeFile file("../test22.keystore")
        storePassword 'test22'
        keyAlias 'test22'
        keyPassword 'test22'
    }
}
// 渠道的維度,支持不一樣維度的渠道
flavorDimensions "channel"
productFlavors {
    common {
        dimension "channel"
    }
    xiaomi {
        dimension "channel"
    }
    huawei {
        dimension "channel"
    }
}
buildTypes {
    debug {
        //debug定製簽名無效 只能指定一個或者使用默認的簽名
// productFlavors.huawei.signingConfig signingConfigs.test11
// productFlavors.xiaomi.signingConfig signingConfigs.test22
// productFlavors.common.signingConfig signingConfigs.test11
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

    }
    release {
        productFlavors.huawei.signingConfig signingConfigs.test11
        productFlavors.xiaomi.signingConfig signingConfigs.test22
        productFlavors.common.signingConfig signingConfigs.test11
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
複製代碼

Manifest配置

有時咱們須要對Mainfest中的某個屬性值作些調整,如配置不一樣渠道數據,App的Icon,還有替換聲明Activity等等,均可以經過下面的配置實現,若是感受這種簡單的調整還不足以知足你的需求,能夠看下方的定製源集的方案去深度的定製spa

// build.gradle
android {
    ···
    flavorDimensions "channel"
    productFlavors {
        common {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "Common Meta Data",
                                    "AppIcon"     : "@mipmap/ic_common",
                                    "MainActivity":CommonActivity"]
        }
        xiaomi {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "XiaoMi Meta Data",
                                    "AppIcon"     : "@mipmap/ic_launcher",
                                    "MainActivity":"XMActivity"]
        }
        huawei {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "HuaWei Meta Data",
                                    "AppIcon"     : "@mipmap/ic_launcher",
                                    "MainActivity": "HWActivity"]
        }
    }
    ...
}

// Manifest 
<application
    //${AppIcon} 替換AppIcon
    android:icon="${AppIcon}"
    ... >

    //${ChannelData} 替換ChannelData
    <meta-data
        android:name="ChannelData"
        android:value="${ChannelData}"/>

    //${ChannelData} 替換聲明Activity
    <activity android:name="${MainActivity}">
        ...
    </activity>
</application>



複製代碼

定製代碼 資源 Manifest 等源集

有時候簡單的調整可能不足以解決實際問題,這個時候能夠直接定製源集解決問題,找到youModule\src,當前目錄下有個main文件夾爲咱們工程的核心代碼和資源,咱們能夠在同級下建立不一樣的渠道目錄,如:common``xiaomi等,此目錄能夠放置自定義的java代碼res資源AndroidManifestassets等。
不一樣變體目錄(按優先級排列):debug

src/commonDebug/(構建變體源集)
src/debug/(buildTypes源集)
src/common/(productFlavors源集)
src/main/(主源集)
複製代碼

上面列出的順序決定了在 Gradle 合併代碼和資源時哪一個源集具備較高的優先級。若是 commonDebug/debug/ 包含相同的文件,Gradle 將使用 commonDebug/ 源集中的文件。一樣,Gradle 會爲其餘源集中的文件賦予比 main/ 中相同文件更高的優先級。Gradle 在應用如下構建規則時會考慮此優先級順序:調試

  • 對於java/ 下的源代碼只能有單一的類文件
    注:對於給定的渠道目錄,若是找到兩個或兩個以上定義同一 Java 類的源集目錄,Gradle 就會引起一個構建錯誤。例如,在構建調試 APK 時,您不能同時定義 src/common/Utility.javasrc/main/Utility.java。這是由於 Gradle 會在構建過程當中檢查這兩個目錄並引起duplicate class錯誤。若是針對不一樣的構建類型須要不一樣版本的 Utility.java,您可讓每一個渠道定義其本身的文件版本,如:src/common/Utility.javasrc/xiaomi/Utility.java,而不將其包含在 main/ 中。
  • 全部Manifest合併爲單個Manifest。將按照上述列表中的相同順序指定優先級。也就是說,某個構建類型的Manifest設置會替換某個渠道的Manifest設置
  • 一樣,values/ res/ 和 asset/ 目錄中的若是存在有兩個或兩個以上的同名資源,好比在渠道中的資源將會替換main中資源,如下對於同時存在於strings.xml的同名資源和資源圖標作個示例
// main 下的 圖標資源
main\res\mipmap-hdpi\ic_launcher.png

// 在 xiaomi 下的 圖標資源
xiaomi\res\mipmap-hdpi\ic_launcher.png 

//打包 xiaomi 渠道的時候會自動替換圖片。
複製代碼
// main 下的 strings.xml
<resource>
    <string name="app_name">MultiChannel</string>
    <string name="string_merge">我是string,沒被合併</string>
</resource>
// 在 xiaomi 下的 strings.xml 內容爲:
<resource>
    <string name="string_merge">我是xiaomi,已經合併</string>
</resource>
//當打 xiaomi 渠道包時,最終 strings.xml 會變成:
<resource>
    <string name="app_name">MultiChannel</string>
    <string name="string_merge">我是xiaomi,已經合併</string>
</resource>
複製代碼

其餘

命令構建

對於習慣於使用命令構建的同窗來講有如下幾點須要補充

  • 打所有包: gradle assemble
  • 打所有 Debug 包: gradle assembleDebug ,能夠簡寫爲 gradle aD 或 aDebug
  • 打所有 Release 包: gradle assembleRelease,能夠簡寫爲 gradle aR 或 aRelease
  • 打指定 flavor 包: gradle assemble(flavor)(Debug|Release) 如:gradle assembleXiaomiDebug
  • 打包完成後安裝: gradle install(flavor)(Debug|Release)如:如:gradle installXiaomiDebug
  • 打包前先 clean 一下,在測試的時候很必要: gradle clean assembleXiaomiDebug

參考閱讀

推薦:官方文檔
android.jobbole.com/84752/
juejin.im/post/58be7b…

相關文章
相關標籤/搜索