Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Gradle & AGP to version 8 #575

Merged
merged 7 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 12 additions & 150 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
import com.android.build.api.transform.*
import com.android.build.api.variant.VariantInfo
import com.android.utils.FileUtils
import org.gradle.internal.os.OperatingSystem
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

plugins {
id("com.android.application")
kotlin("android")
Expand Down Expand Up @@ -55,7 +47,7 @@ dependencies {

implementation("org.greenrobot:eventbus:3.3.1")

debugImplementation("org.aspectj:aspectjrt:1.9.20.1")
debugImplementation("org.aspectj:aspectjrt:1.9.21")
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")

testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
Expand Down Expand Up @@ -141,6 +133,7 @@ android {

buildFeatures {
viewBinding = true
buildConfig = true
}
}

Expand All @@ -157,148 +150,17 @@ fun versionBanner(): String {
/////////////////////////////////////////////////////////////////////////////////////////////// cats
////////////////////////////////////////////////////////////////////////////////////////////////////

// ajc gets hold of some files such as R.jar, and on Windows it leads to errors such as:
// The process cannot access the file because it is being used by another process
// to avoid these, weave in a process, which `javaexec` will helpfully launch for us.

fun weave(classPath: Iterable<File>, aspectPath: Iterable<File>, input: Iterable<File>, output: File) {
val runInAProcess = OperatingSystem.current().isWindows
val bootClassPath = android.bootClasspath

println(if (runInAProcess) ":: weaving in a process..." else ":: weaving...")
println(":: boot class path: $bootClassPath")
println(":: class path: $classPath")
println(":: aspect path: $aspectPath")
println(":: input: $input")
println(":: output: $output")

val arguments = listOf("-showWeaveInfo",
"-1.8",
"-preserveAllLocals",
"-bootclasspath", bootClassPath.asArgument,
"-classpath", classPath.asArgument,
"-aspectpath", aspectPath.asArgument,
"-inpath", input.asArgument,
"-d", output.absolutePath)

if (runInAProcess) {
javaexec {
classpath = weaving
main = "org.aspectj.tools.ajc.Main"
args = arguments
}
} else {
val handler = MessageHandler(true)
Main().run(arguments.toTypedArray(), handler)

val log = project.logger
for (message in handler.getMessages(null, true)) {
when (message.kind) {
IMessage.DEBUG -> log.debug("DEBUG " + message.message, message.thrown)
IMessage.INFO -> log.info("INFO: " + message.message, message.thrown)
IMessage.WARNING -> log.warn("WARN: " + message.message, message.thrown)
IMessage.FAIL,
IMessage.ERROR,
IMessage.ABORT -> log.error("ERROR: " + message.message, message.thrown)
}
}
}
}

// the only purpose of the following is to get a hold of aspectjtools jar
// this jar is already on build script classpath, but that classpath is impossible to get
// see https://discuss.gradle.org/t/how-do-i-determine-buildscript-classpath/37973/3

val weaving: Configuration by configurations.creating

dependencies {
weaving("org.aspectj:aspectjtools:1.9.20.1")
}

// historical note: the problem with weaving Kotlin and Java in-place is that:
// * Java is compiled by task compileDebugJavaWithJavac
// * gradle can run either one of these tasks, or both of them
// * compileDebugJavaWithJavac depends on compileDebugKotlin
// * weaving Kotlin requires Java classes
// This is hacky but it makes the AspectJ weaving only happen on debug builds.
// Note that `apply(plugin = ...)` prevents us from configuring a filter,
// which seems to require the unconditional syntax `plugin { id(...) }`.
// However, the filter somehow doesn't seem to work either way, even if we simplify it to this:
//
// a transformation is a poorly advertised feature that works on merged code, and also has its own
// inputs and outputs, so this fixes all of our problems...

class TransformCats : Transform() {
override fun getName(): String = TransformCats::class.simpleName!!

override fun getInputTypes() = setOf(QualifiedContent.DefaultContentType.CLASSES)

// only look for annotations in app classes
// transformation will consume these and put woven classes in the output dir
override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT)

// but also have the rest on our class path
// these will not be touched by the transformation
override fun getReferencedScopes() = mutableSetOf(QualifiedContent.Scope.SUB_PROJECTS,
QualifiedContent.Scope.EXTERNAL_LIBRARIES)

override fun isIncremental() = false
// aopWeave {
// filter = "ubergeek42"
// }

// only run on debug builds
override fun applyToVariant(variant: VariantInfo) = variant.isDebuggable
val taskRequests = getGradle().startParameter.taskRequests.flatMap { it.args }

override fun transform(invocation: TransformInvocation) {
if (!invocation.isIncremental) {
invocation.outputProvider.deleteAll()
}

val output = invocation.outputProvider.getContentLocation(name, outputTypes,
scopes, Format.DIRECTORY)
if (output.isDirectory) FileUtils.deleteDirectoryContents(output)
FileUtils.mkdirs(output)

val input = mutableListOf<File>()
val classPath = mutableListOf<File>()
val aspectPath = mutableListOf<File>()

invocation.inputs.forEach { source ->
source.directoryInputs.forEach { dir ->
input.add(dir.file)
classPath.add(dir.file)
}

source.jarInputs.forEach { jar ->
input.add(jar.file)
classPath.add(jar.file)
}
}

invocation.referencedInputs.forEach { source ->
source.directoryInputs.forEach { dir ->
classPath.add(dir.file)
}

source.jarInputs.forEach { jar ->
classPath.add(jar.file)
// this used to read `if (jar.name == ":cats") ...`,
// but with android gradle plugin 4.2.0 jar names contain garbage
// this is a very simple but a bit fragile workaround. todo improve
if (jar.file.directoriesInsideRootProject().contains("cats")) {
aspectPath.add(jar.file)
}
}

}

weave(classPath, aspectPath, input, output)
}
}

android.registerTransform(TransformCats())

val Iterable<File>.asArgument get() = joinToString(File.pathSeparator)

fun File.directoriesInsideRootProject() = sequence {
var file = this@directoriesInsideRootProject
while (true) {
yield(file.name)
file = file.parentFile ?: break
if (file == rootProject.projectDir) break
}
if (taskRequests.isNotEmpty() && taskRequests.all { "Debug" in it }) {
apply(plugin = "com.ibotta.gradle.aop")
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public FullScreenEditTextPreference(Context context) {

@SuppressWarnings("WeakerAccess")
public FullScreenEditTextPreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextPreferenceStyle);
this(context, attrs, androidx.preference.R.attr.editTextPreferenceStyle);
}

@SuppressWarnings("WeakerAccess")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class P implements SharedPreferences.OnSharedPreferenceChangeListener{
public static void storeThemeOrColorSchemeColors(Context context) {
ColorScheme scheme = ColorScheme.get();
TypedArray colors = context.obtainStyledAttributes(
new int[] {R.attr.colorPrimary, R.attr.colorPrimaryDark, R.attr.toolbarIconColor});
new int[] {androidx.appcompat.R.attr.colorPrimary, androidx.appcompat.R.attr.colorPrimaryDark, R.attr.toolbarIconColor});
colorPrimary = scheme.colorPrimary != ColorScheme.NO_COLOR ?
scheme.colorPrimary : colors.getColor(0, ColorScheme.NO_COLOR);
colorPrimaryDark = scheme.colorPrimaryDark != ColorScheme.NO_COLOR ?
Expand Down
6 changes: 4 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ buildscript {
repositories {
mavenCentral()
google()
maven("https://plugins.gradle.org/m2/")
}

dependencies {
classpath("com.android.tools.build:gradle:7.4.2")
classpath("org.aspectj:aspectjtools:1.9.20.1") // updating to 1.9.21 leads to dexing errors
classpath("com.android.tools.build:gradle:8.2.2")
classpath("org.aspectj:aspectjtools:1.9.21")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20")
classpath("org.jetbrains.kotlin:kotlin-serialization:1.9.20")
classpath("com.ibotta:plugin:1.4.1")
}
}

Expand Down
6 changes: 5 additions & 1 deletion cats/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

dependencies {
implementation("org.aspectj:aspectjrt:1.9.20.1")
implementation("org.aspectj:aspectjrt:1.9.21")
implementation("androidx.annotation:annotation:1.7.1")

testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
Expand Down Expand Up @@ -38,6 +38,10 @@ android {
targetSdk = 34
minSdk = 16
}

buildFeatures {
buildConfig = true
}
}

tasks.withType<JavaCompile> {
Expand Down
26 changes: 10 additions & 16 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,10 @@ org.gradle.jvmargs=-Xmx1024m -XX:MaxMetaspaceSize=512m

android.enableR8.fullMode=true

# These are set by “Migrate to AndroidX” refactor
# When set to true, the Android plugin uses the appropriate AndroidX library instead of a Support
# Library. The flag is false by default if it is not specified.
android.enableJetifier=true

# https://issuetracker.google.com/issues/159151549#comment7
android.jetifier.ignorelist = bcprov-jdk15on-1.70.jar

# When set to true, the Android plugin automatically migrates existing third-party libraries to use
# AndroidX by rewriting their binaries. The flag is false by default if it is not specified.
android.useAndroidX=true


# Add the following to ~/.gradle/gradle.properties to build dev/release

# Key info for creating the development release in the android market
Expand All @@ -48,10 +39,13 @@ android.useAndroidX=true
# kapt is the annotation processor for Kotlin
kapt.incremental.apt=true

# Linter that comes with AGP 7.4.2 doesn't support Kotlin 1.9, so force a newer version.
# Suppresses messages like:
# Module was compiled with an incompatible version of Kotlin.
# The binary version of its metadata is 1.9.0, expected version is 1.7.1.
# See answer by the_jk: https://stackoverflow.com/q/76690078/#76763654
# TODO Remove this after updating to AGP 8
android.experimental.lint.version=8.3.0-alpha18
android.nonTransitiveRClass=true

# Using non-final resource IDs is supposed to improve compilation performance.
# The idea is that they must be unique among libraries,
# so in case of a collision recompilation is reqiured.
# However, in practice, after switching this to true (now default) I see
# * no difference in incremental build times, and
# * slight increase in a full build time,
# so let's leave it as it is for now.
android.nonFinalResIds=false
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
Loading