Skip to content

Android bridge without the Java wrapper, harness on a device - #36

Open
yauch-dev wants to merge 5 commits into
feature/testing-toolsfrom
feature/android-bridge-without-wrapper
Open

yauch-dev wants to merge 5 commits into
feature/testing-toolsfrom
feature/android-bridge-without-wrapper

Conversation

@yauch-dev

Copy link
Copy Markdown
Collaborator

What

  • Android bridge calls CrossplatformHelper from C#. AdaptyAndroid.cs reaches io.adapty.internal:crossplatform through JNI and implements its four callback interfaces as AndroidJavaProxy. The adaptyandroidwrapper Gradle project, the unity-wrapper AAR under Plugins/Android/Local and AdaptyAndroidCallbackAction are gone; a native bump is one line in the androidlib build.gradle. R8 needs no rule: android-sdk's consumer rules keep com.adapty.**.
  • Callbacks go through a Handler on the Unity thread's Looper, as the wrapper did. A flow is an Activity of its own and Unity's player loop is paused underneath it; a SynchronizationContext post would wait for the frame that comes only once the flow is gone, so the close action would reach the listener with nothing left to dismiss. RunOnMainThread stays for the delegates the SDK hands to app code.
  • SDK harness on an Android device. harness_build_android, AndroidHarnessServer (the stock Pipeline runtime server writes its descriptor next to the APK and dies), the run steps in the harness AGENTS.md. Pipeline is bumped to 0.6.0-exp.1, which starts the runtime server from Project Settings rather than a scene component; the scene's stale RuntimePipelineManager is removed.
  • Demo orientation fixed to portrait.

Verified

  • JSON layer suite, all four legs.
  • Harness on a Nothing Phone (1), Android 16, A/B against the wrapper build: Activate, GetProfile, GetFlow (rt.RegTestPaywall1, calm9), GetPaywallProducts with Play prices, CreateFlowView / PresentFlowView / DismissFlowView, and flow_view_did_perform_action (system_back) delivered to C# within 3 s while the flow is on screen — identical on both builds.
  • Not exercised: a purchase through the flow.

AdaptyAndroid.cs reaches io.adapty.internal:crossplatform through JNI and
implements its four callback interfaces as AndroidJavaProxy, so the package
ships no Java of its own: the adaptyandroidwrapper Gradle project, the
unity-wrapper AAR under Plugins/Android/Local and AdaptyAndroidCallbackAction
go away, and a native bump is one line in the androidlib build.gradle.

Callbacks are posted to a Handler on the Unity thread's Looper, as the
wrapper did, not through RunOnMainThread: a flow is an Activity of its own,
Unity's player loop is paused underneath it, and a SynchronizationContext post
would wait for the frame that comes only once the flow is gone - the close
action would reach the listener with nothing left to dismiss. Measured on a
device with the SDK harness against the wrapper this replaces.

R8 needs no rule of its own: android-sdk's consumer rules keep com.adapty.**.
harness_build_android builds the harness scene as a Development ARM64 player.
The stock Pipeline runtime server cannot run on a device - it writes its
descriptor next to Application.dataPath, which is the APK - so
AndroidHarnessServer turns the driver's autostart off and runs a subclass that
writes the descriptor into the app's internal files directory, with a token of
its own. The host pulls it with run-as, rewrites pid and heartbeat to what the
CLI accepts, and bridges the port with adb forward; the harness AGENTS.md has
the steps and the pause behaviour under a flow.

Pipeline 0.6.0-exp.1 starts the runtime server from Project Settings >
Pipeline > Runtime rather than a scene component; the settings file enables it
on port 7900.
…nced

Pipeline 0.6.0 has no such component; the runtime server is configured in
Project Settings > Pipeline > Runtime, and the scene showed a missing script.
Under GameActivity - the default entry point of a new Unity 6 project - Unity's
scripting thread has no Java Looper, so the bridge threw on its first use and
no call reached the SDK; 4.1.0-4.1.2 with the Java wrapper registered nothing
and dropped every completion and event instead. While a flow is on screen
GameActivity also stops the player loop, SynchronizationContext and
UnityPlayer.invokeOnMainThread alike, so a RunOnMainThread fallback would leave
a flow that cannot be closed.

AdaptyAndroidLooper registers an eventfd on the thread's native ALooper through
P/Invoke into libc and libandroid, and drains its queue in the looper callback.
That looper keeps turning through the pause on both entry points - Looper.loop()
polls it under UnityPlayerActivity, the activity glue under GameActivity - so
it replaces the Handler outright; a Handler on Looper.myLooper() would also
bind to a Looper nobody loops if something called Looper.prepare() there.

Checked on an Android 17 emulator: calm9 closed from the flow's close action
and from system Back while Unity was paused, on both entry points with Unity
6000.4, GameActivity also on 6000.0 and 6000.6. The AGENTS.md #if count is
corrected to what the package holds.
@StanislavMayorov

Copy link
Copy Markdown
Contributor

@codex

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T10:30:04.897369Z 6e142ac Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e142ac2aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

{
// The Pipeline build processor reads this flag, not the build options: with Enable In
// Builds on and the flag off it cancels an interactive build as a release one.
EditorUserBuildSettings.development = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Set the development flag for the iOS harness build

When harness_build runs from a fresh Editor where EditorUserBuildSettings.development is false, the newly enabled Pipeline 0.6 build processor also applies to that iOS build, but Build() never sets this flag—the assignment is present only in BuildAndroid(). Because the processor reads the Editor flag rather than BuildOptions.Development, the documented iOS harness command is treated as a release build and canceled despite passing the development option; set the flag for the iOS path as well.

AGENTS.md reference: Assets/SdkHarness/AGENTS.md:L34-L34

Useful? React with 👍 / 👎.

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.

2 participants