Skip to content

Register the Android wrapper before launch - #9

Merged
krassx merged 2 commits into
cursor/upm-package-scaffoldfrom
wrapper/android-registration
Oct 9, 2026
Merged

krassx merged 2 commits into
cursor/upm-package-scaffoldfrom
wrapper/android-registration

Conversation

@krassx

@krassx krassx commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • A UnityWrapperProvider at initOrder 200 calls setWrapper before the SDK launches. The class name is not stripped by the Gradle plugin.
  • C# only calls refineContext, which installs the same instance if the provider has not run yet.

Test plan

  • DOTNET_ROLL_FORWARD=LatestMajor dotnet test Tests~/WrapperPolicy/Bugsee.WrapperPolicy.Tests.csproj --filter RegistrationSourceTests

Made with Cursor

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Deep review: Register the Android wrapper before launch

The approach is the right one for 7.x crash recovery. BugseeInitProvider is initOrder="100" and autoLaunch / handleRespawnAutoLaunch run in that onCreate. A sibling ContentProvider at initOrder="200" calling Bugsee.setWrapper matches Bugsee's own NDK extension (BugseeNdkInitProvider) and the documented custom-extension pattern. C# no longer calling setWrapper is correct: a JNI AndroidJavaProxy cannot exist before the engine is up. I checked plugin 4.0.8: removeExtensionInitProviders only drops the known Bugsee*InitProvider FQNs (NDK, OkHttp, Feedback, …), so UnityWrapperProvider is not stripped.

Bugsee.Launch still depends on the new Java type being in the APK (refineContext is a fallback install() as well as a context fill). That makes packaging and minify keep-rules load-bearing.

Overall risk: Medium
Merge recommendation: Request changes

Must fix

  1. P1 — Commit PluginImporter .meta files for UnityWrapperProvider.java and AndroidManifest.xml (same shape as UnityManagedException.java.meta). Without them a UPM git install can omit the class and/or the provider, so either the process crashes on the manifest entry or Bugsee.Launch throws.
  2. P2 — Mark the provider android:directBootAware="true" so it still runs in the same Direct Boot window as BugseeInitProvider.
  3. P2 — Keep com.bugsee.unity.UnityWrapper.refineContext (and the class) from R8. Minify currently breaks the C# JNI call on Launch.

Also worth doing

  • P3 getWrapperBuild() is hardcoded "unknown". iOS and the old C# BugseeWrapperProxy both published BugseePackageVersion.Build. Pass build through refineContext.
  • The new source test looks for initOrder in a Java comment and never opens AndroidManifest.xml, so it cannot catch a dropped android:initOrder="200".

I decompiled bugsee-android:7.3.0 and gradle plugin 4.0.8 for init order, wrapper defaults, and the strip list. dotnet is not in this environment; I did not run RegistrationSourceTests.

What looks good

  • initOrder 200 vs core 100 is the correct ordering for respawn recovery.
  • refineContext → install() is a real fallback if the provider did not run.
  • exported="false", package-private helper + public provider, and avoiding the Bugsee*InitProvider FQN are all sound.
  • App setReportHandler / setLifecycleEventsListener stay on the C# proxies; the Java stubs completing immediately match the old BugseeWrapperProxy and are appropriate before the engine is up.
Open in Web View Automation 

Sent by Cursor Automation: Bugsee code review

Comment thread Plugins/Android/UnityWrapperProvider.java
Comment thread Plugins/Android/AndroidManifest.xml
Comment thread Plugins/Android/UnityWrapperProvider.java
Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review: Register the Android wrapper before launch

3cb678d addresses the previous packaging / Direct Boot / R8 findings. The 7.x crash-recovery shape is still right: BugseeInitProvider is initOrder="100" and runs autoLaunch / handleRespawnAutoLaunch in onCreate; a sibling provider at 200 calling Bugsee.setWrapper matches BugseeNdkInitProvider. Plugin 4.0.8 ExtensionSpec.fromInitProviderFqn only consolidates the known com.bugsee.library.Bugsee*InitProvider FQNs, so com.bugsee.unity.UnityWrapperProvider is left in the merged manifest. C# only calling refineContext is correct — a JNI AndroidJavaProxy cannot exist before the engine is up.

I re-checked Bugsee.setWrapper (stores the instance on BugseeEnvironment and is safe before core init), getSecureRectangles ({1,0} takes the same empty-wrapper path as the interface default null; it does not wipe addSecureRectangle areas), and the new PluginImporter .meta files against UnityManagedException.java.meta.

No remaining P0–P2. Two P3s below.

Overall risk: Low
Merge recommendation: Approve

Prior findings (now addressed)

  1. P1 PluginImporter .meta for the Java + manifest — shipped, Android-only, overridable.
  2. P2 android:directBootAware="true" — shipped.
  3. P2 R8 keep for UnityWrapper.refineContext — Plugins/Android/bugsee-unity-wrapper.proguard (Unity picks up *.proguard from that folder).

Residual (non-blocking)

  1. P3 getWrapperBuild() is still hardcoded "unknown" after Launch. iOS and the old C# BugseeWrapperProxy published BugseePackageVersion.Build. Android 7.3.0 J0 copies type/version/build into $$WRAPPER.
  2. P3 RegistrationSourceTests still looks for initOrder in a Java comment and never opens AndroidManifest.xml.
  3. Leftover: _wrapperContextRefined = true is still set before the JNI call. Harmless if packaging/minify stay correct; a thrown refineContext still suppresses retry.

I decompiled bugsee-android:7.3.0 and gradle plugin 4.0.8 for init order, setWrapper, secure-rect merge, and the strip list. dotnet is not in this environment; I did not run RegistrationSourceTests.

What looks good

  • initOrder 200 vs core 100, plus Direct Boot, matches NDK and is the correct ordering for respawn recovery.
  • refineContext → install() is a real fallback if the provider did not run.
  • exported="false", package-private helper + public provider, and avoiding the Bugsee*InitProvider FQN are all sound.
  • App setReportHandler / setLifecycleEventsListener stay on the C# proxies; the Java stubs completing immediately match the old BugseeWrapperProxy and are appropriate before the engine is up.
Open in Web View Automation 

Sent by Cursor Automation: Bugsee code review

Comment on lines +65 to +67
@Override
public String getWrapperBuild() {
return "unknown";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: P3 Low

Problem: getWrapperBuild() is hardcoded "unknown". refineContext updates wrapperVersion but has no build argument, so this stays "unknown" for the life of the process — including after Bugsee.Launch.

Impact: Android 7.3.0 copies getWrapperType / getWrapperVersion / getWrapperBuild into the $$WRAPPER session option. iOS (_bugsee_ensure_wrapper(Version, Build)) and the old C# BugseeWrapperProxy both published BugseePackageVersion.Build ("dev" today). Android reports will disagree with iOS on wrapper identity.

Scenario: Launch on device, then any report/crash. Session metadata shows wrapper version 0.1.0 and build unknown. Same app on iOS shows build dev.

Fix: Add a wrapperBuild field (default "unknown"), pass BugseePackageVersion.Build as a sixth refineContext argument, and return it from getWrapperBuild(). Extend the proguard keep signature to match.

string java = File.ReadAllText(RepoFile("Plugins/Android/UnityWrapperProvider.java"));
Assert.That(Regex.IsMatch(java, @"class\s+Bugsee[A-Za-z0-9_]+InitProvider\b"), Is.False);
Assert.That(java, Does.Contain("class UnityWrapperProvider"));
Assert.That(java, Does.Contain("initOrder"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: P3 Low

Problem: This assertion is satisfied by the // initOrder 200 comment in UnityWrapperProvider.java. The load-bearing values are on the provider element in Plugins/Android/AndroidManifest.xml (android:initOrder="200", android:directBootAware="true"). The test never opens that file.

Impact: Dropping or lowering android:initOrder (so this provider runs after BugseeInitProvider at 100) still passes CI, and crash recovery can assemble a session without wrapperType=unity. Same for losing directBootAware.

Scenario: Someone removes the comment as noise, or changes the manifest to 100 / omits directBootAware, and leaves the Java class name alone. Provider_class_name_survives_the_gradle_plugin_strip stays green.

Fix: Read AndroidManifest.xml and assert android:initOrder="200", android:directBootAware="true", and the provider FQN. Keep the Bugsee*InitProvider name check on the Java source.

@krassx
krassx merged commit 1db0648 into cursor/upm-package-scaffold Oct 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant