Android 配置化参数动态化方案

背景

随着 APP 的发展,以及业务的需求,有时我们需要提供代码业务逻辑相同,而页面展示的元素有部分差异的APP,那我们如何快速的产出 APP ,打造 APP 产品矩阵?

​ 目前 Google 官方已提供了构建变异体 APP 代码的能力,简单来说就是直接配置就可以了,并不需要我们处理太多东西;

基本步骤

这部分大同小异,没有什么需要说明的,直接看步骤即可

创建与 app/src/main 同级别的产品目录,里面保持与 main 里相同的目录结构

文件目录结构:

0n55AX_01_05

app gradle 中配置:

android {
    compileSdkVersion 30
    defaultConfig {
        ...
        // 参数化打包配置
        flavorDimensions "app"
    }

    // product 定义
    productFlavors {
        product_1 {
            dimension "app"
            applicationId = "com.egan.product_1"
        }
        product_2 {
            dimension "app"
            applicationId = "com.egan.product_2"
        }

    }

    buildTypes {
        release {
            ...
        }

        debug {
            ...
        }
    }
}

productFlavors 中定义名称需要与文件夹保持一致,这样会自动定位到我们的文件,而不用我们在进行配置文件路径

这样一个基本的构建 APP 变异体的配置就算基本完成了;我们仅仅处理了 applicationId 的差异;

当然我们也可以处理 versionNameversionCode 等参数

我们除了在不同产品文件夹下处理资源文件以外,系统也提供了通过 脚本代码进行字符串等资源的写入

在编译时动态处理 res value

resValue "string", "AppName", "app1"

相当于在res/strings.xml 下增加一个名为 AppName,值为 app1 的资源。在java中的使用 resValuestrings.xml 的数据方式是一样的,context.getResources().getString(AppName);

在编译时动态处理 BuildConfig

buildConfigField "String", "AppName", "\"app1\"

java 代码中 BuildConfig.AppName 可以正常读取到写入的数据

在编译是动态处理 Manifest

manifestPlaceholders = [key: "value"]

manifest 中就可以通过 ${key} 的方式读取到数据,java 代码中可以通过读取 meta-data 来获取数据

以上算是基本配置构建变异体的基本步骤


下面说点不一样的:

大量参数的动态配置

我们如果需要处理少量的配置,这样配置问题不大,包括后续进行调整也并不麻烦;

痛点:

​ 如何在构建的时候动态指定不同产品的 build 模式:

举个例子:

  1. product_1 中,我需要区分 debugrelease 环境
  2. product_2 中,我需要区分 debugrelease 环境
  3. product_1product_2 中的 debugrelease 环境的配置参数的值又不相同

那我如何动态的处理,保证构建出来的 apk 符合预期?

由于脚本的执行是顺序的,如果我们在配置 product 是又区分了 debug、release ,那你会发现,我们构建出来的 apk 里面配置的数据都是脚本中最后一个配置生效;

解决方案:

productFlavors.all { flavor ->
    // flavor 是我们构建的变异体产品,这里可以配置 applicationId、versionName、versionCode 等数据
    def flavorName = flavor.name
}

applicationVariants.all { variant ->
    // variant 这里我们可以拿到
    // 产品名称
    def productName = variant.flavorName
    // 打包类型
    def buildType = variant.buildType.name
  	// 当拿到产品名称以及 打包类型的情况,就可以通过 外部配置文件,动态读取不同配置,通过 resValue 写入文件,项目中正常获取
}

比如测试项目的配置:

applicationVariants.all { variant ->

    println("applicationVariants >>> ${variant.name}")
    // 产品
    def productName = variant.flavorName
    // 打包类型
    def buildType = variant.buildType.name

    // 构建的特定产品参数
    def buildProductParams = productParams.get(productName)
    // 全部需要写入的参数
    def buildParams = buildProductParams[buildType]
    buildParams.each { k, v ->
        // 需要写入数据
        println("需要写入数据: $k  :  $v")
        resValue("string", k, v)
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值