美文网首页
简单的实现下通过gradle配置设置Android属性

简单的实现下通过gradle配置设置Android属性

作者: BlueSocks | 来源:发表于2023-09-14 17:44 被阅读0次

    早上,这个砖来一个一个需求,老板要求在版本号上面整一个打包日期,也没有要求太详细,就精确到天就好。emmm? 这个明显是不能手动改的,结合物理经验,无论是手动打包还是配置打包脚本,都需要基于gradle project,所以,这个方向就很明确了,这个写到build.gradle里面。那么如何整呢?

    正文

    我们先来整业务诉求,诉求很简单,每次gradle执行的时候,就存一个值到Android里面,方向有3个,

    • 往buildConfig中添加一个属性。
    • 往 AndroidMainifest 文件里面丢一个meta-data
    • 或者往resources 里面添加一个我们没有定义的 name

    那么就开整,为了简单,那就直接写在 defaultConfig 闭包中。

    BuildConfig

            var format= DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDate.now())
            buildConfigField("String","myName","\"${format}\"")
    
    

    可以看到,上面的代码的逻辑很简单,往buildConfig 中添加一个field,名称为myName,类型是String,值是格式化后的当前日期。

    如果报错了,提示需要开启权限,那就在项目的gradle.properties中添加

    android.defaults.buildfeatures.buildconfig=true
    
    

    先make project。调用的时候就直接BUildConfig.myName就可以了。 如果添加其他类型也是类似逻辑。

    AndroidMainifest中的meta-data

    首先我们需要先定义几个meta-data在AndroidManifest 中。

            <meta-data android:name="my_demo" android:value="${my_demo}"/>
            <meta-data android:name="my_demo_1" android:value="${my_demo_1}"/>
    
    

    同样在 defaultConfig 中添加:

            // 写法1 
            manifestPlaceholders.put("my_demo","\"${format}\"")
            // 写法2,这个其实也是往manifestPlaceholders 这个map里面丢。
            addManifestPlaceholders(Map.of("my_demo_1","my_demo2"))
    
    

    然后是获取meta-data的值:

    val  info=packageManager.getApplicationInfo(
                packageName, PackageManager.GET_META_DATA
            )
            info.metaData.keySet().forEach{
                LogUtils.e(it+"  ${info.metaData.get(it)}")
            }
    
    

    可以看到ContextWrapper也有一个getApplicationInfo。但是这个获取到的metaData是空。所以还是得通过GET_META_DATA 获取。

    通过添加res的方式

    这个有一个前提是,定义的res的name及其type没有被定义。还是在defaultConfig中添加。

            // string
            resValue("string","my_demo3","${format}")
            // boolean
            resValue("bool","my_demo4","true")
            // integer
            resValue("integer","my_demo5","5")
            // color
            resValue("color","my_demo6","#FFFFFFFF")
    
    

    这个设置的字段必须是没有定义在res下面的,重新make project 在build/res/resValues/debug/values/gradleResValues.xml 就可以看到设置成功的内容了。 通常来说,值都应该用双引号保存。

    其他方案

    其他方案上来说,可能就是生成文件或者生成class的区别了。 生成文件,然后通过gradle 脚本复制到assets 目录下。生成的class 就需要放到指定的源码路径中了。

    当然了也可以设置资源和class源码所在路径,那么就可以用到sourceSets。 在Android项目中,通过sourceSets可以配置代码和资源的放置位置。

    sourceSets中的属性有:

    • java:指定Java代码的目录。
    • assets:指定资产文件的目录。
    • aidl:指定AIDL文件的目录。
    • jni:指定JNI文件的目录。
    • jniLibs:指定JNI库的目录。
    • manifest:指定清单文件的目录。
    • renderscript:指定RenderScript文件的目录。
    • res:指定资源文件的目录。
    • resources:指定资源文件的目录,与res功能相同。

    除了上述属性外,sourceSets还可以通过setRoot(String path)方法,来显式指定特定的文件和目录。例如,如果在sourceSets中有多个目录,可以使用setRoot方法来设置根目录。 总之,sourceSets是Android项目中非常重要的配置项,可以根据需要灵活配置代码和资源的放置位置。

        sourceSets {
            getByName("main"){
                println( jniLibs)
                println( java)
                println( assets)
                println( aidl)
                println( jni)
                println( jniLibs)
                println( manifest)
                println( renderscript)
                println( res)
                println( resources)
            }
            // getByName(main) 和下面这种写法是一致的。
            main {
                println( jniLibs)
                println( java)
                println( assets)
                println( aidl)
                println( jni)
                println( jniLibs)
                println( manifest)
                println( renderscript)
                println( res)
                println( resources)
            }
        }
    
    

    扩展:渠道、马甲或多环境

    既然都写到这里了,感觉要不把马甲包和多环境的配置一起整了吧。上面的知识很多时候都是整马甲包或者多环境配置来着。像今天这种小众的需求还是很少的。

    那么这种差异化的需求,通常有两种方式:

    • 一种是整多个 buildType
    • 一种是整多个 productFlavors

    buildType

    通常而言,多网络环境用这个挺多的。写法有很简单:

    buildTypes {
        release {
            resValue("color","my_demo8","#FFFFFFFF")
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            resValue("color","my_demo9","#FFFFFFFF")
            signingConfig signingConfigs.debug
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        text {
            resValue("color","my_demo6","#FFFFFFFF")
            signingConfig signingConfigs.debug
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    
    

    基于release或者debug 复制一个即可,然后在里面配置参数。

    productFlavors

    通常而言,这个主要是做马甲包,渠道包多一些,因为涉及到不同的目的切换不同的埋点,资源,cpu架构等等。 kotlin dsl 和groovy dsl 写法没有多少区别。都是基于flavorDimensions。所以:

        // groovy 写法
        // 方式1
        //flavorDimensions.flavorDimensions.add("cpu")
        //flavorDimensions.flavorDimensions.add("channel")
        // 方式2
        flavorDimensions("cpu","channel")
        productFlavors {
            create("baidu"){
                dimension="channel"
            }
            create("x86"){
                dimension="cpu"
            }
        }
    
    

    kotlin 设置 flavorDimensionList :

    flavorDimensionList.apply {
            add("channel")
            add("cpu")
        }
    
    

    当然了,我们运行一个程序都需要选择以varinat 所以,我们可以基于varints统一配置固定的参数:

        applicationVariants.configureEach {
            resValue("color","my_demo6","#FFFFFFFF")
        }
    
    

    sourceSets

    既然每次选择都会选择一个variant,所以sourceSets里面就可以拿到flavor自己设置。例如:

        sourceSets {
            main {
                println( jniLibs)
                println( java)
                println( assets)
                println( aidl)
                println( jni)
                println( jniLibs)
                println( manifest)
                println( renderscript)
                println( res)
                println( resources)
            }
            baidu{
                println("baidu:" +java)
            }
        }
    
    

    总结

    可以看到上面很多printlin,写printlin()的意思是这个可以被执行。只要可以执行到那个闭包中,那么具体实现就是想象空间了。嗯,整体来说还是蛮简单的,主要还是扩充认知,遇到了可以多一种选择罢了。

    相关文章

      网友评论

          本文标题:简单的实现下通过gradle配置设置Android属性

          本文链接:https://www.haomeiwen.com/subject/ccnmvdtx.html