Skip to content

Fix Galaxy Store hang by timing out transaction lookup#436

Merged
ianrumac merged 3 commits into
developfrom
claude/galaxy-store-purchase-hang-apgr3k
Jul 22, 2026
Merged

Fix Galaxy Store hang by timing out transaction lookup#436
ianrumac merged 3 commits into
developfrom
claude/galaxy-store-purchase-hang-apgr3k

Conversation

@ianrumac

Copy link
Copy Markdown
Collaborator

Changes in this pull request

  • Refactored transaction lookup logic into a new awaitLatestTransaction() helper method that centralizes transaction verification across multiple call sites
  • Added timeout protection for external purchase controllers (e.g., Galaxy Store) that may bypass Google Play entirely, preventing indefinite suspension when the billing client never emits a result
  • Clear stale purchase results before initiating new purchases to prevent resolution against outdated transactions from previous purchase flows
  • Added regression test for Galaxy Store scenario where external purchase controller completes purchase outside Google Play

Technical Details

The Galaxy Store integration issue occurred because:

  1. External purchase controllers can complete purchases outside Google Play's billing system
  2. When this happens, the SDK's billing client never fires onPurchasesUpdated()
  3. The old code would call getLatestTransaction() without timeout, causing indefinite suspension
  4. This hung the entire purchase flow

The fix introduces:

  • awaitLatestTransaction() method that wraps transaction lookup with a 5-second timeout when an external purchase controller is present
  • Falls back to null transaction if timeout occurs (safe since transactions only enrich tracking events)
  • Clears purchaseResults before new purchases to prevent stale transaction matching
  • Consolidates transaction lookup logic to reduce duplication

Test Coverage

Added purchase_internalWithExternalControllerAndNoPlayResult_completesWithoutHanging() test that:

  • Simulates Galaxy Store scenario where PurchaseController completes purchase outside Play
  • Verifies purchase completes without hanging despite getLatestTransaction() never returning
  • Confirms transaction tracking events complete with null transaction

Checklist

  • All unit tests pass (including new regression test)
  • Change is covered by automated tests
  • No breaking changes to public API
  • Follows existing code patterns and conventions

https://claude.ai/code/session_01YTvfzggPBxHokZmZdauvwo

claude and others added 3 commits July 22, 2026 15:18
When a custom PurchaseController completes a purchase on a non-Play
store (e.g. Galaxy Store), Google Play Billing never fires
onPurchasesUpdated, so getLatestTransaction() suspended forever on the
purchaseResults StateFlow. Paywall purchases then never resolved: no
transaction_complete, no dismissal, spinner stuck indefinitely.

- Bound the wait with a 5s timeout when an external purchase controller
  is in use; the controller's result is the source of truth and the Play
  transaction only enriches tracking events, so fall back to null.
- Clear the retained purchaseResults value when a purchase starts so a
  purchase can't be resolved against a stale transaction from an
  earlier one (StateFlow retains the last emission indefinitely).
- Remove a redundant duplicate getLatestTransaction() await in the
  external purchase path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTvfzggPBxHokZmZdauvwo
prepareToPurchase now clears billing.purchaseResults at purchase start,
which the strict mock in the androidTest TransactionManagerTest didn't
stub, failing internal purchase tests with MockKException.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTvfzggPBxHokZmZdauvwo
@ianrumac
ianrumac merged commit 3e5244b into develop Jul 22, 2026
12 checks 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.

2 participants