Android使用Gradle玩轉(zhuǎn)多渠道多包名打包

寫這篇文章主要是因為,公司的項目對打包有多重需求,有哪些需求呢?
1.多渠道,這是最基本的;
2.分為3個版本(內(nèi)地版,海外版,精簡版),每個版本包名不同(這就意味著第三方sdk的各種key都不一樣),且logo,部分圖標(biāo)也不一樣;
3.開發(fā)版本的區(qū)別,分為debug版,pre預(yù)覽版,release正式版;
4.開發(fā)版本的區(qū)別要通過app名稱直接體現(xiàn)在桌面上,即apk安裝后,app名稱直接是XXdebug版,XXrelease版本

現(xiàn)在我們就分別來實現(xiàn)以上的需求

一.多渠道打包

gradle的productFlavors用來配置渠道,這里主要介紹一下友盟的多渠道打包配置

  1. 在AndroidManifest.xml中做如下配置
<meta-data
           android:name="UMENG_CHANNEL"
           android:value="${UMENG_CHANNEL_VALUE}" />

${...}這個占位符很重要,下面我們動態(tài)配置一些屬性的時候都會用到這個占位符

  1. 在項目app這個module下的gradle中配置渠道,注意這個productFlavors是配置在android下的
//配置多渠道
    flavorDimensions "default"
    productFlavors {
        wandoujia {dimension "default"}
        _360 {dimension "default"}
        baidu {dimension "default"}
        xiaomi {dimension "default"}
        tencent {dimension "default"}
        taobao {dimension "default"}
    }

    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
  1. 如上配置后,在AndroidStudio的Build->Select Build Variants ,可以看到每個渠道都有debug和release兩個版本


    多渠道.png
  • 4 多版本apk安裝在同一手機上,也就是打多版本
    這是看到了這位大神的文章,覺得講的比我寫的更詳細(xì),下面部分就直接使用大神文章,謝謝作者
    這種情況只需要我們提供不同包名的apk即可完成。因為只要應(yīng)用包名不一樣即使簽名信息一樣還是可以同時安裝在同一臺手機上的,因此我們應(yīng)該在打包成apk時修改應(yīng)用的包名就可以達(dá)到目的啦。接下來我們進入實際操作過程。這里我們先介紹一個知識點,請直接看下圖:
    image.png

當(dāng)然從截圖也可以看出,配置多apk打包和上一篇文章配置多渠道打包是一樣的,都是在productFlavors中配置的。如上圖,我們在productFlavors中配置了兩種flavor的apk信息一種是Beta版,一種是Releases版,同時每個flavor中我們都重新配置applicationId這個屬性,通過這個屬性我們就可以使打包出來的apk包名產(chǎn)生對應(yīng)的變化啦。至于為什么重新配置了applicationId就行呢,原因圖已經(jīng)說明啦,就是因為defaultConfig是Beta版和Releases版flavor的基礎(chǔ)配置,只要我們重寫了applicationId這個屬性就會覆蓋defaultConfig中相對應(yīng)屬性的信息,從而使打包出來的兩種apk的包名不一樣,達(dá)到在同一臺手機上安裝的目的。那么applicationId又是什么呢?看下圖(因此我們更改其實就是package屬性)


image.png
image.png

比如說不同版本要使用不同的icon,這時該如何做呢?實際上還是在productFlavors的每個flavor中通過manifestPlaceholders屬性配置即可,manifestPlaceholders是一個類似HashMap的容器,因此在manifestPlaceholders可以配置多個屬性,以便在AndroidManifest.xm中使用,比如我們需要為每種版本的apk替換特定的icon和appName這時我們可以這樣如下配置:


image.png

然后在AndroidManifest.xm中這樣使用即可:


image.png
   defaultConfig {
        applicationId "com.zejian.multi_versionapk"
        minSdkVersion 10
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug4zj
            minifyEnabled true
            zipAlignEnabled true
        }
    }
    //配置多版本的apk
    productFlavors{
        Beta{
            applicationId "com.zejian.multi_versionapk.beta"
            manifestPlaceholders = [app_name:"multi_versionapk.beta" ,icon: "@mipmap/ic_launcher_beta"]
            //在java代碼中具體的使用方式為:context.getResources().getString(R.string.strKey);
            resValue("string" , "strKey","beta版本")
        }
        Releases{
            applicationId "com.zejian.multi_versionapk.release"
            manifestPlaceholders = [app_name:"multi_versionapk.release",icon: "@mipmap/ic_launcher_releases"]
            resValue("string" , "strKey","release版本")
        }
    }
}
多版本.png

同時,我們Generate signed APK就可以打出release和debug的每個版本和每個渠道的包


打包的選項.png

至此,我們就可以通過Build Variants來控制當(dāng)前的運行環(huán)境,來決定當(dāng)前的包是屬于哪個版本和哪個渠道

二. 多渠道包跟多版本包不同的內(nèi)容,如何來區(qū)分,也就是文章開頭第二條中的icon,logo,包名等信息不同時候如何來區(qū)別對待,那就要用到manifestPlaceholders了,文章上面說過,我們使用${...}占位符能夠動態(tài)替換AndroidManitest里面的很多東西,如何操作請往下看
wandoujia {
            dimension "default"
            manifestPlaceholders = [
                    applicationId :"com.app.test",
                    app_name     : "@string/AppName",
                    icon         : "@string/ic_launcher",
                    app_key      : "1234567",
                    umeng_channel: "豌豆莢"
            ]
        }
 wandoujia_oas {
            dimension "default"
            manifestPlaceholders = [
                    applicationId :"com.app.oas",
                    app_name     : "@string/AppNameOas",
                    icon         : "@string/ic_launcher",
                    app_key      : "910JQKA",
                    umeng_channel: "豌豆莢海外版"
            ]
        }
<application
        android:allowBackup="false"
        android:icon="${icon}"
        android:label="${app_name}"
        android:persistent="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="android:allowBackup,android:label, android:icon, android:theme">

這樣第三方SDK的不同key都可以采用占位符來動態(tài)替換,就像上面,當(dāng)我們打海外版包時,就會將app_key和logo替換成另一套

三. 針對debug版本和release版本一些控制,就要用到 buildConfigField 了,buildConfigField 能夠在debug和release中生成不同的BuildConfig,我們在開發(fā)中的是否需要打印日志的控制就可以使用它
buildTypes {
        release {
            minifyEnabled false
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("boolean","show_log","false")
        }

        //預(yù)覽版
        pre {
            minifyEnabled false
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("boolean","show_log","true")
        }

        debug {
            minifyEnabled false
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("boolean","show_log","true")
        }
    }

配置之后我們得到的BuildConfig如下,在代碼中使用直接BuildConfig.xxx就可以

public final class BuildConfig {
  public static final boolean DEBUG = false;
  public static final String APPLICATION_ID = "kotlin.app.com.gradledemo";
  public static final String BUILD_TYPE = "release";
  public static final String FLAVOR = "baidu";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Fields from build type: release
  public static final boolean show_log = false;
}

除了日志開關(guān),其他用的最多的地方還有url環(huán)境的切換,比如debug版本一般我們會用內(nèi)網(wǎng)的url,那么release版本就需要用生產(chǎn)環(huán)境的url

四. 要實現(xiàn)開篇的不同版本的apk名稱不一樣,就需要用到resValue了,它能夠定義資源,并且可以在debug和release等不同版本中來分別定義,例如resValue "string" 就是字符串資源,可以用R.String 來引用對應(yīng)的字符串資源
//在debug下設(shè)置如下
resValue "string","AppName","測試DEV"
resValue "string","AppNameOas","測試海外版DEV"
resValue "string","AppNameSimple","測試1精簡版DEV"

這時候一編譯,就會自動在R.String下生成AppName,AppNameOas,AppNameSimple三個字符串,通過R.String.xxx就可以引用到;
注意:需要將之前values下string下的appName刪除,否則會報資源重復(fù)異常

五. 全局配置文件

project的build.gradle中的ext可以為各位module進行全局配置參數(shù),防止各個module之間的不統(tǒng)一,不可控。而且當(dāng)我們升級sdk、build tool、target sdk等,幾個module都要更改,非常的麻煩。
在項目根目錄建立gradleConfig,然后

ext {
    //統(tǒng)一管理依賴版本
    android = [
            compileSdkVersion: 25,
            buildToolsVersion: '25.0.2',
            applicationId    : "com.test.xxx",
            minSdkVersion    : 17,
            targetSdkVersion : 24,
            versionCode      : 2
            versionName      : "0.1"

    ]

    def dependVersion = [
            support: "25.1.0"
    ]
    dependencies = [
            "appcompat-v7"   : "com.android.support:appcompat-v7:${dependVersion.support}",
            "cardview-v7"    : "com.android.support:cardview-v7:${dependVersion.support}",
            "recyclerview-v7": "com.android.support:recyclerview-v7:${dependVersion.support}",
            "design"         : "com.android.support:design:${dependVersion.support}",
            "support-v4"     : "com.android.support:support-v4:${dependVersion.support}"
    ]
}

然后在每個module中引用

android {

    compileSdkVersion rootProject.ext.compileSdkVersion

    buildToolsVersion rootProject.ext.buildToolsVersion

   defaultConfig {

      applicationId "com.xxx.xxx"

      minSdkVersion rootProject.ext.minSdkVersion

      targetSdkVersion rootProject.ext.targetSdkVersion

      versionCode rootProject.ext.versionCode

      versionName rootProject.ext.versionName
    }
}
六. module 調(diào)整目錄結(jié)構(gòu)sourceSets

默認(rèn)情況下,java文件和resource文件分別在src/main/java和src/main/res目錄下,在build.gradle文件,andorid{}里面添加下面的代碼,便可以將java文件和resource文件放到src/java和src/resources目錄下。

sourceSets {
   main {
      java {
          srcDir 'src/java'
      }
      resources {
        srcDir 'src/resources'
     }
   }
}

簡便寫法

sourceSets {
   min.java.srcDirs = ['src/java']
   min.resources.srcDirs = ['src/resources']
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,886評論 18 139
  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項,請點擊這里進行查閱:DSL參考 1.1新構(gòu)建系統(tǒng)...
    Chuckiefan閱讀 12,171評論 8 72
  • 轉(zhuǎn)載注明出處:http://www.lxweimin.com/p/5255b100930e 0. 前言 完全由個人翻...
    王三的貓阿德閱讀 2,554評論 0 4
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,132評論 25 708
  • 1.有資本 比如有不動產(chǎn)可以出租,有資金可以儲蓄理財。 2.有一個運營良好的公司 自己不上班,也就是要一個可靠的外...
    步履如菲閱讀 580評論 0 50