Skip to content

Instantly share code, notes, and snippets.

@sickworm
Last active October 5, 2025 01:02
Show Gist options
  • Select an option

  • Save sickworm/ee2d64b12a770a88e7c860ae4058634a to your computer and use it in GitHub Desktop.

Select an option

Save sickworm/ee2d64b12a770a88e7c860ae4058634a to your computer and use it in GitHub Desktop.
import com.android.build.gradle.internal.services.BuildServicesKt
import com.android.build.gradle.options.ProjectOptions
import com.android.build.gradle.options.ProjectOptionService
import com.android.build.gradle.options.StringOption
import com.android.builder.errors.EvalIssueException
import com.android.builder.errors.IssueReporter
import com.google.common.collect.ImmutableMap
import org.jetbrains.annotations.NotNull
import java.lang.reflect.Field
/**
* 目的:动态设置 gradle.properties 里的 android.aapt2FromMavenOverride=/Users/sickworm/Library/Android/sdk/build-tools/35.0.1/aapt2
* gradle.properties 不支持动态路径
*/
// 1. 拿到 35.0.1 aapt2 的路径
// 更推荐的方式:直接拷贝 $sdkDir/build-tools/35.0.1/aapt2 到工程,这样就不用每个开发安装一次了(需要分别内置 windows,linux,mac)
def sdkDir = com.android.build.gradle.internal.SdkLocator.getSdkDirectory(project.rootDir, new IssueReporter() {
@Override
boolean hasIssue(@NotNull IssueReporter.Type type) {
return false
}
@Override
protected void reportIssue(@NotNull IssueReporter.Type type, @NotNull IssueReporter.Severity severity, @NotNull EvalIssueException e) {
}
})
println("sdkDir: $sdkDir")
if (sdkDir == null || !sdkDir.exists()) {
System.err.println("Android sdkDir 找不到,退出替换") // 这里不应该没有,先不直接报错,先跑起来,避免首次初始化等部分场景读不到
return
}
def aapt2Path = "$sdkDir/build-tools/35.0.1/aapt2"
if (! new File(aapt2Path).exists()) {
def message = "编译检查:找不到 $aapt2Path,请先安装 build-tools 35.0.1。方法:Android Studio -> Tools -> SDK Manager -> SDK Tools -> 安装 build-tools 35.0.1。"
System.err.println(message)
System.err.println(message)
System.err.println(message)
throw new IllegalArgumentException(message)
}
// 2. 反射设置进去
new ProjectOptionService.RegistrationAction(project).execute().get() // 触发 ProjectOptionService 创建。正常是在 apply com.android.library 时懒加载创建
def buildServiceRegistry = project.getGradle().getSharedServices()
Object byName = buildServiceRegistry.getRegistrations().getByName(BuildServicesKt.getBuildServiceName(ProjectOptionService.class))
if (byName == null) {
throw new NullPointerException("null cannot be cast to non-null type org.gradle.api.services.BuildServiceRegistration<ServiceT of com.android.build.gradle.internal.services.BuildServicesKt.getBuildService, *>");
}
def service = byName.getService()
ProjectOptions projectOptions = service.get().getProjectOptions()
println("projectOptions $projectOptions")
Field stringOptionValues = projectOptions.getClass().getDeclaredField("stringOptionValues")
stringOptionValues.setAccessible(true)
ImmutableMap<StringOption, ProjectOptions.OptionValue<StringOption, String>> value = stringOptionValues.get(projectOptions)
// 2.2 找到 AAPT2_FROM_MAVEN_OVERRIDE
value.entrySet().forEach { entry ->
def getMethod = entry.value.getClass().getDeclaredMethod("getValueForUseAtConfiguration")
getMethod.setAccessible(true)
// AAPT2_FROM_MAVEN_OVERRIDE=/Users/sickworm/Library/Android/sdk/build-tools/35.0.1/aapt2
if (entry.key.toString() == "AAPT2_FROM_MAVEN_OVERRIDE") {
println("projectOptions ${entry.key}=${getMethod.invoke(entry.value)}")
def field = entry.value.getClass().getDeclaredField("option") // StringOption
field.setAccessible(true)
StringOption stringOption = field.get(entry.value)
def mockStringOption = new com.android.build.gradle.options.Option<String>() {
@Override
String getDefaultValue() {
return aapt2Path
}
@Override
String getPropertyName() {
return stringOption.getPropertyName()
}
@Override
com.android.build.gradle.options.Option.Status getStatus() {
return stringOption.getStatus()
}
@Override
String parse(@NotNull Object o) {
return aapt2Path
}
}
field.set(entry.value, mockStringOption)
println("projectOptions after ${entry.key}=${getMethod.invoke(entry.value)}")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment