Add DeferredPurchasesListener, deprecate EntitlementsUpdateListener#423
Add DeferredPurchasesListener, deprecate EntitlementsUpdateListener#423
Conversation
…Listener Introduces a new DeferredPurchasesListener with onDeferredPurchaseCompleted callback for deferred purchase completions (SCA, Ask to Buy, etc.). - New DeferredPurchasesListener interface and TurboModule event - Adapter pattern: deprecated setEntitlementsUpdateListener wraps to new interface - Config supports both listeners, new takes priority - iOS/Android native bridges emit both events from entitlements delegate - 9 unit tests covering new listener, adapter, config, backward compat DEV-643 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The adapter pattern had a future-breaking bug: when sandwich adds real deferred purchase filtering, old customers using setEntitlementsUpdateListener would silently lose non-deferred updates because the adapter routed them through onDeferredPurchaseCompleted. Fix: two independent listener slots, each with its own native event. - setEntitlementsUpdateListener → onEntitlementsUpdated (all updates) - setDeferredPurchasesListener → onDeferredPurchaseCompleted (deferred only) Both can coexist. Old code is future-proof when filtering is added. Tests updated: 11 cases (was 9). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Self-ReviewWhat this PR does now
What this PR does NOT doNo actual deferred purchase filtering yet. Both events currently fire from the same source ( True filtering requires one of:
Architecture decision: separate slots, not adapterThe initial commit used an adapter pattern ( Current architecture:
Both can coexist. Old code is future-proof. Remaining work
|
Track pending purchase product IDs from purchaseWithResult, correlate against entitlement updates to fire deferredPurchasesListener only for actual deferred purchase completions. Revert native-side dual emission back to single onEntitlementsUpdated — filtering is handled in JS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LEVER Self-ReviewLogic✅ Correlation filtering correctly tracks
Edge cases✅ No double-fire: Risks
Backward compatibility✅ Old Verification✅ 12 TDD tests pass (Red → Green methodology) |
Replace JS-layer filtering with native DeferredPurchasesListener from Sandwich SDK. The listener now receives a DeferredTransaction object with full transaction details instead of entitlements. - Add DeferredTransaction model - Wire native onDeferredPurchaseCompleted event (iOS + Android) - Remove JS-side pendingPurchaseProductIds tracking - Update DeferredPurchasesListener to use DeferredTransaction - 10 tests passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NickSxti
left a comment
There was a problem hiding this comment.
Self-review notes after rework to native events:
Architecture change - Replaced JS-layer pendingPurchaseProductIds filtering with direct native onDeferredPurchaseCompleted event from Sandwich SDK. This is more reliable (no in-memory state lost on app restart) and consistent with how the native SDKs work.
Breaking change in DeferredPurchasesListener interface - onDeferredPurchaseCompleted now receives a DeferredTransaction object (with productId, transactionId, originalTransactionId, type, value, currency) instead of Map<string, Entitlement>. Since this was not yet released, this is fine.
Native module changes:
- iOS: Added
qonversionDidCompleteDeferredPurchasetoQonversionEventDelegateprotocol andQonversionEventHandler, emits viaemitOnDeferredPurchaseCompletedinRNQonversion.mm - Android: Added
onDeferredPurchaseCompletedoverride inQonversionModule.kt, emits viaemitOnDeferredPurchaseCompleted
Event subscriptions are now independent - setDeferredPurchasesListener subscribes to onDeferredPurchaseCompleted (not onEntitlementsUpdated), so each listener has its own native event source.
10 tests passing covering: native event subscription, DeferredTransaction payload, listener replacement, independent event subscriptions, coexistence with EntitlementsUpdateListener.
Depends on: Sandwich SDK PR qonversion/sandwich-sdk#302
Summary
DeferredPurchasesListenerinterface withonDeferredPurchaseCompletedmethod for specifically handling deferred (pending) purchase completionsEntitlementsUpdateListener(still works for backward compat — fires for ALL entitlement updates)purchaseWithResultwhen status is PENDING, match againstonEntitlementsUpdatedevents to detect deferred purchase completionsonEntitlementsUpdatedevent, filtering is JS-onlyArchitecture
New public API
DeferredPurchasesListenerinterface (exported from index)QonversionConfigBuilder.setDeferredPurchasesListener(listener)QonversionApi.setDeferredPurchasesListener(listener)(runtime setter)Backward compatibility
setEntitlementsUpdateListenerstill works (marked@deprecated)Test plan
Known limitations
purchaseWithResulttracks pending status (deprecatedpurchase/purchaseProductdon't return PurchaseResult)🤖 Generated with Claude Code