Android Gradle Plugin 3.0 中的 productFlavors 知识

#android gradle plugin

productFlavors 新版配置

参考资料: gradle-plugin-3-0-0-migration

如果我们在 module 的 build.gradle 指定了某个 product flavor。如下图所示:

productFlavors {
  // flavor name
  free {}
}

那么必须指定一个 flavor dimension。否则会报错 Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html

根据文档修改为如下代码:

// freeDimension 为 dimension name
flavorDimensions "freeDimension"

productFlavors {
  // flavor name
  free {}
}

上面代码配置等同于下面的代码:

// freeDimension 为 dimension name
flavorDimensions "freeDimension"

productFlavors {
  // flavor name
  free {
    dimension "freeDimension"
  }
}

原因是我们只指定了一种 flavor dimension — freeDimension。

假如 productFlavors 中包含多个 flavor,也是一样的道理,flavor 中指定的 dimension 默认为 freeDimension。

例如:

// freeDimension 为 dimension name
flavorDimensions "freeDimension"

productFlavors {
  // flavor name
  free {
    dimension "freeDimension"
  }
  paid {
    dimension "freeDimension"
  }
}

等同于

// freeDimension 为 dimension name
flavorDimensions "freeDimension"

productFlavors {
  // flavor name
  free {}
  paid {}
}

基本概念

看到这里,我们要明确两个概念,productFlavors 中的 flavor name 和 flavorDimensions 中的 dimension name 是两个东西,不一定要同名。

那么,它们的关系是什么呢?

productFlavors 中的某个 flavor 必须指定某个 dimension,flavorDimensions 下面的 dimension 个数决定了 productFlavors 最多可以被分为几大类。而 productFlavors 下面所有的 flavor 都需要选择“站队“。 (指定 dimension 就是在选择类型)

请往下看例子

例子

假设我们有 app module 和 library module,app module 依赖 library module。

配置一

app module 中的 build.gradle 配置为:

android {
  // ... 省略

  buildTypes {
    release {
      minifyEnabled false
    }
  }

  flavorDimensions "freeDimension"

  productFlavors {
    free {}
    paid {}
  }
}

dependencies {
  implementation project(':library')
}

library module 中的 build.gradle 配置为:

android {
  // ... 省略
  
  buildTypes {
    release {
      minifyEnabled false
    }
  }
}

最后看下 Build Variants 中的配置:

结果显示:当 app module 中所有 product flavor 都属于同一种 flavor dimension 时,其行为和之前使用 Android Plugin 2.3 系列基本一致。

配置二

app module 中的 build.gradle 配置变为:

flavorDimensions "freeDimension", "paidDimension"

productFlavors {
  free {
    dimension "freeDimension"
  }
  paid {
    dimension "paidDimension"
  }
}

library module 中的 build.gradle 和配置一相同。

最后看下 Build Variants 中的配置:

library module 的配置没有变话,不贴图了。

结果显示:free 和 paid 两个 flavor 由于属于两种 flavor dimension 时,这两个 flavor 会同时编译。请看下图:

如果 app module 种包含三个 flavor 而且分别属于三种 flavor dimension 时,大家猜猜是怎么样?

结果如下:

配置三

app module 中的 build.gradle 配置为:

flavorDimensions "freeDimension", "paidDimension"

productFlavors {
  free {
    dimension "freeDimension"
  }
  paid {
    dimension "freeDimension"
  }
  discount {
    dimension "paidDimension"
  }
}

结果如下:

假如 paidDimension 下面增加一个 flavor 会如何呢?

flavorDimensions "freeDimension", "paidDimension"

productFlavors {
  free {
    dimension "freeDimension"
  }
  paid {
    dimension "freeDimension"
  }
  discount {
    dimension "paidDimension"
  }
  limited {
    dimension "paidDimension"
  }
}

结果如下:

结论

productFlavors 中的 flavor 会根据 flavor dimension 类型分类,然后每个类型下面的 flavor 再分别组合形成新的 product flavor,再与 build type 进行组合,最后构成 Build Variants。

新的 product flavor 个数怎么计算呢?

假设 productFlavors 中所有的 flavor 根据 flavor dimension 分为 N 类(N >= 1),每个类型下面的 flavor 个数为 M1,M2,M3 … M++,新的 product flavor 个数为 F,那么有如下公式:

F = M1 * M2 * M3 * ... * M++

而且,无论 productFlavors 中有几种 flavor dimension 类型,都会在每个类型下选取 flavor 之后同时编译代码。

至此,我们弄清楚了单个 module 中 productFlavors 的配置规律。

代码示例

TestAndroidPlugin-3_0_0-Demo

小提示

我们不可以声明多余的 flavor Dimension,否则会报错。

假如配置如下:

flavorDimensions "freeDimension", "paidDimension", "discountDimension"

productFlavors {
  free {
    dimension "freeDimension"
  }
  paid {
    dimension "freeDimension"
  }
  discount {
    dimension "discountDimension"
  }
}

报错如下:

Error:No flavor is associated with flavor dimension 'paidDimension'.

配置中只使用了 freeDimension 和 discountDimension,所以会报错。