Gradle打包APK的一些小技巧和productFlavor配置

前言

在使用Gradle來打包Android應用以前,Android自動化打包一般會選擇使用ant,ant是一種一步一步來執行任務的工具,一般打包一個apk要通過一個複雜的過程,ant工具經過一步一步完成這些過程來生成一個apk。若是要實現一個複雜一點的打包過程,它的xml配置文件的長度也是足以讓你崩潰的。Gradle的出現讓打包過程變得十分輕鬆,並且配置起來也是簡單易懂。之前須要寫好幾天的配置文件如今只要簡單的幾步就能完成,配合Android Studio更加駕輕就熟。android

一個完整的打包流程以下: picapp

基本的build.gradle

若是你用Android Studio生成一個項目的話,在app模塊中你會看到一個build.gradle文件,這個文件就是配置這個模塊的地方,大體文件結構以下:ide

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

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

這裏就不一行行地解釋了,關於Gradle的語法能夠自行Google。工具

這裏主要有兩個小技巧gradle

  1. 簽名:開發App時常常遇到Release版和Debug版共存問題,因爲默認的簽名不一樣,常常要卸載Debug版安裝Release版,很是麻煩。有兩種方法能夠避免這種狀況:1. 使用同一個簽名;2. 使用不一樣包名
// 方法1 (簽名配置方法能夠Google)
android {
   buildTypes {
       debug {signingConfig signingConfigs.myConfig}
       release {signingConfig signingConfigs.myConfig}
   }
}
// 方法2 
android {
   buildTypes {
       debug {packageNameSuffix ".debug"}
   }
}
  1. Release版打包的apk文件名:經過下面的代碼能夠自動爲生成的apk文件附加上版本和build日期,這裏能夠根據你的需求添加各類信息上去。
android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            def today = new Date()
            if (variant.buildType.getName().equals("release")) {
                println "Change output apk name"
                variant.outputs.each { output ->
                    output.outputFile = new File(
                            output.outputFile.parent,
                            output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + "-" + today.format('yyyyMMdd') + ".apk"))
                }
            }
        }
    }
}

BuildVariants

Gradle的Android插件中有個BuildVariants的概念,其實簡單來講其實就是buildTypes+productFlavors,buildType前面咱們看到過了,主要就是debug和release的分別。而productFlavors就是咱們用來打包不一樣版本app的主要方式。從字面意思來翻譯指的就是不一樣的「產品特色」。ui

Android Studio會自動根據build.gradle 生成對應的BuildVariants。好比如下代碼:google

android {
    productFlavors {
        free {}
        paid {}
    }
}

會生成如下的BuildVariants:spa

pic

productFlavors的維度

productFlavors能夠是多維的,聽起來好像很難理解,這裏舉個栗子,有以下代碼:插件

android {
    flavorDimensions("isfree", "channel")
    productFlavors {
        free {dimension "isfree"}
        paid {dimension "isfree"}

        googleplay {dimension "channel"}
        wandoujia {dimension "channel"}
    }
}

可以生成以下的BuildVariants:翻譯

pic

這裏咱們就能夠看到,咱們有兩個維度,一個是是否免費,另外一個是渠道,咱們可以生成2*2=4種Flavor,而且每一個Flavor都有debug和release,總共就有8種不一樣的APK。因此理論上來講經過組合Flavor,咱們能夠作到各類不一樣的分類。

接下來咱們來看看productFlavors能作什麼? ### 定義渠道

在國外通常來講開發者不太須要去管渠道的問題,他們的App只須要發往GooglePlay就能夠了,可是在中國,咱們有衆多的APK分發平臺,咱們的APK須要發往各類地方,在作APP統計的時候咱們就須要在APK裏寫入一些特徵變量,發送到統計平臺,以區分不一樣的渠道,在過去用ant打包的時代,咱們一般的作法就是用不一樣的渠道名來重複ant任務一遍一遍地打包。

若是用gradle:咱們能夠經過增長一個名爲channel的dimension來給每個渠道一個特殊標示,代碼就是咱們以前看到的。可是你可能會問,我怎麼在統計的時候獲取這個渠道名呢?其實很簡單,Android Studio會爲咱們生成一個名叫BuildConfig的類,這個類有一些關於打包的靜態變量,下面是一個示例:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "me.zheteng.android.example";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "freeGoogleplay";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  public static final String FLAVOR_isfree = "free";
  public static final String FLAVOR_channel = "googleplay";
}

其實不止是渠道,經過這個類咱們還能夠很方便地得到這個APK的各類信息。相信你們一眼就能看出來每一個字段的意思。(咱們甚至還能夠自定義字段)。

若是渠道很是多,你也能夠經過讀配置文件的方式動態生成不一樣的flavors。

若是我每一個flavor都有點特別呢?

有的時候咱們每一個flavor可能不僅是一個渠道名這麼簡單,個人ICON可能給每一個渠道的有所不一樣,個人包名也可能有所不一樣。全部這些,均可以直接在這個flavor中從新定義:

android {
    productFlavors {
        googleplay {
            applicationId "me.zheteng.android.example.googleplay"
        }
    }
}

若是須要不一樣的源代碼或資源文件,能夠在app/src下新建一個名爲「flavor名」的目錄(這裏就是googleplay)。也就是app/src/googleplay,而後這個目錄下的結構和app/src/main中是同樣的,打包的時候會優先使用當前flavor下的文件。

其餘Gradle小技巧

Provider名稱

咱們知道Provider的authority是系統中全局惟一的,有時候咱們要爲不一樣的flavor將authority改爲不一樣的,經過gradle你能夠這樣實現:

<provider
    android:exported="true"
    android:name="com.path.to.my.Provider"
    android:authorities="${applicationId}.provider"/>

你問我Java代碼中怎麼獲取?難道你忘了BuildConfig了嘛?

Manifest 佔位符

有些SDK會把配置在Manifest文件中的meta信息裏,而不一樣的flavor這個信息不同,這是咱們能夠經過Manifest 佔位符來實現:

<meta-data android:value="${UMENG_APPKEY}" android:name="UMENG_APPKEY"/>
android {
    productFlavors {
        googleplay {
            applicationId "me.zheteng.android.example.googleplay"
            manifestPlaceholders = [UMENG_APPKEY: "個人友盟KEY"]
        }
    }
}

總結

Gradle的靈活程度超乎想象,若是基本功能沒法知足你,你還能夠經過本身編寫Groovy插件或者task來實現無窮的可能性,歡迎將你的思路分享出來~

相關文章
相關標籤/搜索