Companion to #1416 / #1418 / #1420. The two peer recipes
Xamarin.AndroidX.Compose.UI.Graphics and
Xamarin.AndroidX.Compose.UI.Graphics.Android currently ship as
Java-Library-Only — the AssemblyDescription says it directly:
"this package only adds the Java library to the application. C# bindings are not provided."
That leaves a hole in the Compose binding story. Every other Compose
recipe (Compose.Runtime, Compose.UI, Compose.Foundation, etc.)
now ships real bindings via #1418/#1420, but anything that takes a
Color, Brush, Shape, Path, ImageBitmap, Outline, Matrix,
PathEffect, BlendMode, … from androidx.compose.ui.graphics falls
off the binding surface entirely.
In a managed-only Compose facade (compose-net) this means every
color knob has to be typed as raw long (the packed
androidx.compose.ui.graphics.Color.value) and every JNI call site
has to recreate the inline-class boxing/packing rules by hand. We just
hit it again landing the Phase 2 Modifier ops
(compose-net#26): callers couldn't write
Color.Blue / new Color(0xFF1976D2) because there's no managed
Color type to write — we shipped a hand-rolled ComposeNet.Color
struct that mirrors the Kotlin packing as a stand-in.
Requested change
For both recipes (Xamarin.AndroidX.Compose.UI.Graphics and
Xamarin.AndroidX.Compose.UI.Graphics.Android):
- Delete
<remove-node path="/api/package" /> from the recipe's
Transforms/Metadata.xml.
- Port whatever targeted
<remove-node> entries are needed to make
generation succeed — the usual suspects in Compose are inline-class
hash-mangled overloads (the Color / Brush / Path packages are
full of *-bw27NRU, *-XHw0xAI-style names from
@JvmInline value class Color(value: ULong),
@JvmInline value class Offset, @JvmInline value class Size,
@JvmInline value class TileMode, etc.) and abstract types whose
auto-generated Invokers can't satisfy abstract members.
- Decide how to expose
@JvmInline value class types like Color,
Offset, Size, TileMode. The two viable shapes:
- Surface as managed structs. The cleanest API; matches the
Kotlin user experience (Color.Blue, new Color(0xFF1976D2),
Offset.Zero, size.Width). Requires the binder learning to
project inline value classes (likely tied to
dotnet/java-interop#1440).
- Strip the inline-class types and surface the underlying
primitive. What the rest of the bindings already do — every
*-bw27NRU method ends up with a raw long color parameter.
This unblocks Brush / Shape / Path etc. (those are real
classes, not inline) without waiting on inline-class support;
inline scalars stay raw long / float until #1440 lands.
- Add
<AndroidIgnoredJavaDependency> entries for any -jvm /
-android KMP duplicate clashes that show up.
- Regenerate
api/PublicApi*.txt for both recipes.
Why this matters
Without this, every Compose binding consumer that wants to paint
anything (Modifier.background, Modifier.border, Surface(color = …), MaterialTheme.colorScheme.primary, Brush.linearGradient(...),
Path for custom shapes, Image(painter = …)) is forced to either:
- accept
long everywhere and lose all type safety / discoverability
(today's status quo for containerColor / contentColor /
scrimColor properties throughout the existing Compose Material 3
bindings), or
- re-implement the Kotlin Color packing in user code (what
compose-net did in PR #26 with a hand-rolled
ComposeNet.Color).
Both are bad. The first hides every typo behind a long; the second
duplicates Kotlin's API surface in every facade.
Sequencing
Independent of #1416 — Compose.UI already ships real bindings, and
Compose.UI.Graphics is a peer rather than a dependent. Can ship in
isolation as soon as someone sequences the <remove-node> cleanup +
PublicApi regen.
Companion to #1416 / #1418 / #1420. The two peer recipes
Xamarin.AndroidX.Compose.UI.GraphicsandXamarin.AndroidX.Compose.UI.Graphics.Androidcurrently ship asJava-Library-Only — the
AssemblyDescriptionsays it directly:That leaves a hole in the Compose binding story. Every other Compose
recipe (
Compose.Runtime,Compose.UI,Compose.Foundation, etc.)now ships real bindings via #1418/#1420, but anything that takes a
Color,Brush,Shape,Path,ImageBitmap,Outline,Matrix,PathEffect,BlendMode, … fromandroidx.compose.ui.graphicsfallsoff the binding surface entirely.
In a managed-only Compose facade (compose-net) this means every
color knob has to be typed as raw
long(the packedandroidx.compose.ui.graphics.Color.value) and every JNI call sitehas to recreate the inline-class boxing/packing rules by hand. We just
hit it again landing the Phase 2
Modifierops(compose-net#26): callers couldn't write
Color.Blue/new Color(0xFF1976D2)because there's no managedColortype to write — we shipped a hand-rolledComposeNet.Colorstruct that mirrors the Kotlin packing as a stand-in.
Requested change
For both recipes (
Xamarin.AndroidX.Compose.UI.GraphicsandXamarin.AndroidX.Compose.UI.Graphics.Android):<remove-node path="/api/package" />from the recipe'sTransforms/Metadata.xml.<remove-node>entries are needed to makegeneration succeed — the usual suspects in Compose are inline-class
hash-mangled overloads (the
Color/Brush/Pathpackages arefull of
*-bw27NRU,*-XHw0xAI-style names from@JvmInline value class Color(value: ULong),@JvmInline value class Offset,@JvmInline value class Size,@JvmInline value class TileMode, etc.) and abstract types whoseauto-generated Invokers can't satisfy abstract members.
@JvmInline value classtypes likeColor,Offset,Size,TileMode. The two viable shapes:Kotlin user experience (
Color.Blue,new Color(0xFF1976D2),Offset.Zero,size.Width). Requires the binder learning toproject inline value classes (likely tied to
dotnet/java-interop#1440).
primitive. What the rest of the bindings already do — every
*-bw27NRUmethod ends up with a rawlong colorparameter.This unblocks
Brush/Shape/Pathetc. (those are realclasses, not inline) without waiting on inline-class support;
inline scalars stay raw
long/floatuntil #1440 lands.<AndroidIgnoredJavaDependency>entries for any-jvm/-androidKMP duplicate clashes that show up.api/PublicApi*.txtfor both recipes.Why this matters
Without this, every Compose binding consumer that wants to paint
anything (
Modifier.background,Modifier.border,Surface(color = …),MaterialTheme.colorScheme.primary,Brush.linearGradient(...),Pathfor custom shapes,Image(painter = …)) is forced to either:longeverywhere and lose all type safety / discoverability(today's status quo for
containerColor/contentColor/scrimColorproperties throughout the existing Compose Material 3bindings), or
compose-netdid in PR #26 with a hand-rolledComposeNet.Color).Both are bad. The first hides every typo behind a
long; the secondduplicates Kotlin's API surface in every facade.
Sequencing
Independent of #1416 —
Compose.UIalready ships real bindings, andCompose.UI.Graphicsis a peer rather than a dependent. Can ship inisolation as soon as someone sequences the
<remove-node>cleanup +PublicApi regen.