Skip to content

[Xamarin.AndroidX.Compose.UI.Graphics] Stop stripping the whole package; ship real bindings #1437

@jonathanpeppers

Description

@jonathanpeppers

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):

  1. Delete <remove-node path="/api/package" /> from the recipe's
    Transforms/Metadata.xml.
  2. 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.
  3. 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.
  4. Add <AndroidIgnoredJavaDependency> entries for any -jvm /
    -android KMP duplicate clashes that show up.
  5. 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 #1416Compose.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.

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions