Gradle动态编译能力
Android的Gradle插件内置了一些轻量且便捷的动态编译能力,不用写复杂的脚本也能在编译期生成动态变化的内容。
本文内容原写于2019年,如文中内容如今已有变化,劳烦告知。
动态生成Java常量
// build.gradle
def timestamp(format = 'yyyyMMdd_HHmmss') {
new java.text.SimpleDateFormat(format).format(new Date())
}
android {
//...
buildTypes {
all {
buildConfigField 'int', 'BUILD_NUMBER', "${System.getenv('build_number').toInteger()}"
buildConfigField 'boolean', 'FEATURE_ENABLED', "${System.getenv('feature_enabled').toBoolean()}"
buildConfigField 'String', 'BUILD_TIME', "\"${timestamp()}\"" // 注意引号
}
}
}
// build/generated/source/buildConfig/debug/com/example/BuildConfig.java
package com.example;
public final class BuildConfig {
//...
public static final int BUILD_NUMBER = 1;
public static final boolean FEATURE_ENABLED = true;
public static final String BUILD_TIME = "20190411_195418";
}
实际应用中,如果增强一下脚本甚至可以生成Map
这样的复杂数据结构。
在普通的Java Application中也可以使用BuildConfig
,只需要引入一个独立的Gradle插件:
buildscript {
repositories {
//...
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
//...
classpath "com.github.gmazzo:gradle-buildconfig-plugin:1.6.2"
}
//...
}
apply plugin: "com.github.gmazzo.buildconfig"
buildConfig {
packageName 'com.example'
buildConfigField 'String', 'LIBRARY_VERSION', "\"${BUILD_VERSION}\""
}
动态生成资源
// build.gradle
android {
//...
buildTypes {
debug {
resValue "string", "example_resource", "only use for test: ${new SimpleDateFormat("yyyyMMddHHmm").format(new Date())}"
}
}
}
<!-- 编译后的strings.xml -->
<string name="example_resource">only use for test: 201904111949</string>
动态修改AndroidManifest.xml
// build.gradle
android {
//...
buildTypes {
all {
manifestPlaceholders = [BUILD_TIME_STUB: new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())]
}
}
}
<!-- AndroidManifest.xml 编译前 -->
<meta-data android:name="BUILD_TIME" android:value="${BUILD_TIME_STUB}" tools:replace="android:value"/>
<!-- AndroidManifest.xml 编译后 -->
<meta-data android:name="BUILD_TIME" android:value="20190411_195418" />
另外,对AndroidManifest.xml
而言applicationId
是内置的,可以直接使用:
<!-- AndroidManifest.xml -->
<provider
android:exported="true"
android:name="com.example.MyContentProvider"
android:authorities="${applicationId}.myprovider"
android:process=":daemon" />
动态生成assets
afterEvaluate {
android.applicationVariants.all { variant ->
variant.mergeAssetsProvider.get().with {
setOnlyIf { true }
outputs.upToDateWhen { false }
doLast {
copy {
from sourceFile
into outputs.files.files.grep({
!it.absolutePath.contains('incremental')
}).first()
// like: build/intermetiates/assets/debug/mergeDebugAssets
}
}
}
}
}
通过上述脚本,可以把sourceFile
打包到apk的assets
目录下。这段脚本在Gradle-7.2和AGP-7.1.3环境下测试通过。