通过Gradle脚本声明更改Java变量

Android/Java 开发中的常见需求:在编译时将 Gradle 中定义的值注入到 Java 代码中 ,那么如何通过 Gradle 脚本声明/更改 Java 变量

buildConfigField(最常用)

build.gradle 中定义字段,编译后自动生成到 BuildConfig 类中。

复制代码
android {
    defaultConfig {
        // 类型、字段名、值
        buildConfigField "String",  "API_BASE_URL",  '"https://api.example.com"'
        buildConfigField "boolean", "ENABLE_LOGGING", "true"
        buildConfigField "int",     "MAX_RETRY",     "3"
        buildConfigField "long",    "BUILD_TIME",    "${System.currentTimeMillis()}L"
    }

    // 也可以按 flavor / buildType 分别定义
    buildTypes {
        debug {
            buildConfigField "String", "API_BASE_URL", '"https://debug.api.example.com"'
            buildConfigField "boolean", "ENABLE_LOGGING", "true"
        }
        release {
            buildConfigField "String", "API_BASE_URL", '"https://api.example.com"'
            buildConfigField "boolean", "ENABLE_LOGGING", "false"
        }
    }
}

Java 端使用

复制代码
// 自动生成的 BuildConfig 类,直接引用
String url     = BuildConfig.API_BASE_URL;
boolean logging = BuildConfig.ENABLE_LOGGING;
int retry      = BuildConfig.MAX_RETRY;

编译后会在 build/generated/source/buildConfig/.../BuildConfig.java 自动生成对应字段。

通过 gradle.properties + BuildConfig

将值集中管理在属性文件中,Gradle 读取后注入。

gradle.properties

复制代码
API_BASE_URL=https://api.example.com
ENABLE_LOGGING=true
MAX_RETRY=3

build.gradle

复制代码
// 读取属性(注意类型转换)
buildConfigField "String",  "API_BASE_URL",  "\"${project.properties['API_BASE_URL']}\""
buildConfigField "boolean", "ENABLE_LOGGING", project.properties['ENABLE_LOGGING']
buildConfigField "int",     "MAX_RETRY",     project.properties['MAX_RETRY']

自动生成 Java 源文件

当需要的变量较多、或者不想依赖 BuildConfig 时,可以直接生成一个 .java 文件。

复制代码
android {
    applicationVariants.all { variant ->
        def task = variant.registerJavaGeneratingTask(
            "generate${variant.name.capitalize()}Config",
            file("${buildDir}/generated/source/config/${variant.dirName}")
        )
        task.get().doLast {
            def outputDir = file("${buildDir}/generated/source/config/${variant.dirName}/com/example")
            outputDir.mkdirs()
            def configFile = new File(outputDir, "AppConfig.java")
            configFile.text = """
                package com.example;

                public final class AppConfig {
                    public static final String API_BASE_URL = "https://api.example.com";
                    public static final boolean ENABLE_LOGGING = ${variant.buildType.isDebuggable()};
                    public static final int MAX_RETRY = 3;
                }
            """.stripIndent()
        }
    }
}

Java 端直接用:

复制代码
String url = AppConfig.API_BASE_URL;

Manifest 占位符(Android Manifest 专用)

用于向 AndroidManifest.xml 注入变量。

复制代码
android {
    defaultConfig {
        manifestPlaceholders = [
            APP_NAME: "MyApp Debug",
            CHANNEL:  "google_play"
        ]
    }
}

<!-- AndroidManifest.xml -->
<application
    android:label="${APP_NAME}"
    android:name=".MyApp">
    <meta-data
        android:name="CHANNEL"
        android:value="${CHANNEL}" />
</application>

系统属性(主要用于测试)

复制代码
test {
    systemProperty "api.url", "https://test.api.example.com"
    systemProperty "thread.count", "8"
}

// 测试代码中
String apiUrl = System.getProperty("api.url");

各方案对比

方案 适用场景 优点 缺点
buildConfigField 常量配置、环境区分 最简单,官方支持 仅限 Android,字段生成在 BuildConfig 中
gradle.properties + BuildConfig 集中管理配置 配置与代码分离 本质仍是方案一的包装
生成 Java 源文件 大量配置 / 非 Android 项目 完全自定义 实现稍复杂
Manifest 占位符 AndroidManifest 动态值 直接替换 XML 仅限 Manifest
systemProperty 单元测试 简单直接 仅限运行时

常见注意事项

字符串引号陷阱:

复制代码
// 错误 --- Java 端会缺少引号,编译报错
buildConfigField "String", "URL", "https://example.com"

// 正误 --- 值本身要包含 Java 字符串的双引号
buildConfigField "String", "URL", '"https://example.com"'
// 或
buildConfigField "String", "URL", "\"https://example.com\""

敏感信息不要硬编码:

复制代码
android {
    defaultConfig {
        buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
        buildConfigField("boolean", "ENABLE_LOGGING", "true")
    }
}

Kotlin DSL(build.gradle.kts)写法:

复制代码
android {
    defaultConfig {
        buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
        buildConfigField("boolean", "ENABLE_LOGGING", "true")
    }
}

其他完整事例:

复制代码
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 31

    ArrayList src_lines
    File versionPropsFile

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        //com.example.myapplication  java ,kt 代码
                
        versionPropsFile = file('./src/main/java/com/example/myapplication/MainActivity.kt')
        if (versionPropsFile.canRead()) {
            def stream = new BufferedReader(new InputStreamReader(new FileInputStream(versionPropsFile), "UTF-8"))
            def lines = stream.readLines()
            src_lines = new ArrayList<String>()
            src_lines.addAll(lines)
            stream.close()
            for (int i = 0; i < lines.size(); i++) {
                def line = lines.get(i)
                // 替换java中 包含 "1234"的行
                if (line.contains("1234")) {
                    lines.set(i, "val i = 4567")
                }
                // 替换java中 包含 "我是未修改过的文字或代码"的行
                if (line.contains("我是未修改过的文字或代码")) {
                    lines.set(i, " return \"我已被Gradle动态修改了...而且int值改成了\"+i")
                }
            }
            def writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(versionPropsFile), "UTF-8"))
            for (def line : lines) {
                writer.writeLine(line)
                println(line)
            }
            writer.flush()
            writer.close()


//            new Thread(new Runnable() {
//                @Override
//                void run() {
//                    Thread.sleep(1000)
//                    def writer2 = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(versionPropsFile), "UTF-8"))
//                    for (def line : src_lines) {
//                        writer2.writeLine(line)
//                    }
//                    writer2.flush()
//                    writer2.close()
//                }
//            }).start()
        }

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        viewBinding true
    }
}


task task7() {
    modifyBuildTime()
}

def modifyBuildTime() {
    // res中json文件 [ { "id": "1", "courseID": "1640850159135", "title": "一加一等于几" }, { "id": "2", "courseID": "1640850159135", "title": "请背诵全文" } ]
    def path = "app\\src\\main\\res\\raw\\test.json"
    def time = new Date().getTime()
    println("buildtime =========== " + time)
    def keyword = "courseID"
    def newString = "    \"courseID\": \"" + time + "\","
    def content = fileReader(path, keyword, newString)
    fileWrite(path, content)
}


//读取文件并替换字符串
def fileReader(path, keyword, newString) {
    def readerString = "";
    new File(path).withReader('UTF-8') { reader ->
        reader.eachLine {
            if (it.contains(keyword)) {
                it = it.replace(it, newString)
            }
            readerString <<= it
            readerString << '\n'
        }
        return readerString
    }
}

//写入文件
def fileWrite(path, content) {
    new File(path).withWriter('UTF-8') { writer -> writer.append(content) }
}
相关推荐
程序喵大人2 分钟前
【C++进阶】STL算法与函数对象 -【C++进阶】STL算法与函数对象
开发语言·c++·算法
IKUN家族6 分钟前
Spring MVC(五)
java·spring·mvc
weixin_BYSJ198714 分钟前
【java项目分享】springboot阅读推荐平台10600
java·javascript·spring boot·python·django·flask·php
小 黄 鸡19 分钟前
JVM 核心总结
java
阿kun要赚马内20 分钟前
工具在langchain agent中的调用
人工智能·后端·python
牛马也想出海22 分钟前
使用Playwright被检测为机器人的原因及反检测方案
开发语言·网络·人工智能·机器人·php
GrowthDiary00729 分钟前
Python 常用函数总结
开发语言·python
一笑的小酒馆40 分钟前
Androidiot扫地机器人设备详情页地图加载慢卡顿优化方案
android
热心网友俣先生42 分钟前
2026年华数杯C 题 超详细解题思路
c语言·开发语言·人工智能
Data_Journal44 分钟前
掌握网页抓取中的分页:完整指南
java·服务器·前端