Skip to content

Commit 72a523b

Browse files
committed
Compile against JPC 1.10
1 parent 62b579c commit 72a523b

File tree

6 files changed

+168
-5
lines changed

6 files changed

+168
-5
lines changed

sentry-android-replay/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ kotlin { explicitApi() }
7070

7171
dependencies {
7272
api(projects.sentry)
73+
api(projects.sentryCompose)
7374

7475
compileOnly(libs.androidx.compose.ui.replay)
7576
implementation(kotlin(Config.kotlinStdLib, Config.kotlinStdLibVersionAndroid))

sentry-android-replay/src/main/java/io/sentry/android/replay/viewhierarchy/ComposeViewHierarchyNode.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import io.sentry.android.replay.util.toOpaque
3030
import io.sentry.android.replay.viewhierarchy.ViewHierarchyNode.GenericViewHierarchyNode
3131
import io.sentry.android.replay.viewhierarchy.ViewHierarchyNode.ImageViewHierarchyNode
3232
import io.sentry.android.replay.viewhierarchy.ViewHierarchyNode.TextViewHierarchyNode
33+
import io.sentry.compose.SentryLayoutNodeHelper
3334
import java.lang.ref.WeakReference
3435
import java.lang.reflect.Method
3536

@@ -157,15 +158,13 @@ internal object ComposeViewHierarchyNode {
157158
shouldMask = true,
158159
isImportantForContentCapture = false, // will be set by children
159160
isVisible =
160-
!node.outerCoordinator.isTransparent() &&
161-
visibleRect.height() > 0 &&
162-
visibleRect.width() > 0,
161+
!SentryLayoutNodeHelper.isTransparent(node) && visibleRect.height() > 0 && visibleRect.width() > 0,
163162
visibleRect = visibleRect,
164163
)
165164
}
166165

167166
val isVisible =
168-
!node.outerCoordinator.isTransparent() &&
167+
!SentryLayoutNodeHelper.isTransparent(node) &&
169168
(semantics == null || !semantics.contains(SemanticsProperties.InvisibleToUser)) &&
170169
visibleRect.height() > 0 &&
171170
visibleRect.width() > 0
@@ -301,7 +300,7 @@ internal object ComposeViewHierarchyNode {
301300
options: SentryMaskingOptions,
302301
logger: ILogger,
303302
) {
304-
val children = this.children
303+
val children = SentryLayoutNodeHelper.getChildren(this)
305304
if (children.isEmpty()) {
306305
return
307306
}

sentry-compose/api/android/sentry-compose.api

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ public final class io/sentry/compose/BuildConfig {
66
public fun <init> ()V
77
}
88

9+
public final class io/sentry/compose/ComposeHelper {
10+
public static final field $stable I
11+
public static final field INSTANCE Lio/sentry/compose/ComposeHelper;
12+
public final fun getChildren (Landroidx/compose/ui/node/LayoutNode;)Ljava/util/List;
13+
public final fun isTransparent (Landroidx/compose/ui/node/LayoutNode;)Z
14+
}
15+
916
public final class io/sentry/compose/SentryComposeHelperKt {
1017
public static final fun boundsInWindow (Landroidx/compose/ui/layout/LayoutCoordinates;Landroidx/compose/ui/layout/LayoutCoordinates;)Landroidx/compose/ui/geometry/Rect;
1118
}

sentry-compose/build.gradle.kts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import io.gitlab.arturbosch.detekt.Detekt
22
import org.jetbrains.dokka.gradle.DokkaTask
33
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
44
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
5+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
56

67
plugins {
78
alias(libs.plugins.kotlin.multiplatform)
@@ -118,6 +119,80 @@ android {
118119
}
119120
}
120121

122+
// Compile Compose110Helper.kt against Compose 1.10 where internal LayoutNode accessors
123+
// are mangled with module name "ui" (e.g. getChildren$ui()) instead of "ui_release"
124+
val compose110Classpath by
125+
configurations.creating {
126+
isCanBeConsumed = false
127+
isCanBeResolved = true
128+
attributes {
129+
attribute(Attribute.of("artifactType", String::class.java), "android-classes-jar")
130+
}
131+
}
132+
133+
val compose110KotlinCompiler by
134+
configurations.creating {
135+
isCanBeConsumed = false
136+
isCanBeResolved = true
137+
}
138+
139+
dependencies {
140+
//noinspection UseTomlInstead
141+
compose110Classpath("androidx.compose.ui:ui-android:1.10.0")
142+
//noinspection UseTomlInstead
143+
compose110KotlinCompiler("org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0")
144+
}
145+
146+
val compileCompose110 by
147+
tasks.registering(JavaExec::class) {
148+
val sourceDir = file("src/compose110/kotlin")
149+
val outputDir = layout.buildDirectory.dir("classes/kotlin/compose110")
150+
val compileClasspathFiles = compose110Classpath.incoming.files
151+
152+
inputs.dir(sourceDir)
153+
inputs.files(compileClasspathFiles)
154+
outputs.dir(outputDir)
155+
156+
classpath = compose110KotlinCompiler
157+
mainClass.set("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler")
158+
159+
argumentProviders.add(
160+
CommandLineArgumentProvider {
161+
val cp = compileClasspathFiles.files.joinToString(File.pathSeparator)
162+
outputDir.get().asFile.mkdirs()
163+
listOf(
164+
sourceDir.absolutePath,
165+
"-classpath",
166+
cp,
167+
"-d",
168+
outputDir.get().asFile.absolutePath,
169+
"-jvm-target",
170+
"1.8",
171+
"-language-version",
172+
"1.9",
173+
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
174+
"-Xsuppress-version-warnings",
175+
"-no-stdlib",
176+
)
177+
}
178+
)
179+
}
180+
181+
// Make compose110 output available to the Android Kotlin compilation
182+
val compose110Output = files(compileCompose110.map { it.outputs.files })
183+
184+
tasks.withType<KotlinCompile>().configureEach {
185+
if (name == "compileReleaseKotlinAndroid" || name == "compileDebugKotlinAndroid") {
186+
dependsOn(compileCompose110)
187+
libraries.from(compose110Output)
188+
}
189+
}
190+
191+
// Include compose110 classes in the AAR
192+
android.libraryVariants.all {
193+
registerPreJavacGeneratedBytecode(project.files(compileCompose110.map { it.outputs.files }))
194+
}
195+
121196
tasks.withType<Detekt>().configureEach {
122197
// Target version of the generated JVM bytecode. It is used for type resolution.
123198
jvmTarget = JavaVersion.VERSION_1_8.toString()
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@file:Suppress(
2+
"INVISIBLE_MEMBER",
3+
"INVISIBLE_REFERENCE",
4+
"EXPOSED_PARAMETER_TYPE",
5+
"EXPOSED_RETURN_TYPE",
6+
"EXPOSED_FUNCTION_RETURN_TYPE",
7+
)
8+
9+
package io.sentry.compose
10+
11+
import androidx.compose.ui.node.LayoutNode
12+
13+
/**
14+
* Provides access to internal LayoutNode members that are subject to Kotlin name-mangling.
15+
*
16+
* LayoutNode.children and LayoutNode.outerCoordinator are Kotlin `internal`, so their getters are
17+
* mangled with the module name: getChildren$ui_release() in Compose < 1.10 vs getChildren$ui() in
18+
* Compose >= 1.10. This class detects the version on first use and delegates to the correct
19+
* accessor.
20+
*/
21+
public object SentryLayoutNodeHelper {
22+
@Volatile private var compose110Helper: Compose110Helper? = null
23+
@Volatile private var useCompose110: Boolean? = null
24+
25+
public fun getChildren(node: LayoutNode): List<LayoutNode> {
26+
return if (useCompose110 == true) {
27+
compose110Helper!!.getChildren(node)
28+
} else {
29+
val helper = Compose110Helper()
30+
try {
31+
helper.getChildren(node).also {
32+
compose110Helper = helper
33+
useCompose110 = true
34+
}
35+
} catch (_: NoSuchMethodError) {
36+
useCompose110 = false
37+
node.children
38+
}
39+
}
40+
}
41+
42+
public fun isTransparent(node: LayoutNode): Boolean {
43+
return if (useCompose110 == true) {
44+
compose110Helper!!.getOuterCoordinator(node).isTransparent()
45+
} else {
46+
val helper = Compose110Helper()
47+
try {
48+
helper.getOuterCoordinator(node).isTransparent().also {
49+
compose110Helper = helper
50+
useCompose110 = true
51+
}
52+
} catch (_: NoSuchMethodError) {
53+
useCompose110 = false
54+
node.outerCoordinator.isTransparent()
55+
}
56+
}
57+
}
58+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@file:Suppress(
2+
"INVISIBLE_MEMBER",
3+
"INVISIBLE_REFERENCE",
4+
"EXPOSED_PARAMETER_TYPE",
5+
"EXPOSED_RETURN_TYPE",
6+
"EXPOSED_FUNCTION_RETURN_TYPE",
7+
)
8+
9+
package io.sentry.compose
10+
11+
import androidx.compose.ui.node.LayoutNode
12+
import androidx.compose.ui.node.NodeCoordinator
13+
14+
/**
15+
* Compiled against Compose >= 1.10 where internal LayoutNode accessors are mangled with the module
16+
* name "ui" (e.g. getChildren$ui(), getOuterCoordinator$ui()) instead of "ui_release" used in
17+
* earlier versions.
18+
*/
19+
public class Compose110Helper {
20+
public fun getChildren(node: LayoutNode): List<LayoutNode> = node.children
21+
22+
public fun getOuterCoordinator(node: LayoutNode): NodeCoordinator = node.outerCoordinator
23+
}

0 commit comments

Comments
 (0)