ok,是我,又是我。主要还是将一天中模糊的知识点进行汇总处理。
早上,这个砖来一个一个需求,老板要求在版本号上面整一个打包日期,也没有要求太详细,就精确到天就好。emmm? 这个明显是不能手动改的,结合物理经验,无论是手动打包还是配置打包脚本,都需要基于gradle project,所以,这个方向就很明确了,这个写到build.gradle里面。那么如何整呢?
正文
我们先来整业务诉求,诉求很简单,每次gradle执行的时候,就存一个值到Android里面,方向有3个,
- 往buildConfig中添加一个属性。
- 往 AndroidMainifest 文件里面丢一个meta-data
- 或者往resources 里面添加一个我们没有定义的 name
那么就开整,为了简单,那就直接写在 defaultConfig 闭包中。
BuildConfig
aidl
var format= DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDate.now())
buildConfigField("String","myName","\"${format}\"")
可以看到,上面的代码的逻辑很简单,往buildConfig 中添加一个field,名称为myName,类型是String,值是格式化后的当前日期。
如果报错了,提示需要开启权限,那就在项目的gradle.properties中添加
aidl
android.defaults.buildfeatures.buildconfig=true
先make project。调用的时候就直接BUildConfig.myName
就可以了。 如果添加其他类型也是类似逻辑。
AndroidMainifest中的meta-data
首先我们需要先定义几个meta-data在AndroidManifest
中。
aidl
<meta-data android:name="my_demo" android:value="${my_demo}"/>
<meta-data android:name="my_demo_1" android:value="${my_demo_1}"/>
同样在 defaultConfig 中添加:
aidl
// 写法1
manifestPlaceholders.put("my_demo","\"${format}\"")
// 写法2,这个其实也是往manifestPlaceholders 这个map里面丢。
addManifestPlaceholders(Map.of("my_demo_1","my_demo2"))
然后是获取meta-data的值:
aidl
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中添加。
aidl
// 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项目中非常重要的配置项,可以根据需要灵活配置代码和资源的放置位置。
aidl
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
通常而言,多网络环境用这个挺多的。写法有很简单:
java
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。所以:
aidl
// 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 :
aidl
flavorDimensionList.apply {
add("channel")
add("cpu")
}
当然了,我们运行一个程序都需要选择以varinat 所以,我们可以基于varints统一配置固定的参数:
aidl
applicationVariants.configureEach {
resValue("color","my_demo6","#FFFFFFFF")
}
sourceSets
既然每次选择都会选择一个variant,所以sourceSets里面就可以拿到flavor自己设置。例如:
aidl
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()的意思是这个可以被执行。只要可以执行到那个闭包中,那么具体实现就是想象空间了。嗯,整体来说还是蛮简单的,主要还是扩充认知,遇到了可以多一种选择罢了。
嗯,今天又没有卡12点,完美。