Android buildTypes和productFlavors实现差异化打包

什么是buildTypes和productFlavors

https://developer.android.com/build/build-variants?hl=zh-cn

1. buildTypes

buildTypes 主要用于定义不同的构建变体,通常用于区分不同的构建模式,如开发版、发布版等。每个 buildType 都会有一组配置项,通常是与构建过程和构建输出相关的配置。常见的 buildTypes 包括:

  • debug:用于调试构建,通常包含日志和调试功能。
  • release:用于发布构建,通常会启用混淆、签名、优化等。

一共这些方法

https://developer.android.com/reference/tools/gradle-api/8.7/com/android/build/api/dsl/BuildType

buildTypes 定义的是构建过程的行为,它影响的是最终的 APK 构建方式,例如签名方式、混淆规则等。

android {
    buildTypes {
        debug {
            minifyEnabled false // 不启用混淆
            debuggable true
        }
        release {
            minifyEnabled true // 启用混淆
            shrinkResources true // 去除未使用的资源
            signingConfig signingConfigs.release
        }
    }
}
 

2. productFlavors

productFlavors 用于定义不同的产品变体,通常是用来支持不同的产品版本或配置,比如免费版和付费版、不同地区的版本等。通过 productFlavors,你可以为不同的版本提供不同的代码、资源或配置。

productFlavors 允许你在同一个项目中创建多个产品变体,每个变体可以有不同的资源、应用 ID、版本号等。

android {
    flavorDimensions "version"
    productFlavors {
        free {
            applicationId "com.example.app.free"
            versionName "1.0-free"
        }
        paid {
            applicationId "com.example.app.paid"
            versionName "1.0-paid"
        }
    }
}
 

区别总结:

  • buildTypes 控制构建过程的行为(如是否启用混淆、签名、调试信息等),默认有 debugrelease 两种常见类型。
  • productFlavors 控制应用的版本和特性(如免费版、付费版、不同地区版本等),让你可以为不同的目标配置不同的资源和代码。

在安卓开发过程中,难免会遇到像以下这样的一些需求:

  1.需要打不同市场的包像opp  vivo等,用于友盟统计各个市场的下载量

  2.需要打测试包,生产包等,要求每个报名下的app名称,应用图标,appid ,url不同,甚至代码

像以上的一些需求我们称之为Android的差异化打包

现在我们一起来配置,下面的图是我配置好的

   productFlavors{
        //todo a ,b,c,d等是打包提供的一些标志名称,打包的时候可以选择
        a{
            applicationId "com.example.myapplication1"
            resValue "string", "app_name", "测试a"
            buildConfigField 'String', 'BASE_URL', '"我时a 的路由"'
            manifestPlaceholders=[
                    APPICON : "@mipmap/ic_launcher",
            ]
        }
        b{
            applicationId "com.example.myapplication2"
            resValue "string", "app_name", "测试b"
            buildConfigField 'String', 'BASE_URL', '"我时b 的路由"'
            manifestPlaceholders=[
                    APPICON : "@mipmap/down",
            ]
        }
        c{
            applicationId "com.example.myapplication3"
            resValue "string", "app_name", "测试c"
            buildConfigField 'String', 'BASE_URL', '"我时c 的路由"'
            manifestPlaceholders=[
                    APPICON : "@mipmap/up",
            ]
        }
        d{
            applicationId "com.example.myapplication4"              //修改application
            resValue "String", "app_name", "测试d"                  //todo 修改res中的资源
            buildConfigField 'String', 'BASE_URL', '"我时d 的路由"'  //todo 用来根据不同的包,更换不同的utl
            manifestPlaceholders=[
                    APPICON : "@mipmap/app_icon_mail",  //todo 清单文件中映射的值
            ]
        }
    }

然后运行的时候运行和打包的时候可以选择,这里以运行为列,点击如下按钮,可以选择当前运行包的环境

介绍完productFlavors 后,我们现在带着问题来解释下他的一些属性和用法

问题1:

manifestPlaceholders  占位符的使用,其实很好理解,你可以认为它可以在 build.gradle文件中定义字符串并将值映射到 AndroidManifest清单文件的指定位置.

如何使用呢?

首先在AndroidManifest中设置需要替代的字段

然后在build.gradle中设置清单文件中替代文字需要映射的值

  d{
           
            manifestPlaceholders=[
                    APPICON : "@mipmap/app_icon_mail",  //todo 清单文件中映射的值
            ]
        }

问题2:

resValue  这个指定后,会在build完成后,会在build文件里面生成值,例如
resValue "String", "app_name", "测试a"    //他会在build文件夹生成如下
<string name="app_name" translatable="false">测试b</string>

如果你本里的values文件夹下存在了该

<string name="app_name">ExpandedRecycleViewDemo</string>

那么程序则会报错,因为build时会存在两个app_name的name

buildConfigField   这个属性很好用,这个属性在build后会生成一个buildConfig.java的文件里面有许多可以使用的信息,因此我们可以把BASEURL设置在此,我的是如下配置
    d{
            applicationId "com.example.myapplication4"              //修改application
            resValue "String", "app_name", "测试d"                  //todo 修改res中的资源
            buildConfigField 'String', 'BASE_URL', '"我时d 的路由"'  //todo 用来根据不同的包,更换不同的utl
            manifestPlaceholders=[
                    APPICON : "@mipmap/app_icon_mail",  //todo 清单文件中映射的值
            ]
        }

接下来看下buildConfig的文件

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.example.myapplication2";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "b";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Fields from product flavor: b
  public static final String BASE_URL = "我时b 的路由";
}

变生成了我设置的baseURL ,

以后就可以根据不同的打包环境生成不同的BASEURL

使用变体感知型依赖项管理机制   (这里指的是module ,不是线上的依赖库)

Android Gradle 插件 3.0.0 及更高版本包含一种新的依赖项机制,该机制可在使用库时自动匹配变体。这意味着,应用的 debug 变体会自动使用库的 debug 变体,依此类推。这种机制在使用变种时也同样适用:应用的 freeDebug 变体将使用库的 freeDebug 变体。

为了让插件准确匹配变体,您需要在无法进行直接匹配的情况下,按照以下部分中所述提供匹配回退机制

例如,假设您的应用配置了一个名为“staging”的 build 类型,但该应用的一个库依赖项没有进行相应配置。当插件尝试构建“staging”版本的应用时,它不知道要使用哪个版本的库,因此您将看到一条与以下内容类似的错误消息

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app
解决与变体匹配相关的构建错误 :

您的应用包含库依赖项不包含的 build 类型

例如,您的应用包含“staging”build 类型,但依赖项仅包含“debug”和“release”build 类型。

请注意,如果库依赖项包含您的应用不包含的 build 类型,这不会引发问题。这是因为,插件在任何时候都不会从依赖项请求该 build 类型。

使用 matchingFallbacks 为给定的 build 类型指定替代匹配项,如下所示:

app模块

 buildTypes {
        register("benchmark") {
            isMinifyEnabled = true
            signingConfig = signingConfigs.getByName("release")
            proguardFiles(
                getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            )
            multiDexKeepProguard = file("multidex-rules.pro")
            matchingFallbacks += listOf("debug", "release")
        }
        release {
            isMinifyEnabled = true
            isShrinkResources = true
//            isDebuggable = true
            signingConfig = signingConfigs.getByName("release")
                    proguardFiles(
                getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            )
            multiDexKeepProguard = file("multidex-rules.pro")
        }
        debug {
//            buildConfigField("boolean","name","2")
            isMinifyEnabled = true
            applicationIdSuffix = ".debug" // 调试版应用 ID 后缀
            signingConfig = signingConfigs.getByName("release")
            proguardFiles(
                getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            )
            multiDexKeepProguard = file("multidex-rules.pro")
        }

        create("pre") {
//            buildConfigField("boolean","name","1")
            isDebuggable = true
        }

    }
module模块
  buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }

    }
module模块的buildTyp比 app少了benchmark

所以选择benchmark编译的时候会报错, 

这个时候在app下添加,就行

matchingFallbacks += listOf("debug", "release")。// 选择benchmark模块的时候,其他module没有benchmark,则从listOf("debug", "release")集合中取,优先debug

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值