Explore ManagedPeer compatibility for trimmable typemap apps
- Dominant language
- C#
- Stars
- 2.1k
- Forks
- 579
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 257
Description
## Context
The trimmable typemap runtime intentionally removes `net.dot.jni.ManagedPeer` from `java_runtime_trimmable.jar` and sets `Java.Interop.RuntimeFeature.ManagedPeerNativeRegistration=false`. Trimmable-generated Java/proxy/native-registration code should use generated UCO/proxy paths such as `mono.android.Runtime.registerNatives(Class)` instead of the legacy dynamic Java.Interop bridge:
```java
net.dot.jni.ManagedPeer.registerNativeMembers(Class nativeClass, String methods)
net.dot.jni.ManagedPeer.construct(Object self, String constructorSignature, Object... args)
```
This is desirable for app size and trim/AOT safety, but old generated or handwritten Java bytecode can still reference `ManagedPeer`, which would fail in trimmable apps with `NoClassDefFoundError`.
## Question
Should we add an explicit opt-in compatibility path for trimmable apps that still package Java bytecode referencing `net.dot.jni.ManagedPeer`?
## Possible shape
Default behavior should stay strict:
- Do not package `ManagedPeer.class` in trimmable apps.
- Keep `ManagedPeerNativeRegistration=false`.
- Ideally detect Java bytecode references to `net/dot/jni/ManagedPeer` at build time and fail with an actionable diagnostic.
Potential opt-in behavior, behind a property/feature switch, e.g. `AndroidEnableManagedPeerCompatibility=true`:
1. Package a tiny trimmable-compatible `net.dot.jni.ManagedPeer` shim.
2. `registerNativeMembers(Class, String)` logs a warning and remaps to generated trimmable registration, likely `mono.android.Runtime.registerNatives(Class)`.
3. `construct(Object, String, Object...)` probably remains unsupported and throws a clear error unless/until we add generated per-type constructor dispatch.
4. Build-time detection could downgrade from error to warning when the opt-in is enabled.
## Things to decide
- Is a compatibility shim worth carrying at all, even behind opt-in?
- Should `registerNativeMembers(Class, String)` ignore the legacy `methods` string and rely entirely on generated trimmable metadata?
- Should `construct(...)` always fail, or should we eventually support it through generated dispatch metadata?
- Where should detection happen: Java source scan, class/jar scan, dex scan, or a combination?
- What property name and diagnostic code should we use?
## Why this matters
We want to keep default trimmable apps free of the old dynamic bridge, but we also want a clear story for users who have older JavaInterop1-generated Java wrappers or handwritten Java copied from Java.Interop samples that still call `ManagedPeer.*`.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.