第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Gradle 多渠道打包

我們在日常開發(fā)中多多少少都會遇到多渠道打包的情況。這些版本可能會上傳到不同的應(yīng)用市場,也可能是是線下多渠道推薦。有時候可能不同的渠道使用的資源圖片都不一樣。古老的做法就是,需要打多少個渠道包拉出多少份代碼分支,分別替換對應(yīng)的資源文件和包名配置信息等。這種做法非常的耗時耗力。Gradle 可以幫我們用一份代碼通過配置實現(xiàn)打出所有的渠道包。

1. 創(chuàng)建多渠道資源文件目錄

首先,我們新創(chuàng)建一個工程,然后在 main 模塊下面,根據(jù)不同渠道創(chuàng)建不同的資源文件目錄。我們先定義一個簡單的頁面,里面顯示渠道跟一張圖片。layout 布局文件如下所示:

<?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:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="26sp"
        android:textColor="@color/colorPrimary"
        android:text="@string/chanl_name" />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@mipmap/girl"
        >
    </ImageView>
</LinearLayout>

然后我們根據(jù)我們用到的資源,對不同渠道配置不同的資源。我們這里 model 比較簡單,主要是圖片和字符串,圖片這里我們不同渠道顯示的不同。具體目錄如下所示:

圖片描述
圖片描述

Tips: 注意這里我們創(chuàng)建資源文件目錄的時候不能包含 test ,否則會編譯報錯的。我親自嘗試過 res-test。

2. 配置多渠道資源路徑

前面我們創(chuàng)建了多渠道的資源目錄,那么我們就需要將它配置在 build.gradle 中。我們前面介紹 AS 中 Android 項目的 Gradle 配置時講到過,我們在 SourceSet 閉包配置。具體多渠道配置如下:

    //配置資源文件路徑,可動態(tài)指定不同版本資源文件
    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java']
            resources.srcDirs = ['src/main/resources']
            aidl.srcDirs = ['src/main/aidl']
            renderscript.srcDirs = ['src/maom']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
            jniLibs.srcDir 'src/main/jniLibs'
        }
        //用各自對應(yīng)的資源文件路徑
        chanlA.res.srcDirs = ['src/main/res-a']
        chanlB.res.srcDirs = ['src/main/res-b']
        androidTest.setRoot('tests')
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

3. 配置渠道及不同渠道包名等

配置多渠道在 Gradle 中使用 productFlavors 閉包,在這個閉包中我們可以配置所有的渠道,以渠道名為閉包,每個渠道可以配置 applicationId簽名信息等。我們這里簡單配置了applicationId。如下:

    /*
    * 渠道Flavors,配置不同Chanl的app
    * 資源文件不能用test字段命令(會運(yùn)行報錯的,如res-test)
    * */
    productFlavors {
        chanlA{
            applicationId "com.bthvi.chanla"//可為不同版本動態(tài)指定包名
        }
        chanlB{
            applicationId "com.bthvi.chanlb"//可為不同版本動態(tài)指定包名
        }
    }

4. 配置 apk 包輸出的路徑

我們?nèi)绻慌渲?APK 包的輸出路徑默認(rèn)是在,build 文件夾下的。但是我們這里為了方便可以將編譯生成的 APK 包放在一個自己指定的目錄下面。我們這里放在根目錄的 apks 文件夾下,然后以不同渠道的 applicationId 以及日期存放不同的渠道的包。具體的 Gradle 配置信息如下:

    // 版本比較多時,自定義導(dǎo)出的APK文件的名稱
    applicationVariants.all {
        //獲取是release還是debug版本
        def buildType = it.buildType.name
        def fileName
        //下面的channel是獲取渠道號,你獲取渠道號不一定會和我的代碼一樣,因為有可能你的渠道名稱的規(guī)則和我的不一樣,我的規(guī)則是${渠道名}-${applicationId},所以我是這樣取的。
        def channel = it.productFlavors[0].name.split("-")[0]
        //獲取當(dāng)前時間的"YYYY-MM-dd"格式。
        def createTime = new Date().format("YYYY-MM-dd", TimeZone.getTimeZone("GMT+08:00"))
        it.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/apks/${it.productFlavors[0].applicationId}/${createTime}")
        it.outputs.each {
                //我此處的命名規(guī)則是:渠道名_版本名_創(chuàng)建時間_構(gòu)建類型.apk[大家也可以根據(jù)自己的需求命名]
                fileName = "${channel}_v${defaultConfig.versionName}_${createTime}-${buildType}.apk"
                //打印出apk文件名稱,以便及時查看是否滿足要求
                logger.quiet("文件名:>>>>>>>>>>>>>>>>>>>>>>${fileName}")
                //重新對apk命名。
                //Gradle4.0以下版本
                //it.outputFile = new File(it.outputFile.parent, fileName)
                //Gradle4.0(含)以上版本
                it.outputFileName = fileName
        }
    }

5. 經(jīng)常遇到的坑

  1. 這里我們需要注意的一點(diǎn)就是自己的 Gradle 版本,根據(jù)不同的版本命名 apk 文件的命令也是不一樣的。在 Gradle 4.0 以上使用it.outputFile = new File(it.outputFile.parent, fileName)會拋出以下的錯誤.

  2. 我們還是需要注意自己的 Gradle 版本。由于 Gradle 3.0.0 之后有一種自動匹配消耗庫的機(jī)制,便于 debug variant 自動消耗一個庫,然后就是必須要所有的flavor 都屬于同一個維度。所以如果你的 Gradle 是 3.0.0 之后的版本,我們需要在主 app 的 build.gradle 里面的 defaultConfig 閉包中加入 flavorDimensions “versionCode”。意思是flavor dimension 它的維度就是版本號。否則編譯會報如下錯:

6. 最終的效果

配置完上面的所有之后,我們先看下完整的 build.gradle 長啥樣。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.bthvi.chanl"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        flavorDimensions "versionCode"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    //配置資源文件路徑,可動態(tài)指定不同版本資源文件
    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java']
            resources.srcDirs = ['src/main/resources']
            aidl.srcDirs = ['src/main/aidl']
            renderscript.srcDirs = ['src/maom']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
            jniLibs.srcDir 'src/main/jniLibs'
        }
        //用各自對應(yīng)的資源文件路徑
        chanlA.res.srcDirs = ['src/main/res-a']
        chanlB.res.srcDirs = ['src/main/res-b']
        androidTest.setRoot('tests')
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

    // 版本比較多時,自定義導(dǎo)出的APK文件的名稱
    applicationVariants.all {
        //獲取是release還是debug版本
        def buildType = it.buildType.name
        def fileName
        //下面的channel是獲取渠道號,你獲取渠道號不一定會和我的代碼一樣,因為有可能你的渠道名稱的規(guī)則和我的不一樣,我的規(guī)則是${渠道名}-${applicationId},所以我是這樣取的。
        def channel = it.productFlavors[0].name.split("-")[0]
        //獲取當(dāng)前時間的"YYYY-MM-dd"格式。
        def createTime = new Date().format("YYYY-MM-dd", TimeZone.getTimeZone("GMT+08:00"))
        it.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/apks/${it.productFlavors[0].applicationId}/${createTime}")
        it.outputs.each {
                //我此處的命名規(guī)則是:渠道名_版本名_創(chuàng)建時間_構(gòu)建類型.apk[大家也可以根據(jù)自己的需求命名]
                fileName = "${channel}_v${defaultConfig.versionName}_${createTime}-${buildType}.apk"
                //打印出apk文件名稱,以便及時查看是否滿足要求
                logger.quiet("文件名:>>>>>>>>>>>>>>>>>>>>>>${fileName}")
                //重新對apk命名。
                //Gradle4.0以下版本
                //it.outputFile = new File(it.outputFile.parent, fileName)
                //Gradle4.0(含)以上版本
                it.outputFileName = fileName
        }
    }
    /*
    * 渠道Flavors,配置不同Chanl的app
    * 資源文件不能用test字段命令(會運(yùn)行報錯的,如res-test)
    * */
    productFlavors {
        chanlA{
            applicationId "com.bthvi.chanla"//可為不同版本動態(tài)指定包名

        }
        chanlB{
            applicationId "com.bthvi.chanlb"//可為不同版本動態(tài)指定包名
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

然后我們就可以執(zhí)行命令打包了,我們這里執(zhí)行 gradle build 就可以打出所有渠道的 debug 和 release 包了。具體打包輸出及 APK 包的輸出目錄如下所示:


下面我們裝上不同渠道的包,看下是否不同渠道的圖片和字符串是不同的。

7. 小結(jié)

這一節(jié)內(nèi)容我們主要講了如何通過 Gradle 配置不同資源文件實現(xiàn)一份代碼打出多個渠道包。相較于之前我們用不同的代碼分支來打多渠道包,效率提升很多。