[EXPERIMENTAL]: Beta Galaxy Store Support#2903
Conversation
### Description Introduces the scaffolding for several classes that will be foundational to Samsung development as we move forward: - `GalaxyBillingWrapper`: implementation of `BillingAbstract`. The class currently satisfies all of the BillingAbstract's requirements, but all functions are stubbed with `TODO`s - `GalaxyPurchasingData`: will be used when processing samsung purchases - `GalaxyStoreProduct`: represents a product from the Samsung store
### Description Adds the `GALAXY` to the list of supported Store types. > Note: This PR will have one failing integration test for the Customer Center's localized strings not containing the Galaxy Store string until a backend PR has been merged.
### Description
This PR creates a new module for the Galaxy Store, and allows developers
to set up the Android SDK to use the Galaxy Store when they configure
the SDK, like so:
```kotlin
val configuration = GalaxyConfiguration.Builder(
context,
apiKey,
GalaxyBillingMode.PRODUCTION,
).build()
Purchases.configure(configuration)
```
It also:
- Introduces `GalaxyBillingMode`, an enum required when configuring the
SDK to use the Galaxy Store, which determines the environment that the
Galaxy Store processes IAPs with (prod, test, etc.).
- When a Galaxy configuration is used, `BillingFactory` will wire up a
`GalaxyBillingWrapper`
- Adds unit tests :)
…er (#2906) ### Description The Galaxy Store doesn't support fetching the current storefront/country code or showing in-app messages, so this PR: - Logs + throws an error when `GalaxyBillingWrapper.getStorefront()` is called - Adds docs explaining that the storefront functions/properties aren't supported for the Galaxy Store - Adds a comment to `GalaxyBillingWrapper` to explicitly call out that in-app messages aren't supported
### Description Found an error edge case where we weren't calling `finish()`. This PR updates it so that we do call finish() and future requests can execute.
📸 Snapshot Test571 unchanged
🛸 Powered by Emerge Tools |
tonidero
left a comment
There was a problem hiding this comment.
Gave it a quick glance over. Looks good! One suggestion might be to add to the PR title that this feature is still experimental so it shows in the CHANGELOG.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| onGetProductsDetailsListener = this, | ||
| ) | ||
|
|
||
| this.inFlightRequest = request |
There was a problem hiding this comment.
inFlightRequest set after API call causes race condition
High Severity
ProductDataHandler sets inFlightRequest on line 88 after dispatching the request via iapHelper.getProductsDetails() on lines 83-86. If the callback onGetProducts fires before line 88 executes, inFlightRequest will be null, causing the response callbacks (onReceive/onError) to silently not be invoked. Every other handler (PurchaseHandler, AcknowledgePurchaseHandler, GetOwnedListHandler, ChangeSubscriptionPlanHandler, PromotionEligibilityHandler) correctly sets inFlightRequest before dispatching the request.
There was a problem hiding this comment.
Will address in a follow-up PR 👍
| clearInFlightRequest() | ||
| onError?.invoke(purchasesError) | ||
| return | ||
| } |
There was a problem hiding this comment.
Empty promotion eligibility treated as error blocks products
High Severity
handleSuccessfulGetPromotionEligibilityResponse treats an empty promotionEligibilities list as an error. When users aren't eligible for any promotions (a perfectly valid state), this causes the entire product fetch in ProductDataHandler to fail via the onError callback. Products without promotions or for non-eligible users would never be returned. The error string also references "acknowledgement results," suggesting a copy-paste issue.
There was a problem hiding this comment.
Will address in a follow-up PR 👍
There was a problem hiding this comment.
I just double checked to confirm, and if a product isn't eligible for a promotion, we still receive a PromotionEligibilityVo object for the product, where pricing = RegularPrice, so this isn't an issue. I'll add a comment to the code to document this.
| .filter { | ||
| // TO DO: Find out what this returns for OTPs when we support OTPs | ||
| it.subscriptionEndDate.parseDateFromGalaxyDateString() > dateProvider.now | ||
| } |
There was a problem hiding this comment.
Uncaught exception in filter blocks serial executor permanently
Medium Severity
In queryPurchases, parseDateFromGalaxyDateString() is called inside a .filter block without a try-catch. This function throws IllegalArgumentException on unparseable dates. Unlike the .map block below which catches this exception, an uncaught throw here prevents finish() from ever being called on the SerialRequestExecutor, permanently blocking all future Galaxy Store operations.
There was a problem hiding this comment.
Will address in a follow-up PR 👍
### Description Adds a clarifying comment in response to this review comment raised by Cursor: #2903 (comment) I double checked with a manual test to confirm the behavior :) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Comment-only change with no behavioral impact; low risk aside from potential documentation drift if the upstream API behavior changes. > > **Overview** > Adds a clarifying comment in `PromotionEligibilityHandler.handleSuccessfulGetPromotionEligibilityResponse` explaining that Samsung’s API returns `PromotionEligibilityVo` entries even for non-eligible products (with `"RegularPrice"`), so an *empty* success response indicates an unexpected/error condition and links to the relevant Samsung documentation. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 89a4bef. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
**This is an automatic release.** ## RevenueCat SDK ### ✨ New Features * [EXPERIMENTAL]: Beta Galaxy Store Support (#2903) via Will Taylor (@fire-at-will) ### 🐞 Bugfixes * Skip installation on GCP CLI in run-firebase-test (#3218) via Will Taylor (@fire-at-will) * Fix reduced timeouts being used for HTTP requests when a proxy URL is configured (#3188) via Rick (@rickvdl) ## RevenueCatUI SDK ### 🐞 Bugfixes * Fix missing ripple effect in View-based paywall wrappers (#3206) via Toni Rico (@tonidero) ### Paywallv2 #### ✨ New Features * Rules v0 Integration branch (#3117) via Cesar de la Vega (@vegaro) ### 🔄 Other Changes * [Galaxy]: Add promotionEligibilities comment (#3214) via Will Taylor (@fire-at-will) * [EXTERNAL] Migrate deprecated buildDir to layout API (#3202) contributed by @AlexanderTalledo (#3212) via Toni Rico (@tonidero) * Remove automatic Claude code review workflow (#3211) via Cesar de la Vega (@vegaro) * Remove unused convention plugin (#3195) via Toni Rico (@tonidero) * [EXTERNAL] Integrate convention plugins into Version Catalogs (#3181) contributed by @AlexanderTalledo (#3194) via Toni Rico (@tonidero) * [EXTERNAL] Migrate androidx cardview dependency to version catalogs (#3192) contributed by @AlenxanderTalledo (#3193) via Toni Rico (@tonidero) * Improve AdMob adapter test coverage (#3204) via Pol Miro (@polmiro) * Bump fastlane-plugin-revenuecat_internal from `f5c099b` to `e146447` (#3197) via dependabot[bot] (@dependabot[bot]) * Fix integration tests (#3196) via Toni Rico (@tonidero) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk release bookkeeping: version strings and deployment paths are updated from `9.24.0-SNAPSHOT` to `9.24.0`, plus changelog/docs refresh. Main risk is accidental publishing/docs deployment to the wrong versioned location. > > **Overview** > Cuts the `9.24.0` release by updating all version references from `9.24.0-SNAPSHOT` to `9.24.0` (root `.version`, `gradle.properties`, and `Config.frameworkVersion`), and aligning sample/test app version catalogs to consume the released artifact. > > Updates documentation publishing to point at the `9.24.0` directory (CircleCI S3 sync and `docs/index.html` redirect) and refreshes `CHANGELOG.latest.md`/`CHANGELOG.md` with the `9.24.0` release notes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8e6d567. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->


Description
Beta support for the Galaxy Store in the native Android SDK.
Note
High Risk
Introduces a new Galaxy billing integration (purchase, restore, product fetching, and subscription change flows) and wires it into CI/release packaging, which is core monetization logic and sensitive to store edge cases and dependency/versioning issues.
Overview
Adds an experimental
feature:galaxymodule to support Samsung Galaxy Store subscriptions, including aGalaxyConfigurationbuilder, aGalaxyBillingWrapperimplementation, and conversion/handler layers for product details, purchases, acknowledges, restores, and subscription plan changes.Updates build and CI/release tooling to conditionally include the Galaxy feature when the Samsung IAP AAR is available, download the AAR in CI via a new
downloadSamsungIapAartask, run a newtest-galaxyjob, and publish a Galaxy artifact. Updatesapi-testerand thepurchase-testersample to optionally compile/run with Galaxy support (new store selection, persistence, and warning/reflective setup when the module/AAR isn’t present).Written by Cursor Bugbot for commit bdc971a. This will update automatically on new commits. Configure here.