Skip to content

Galaxy Store Purchasing Happy Path#2922

Merged
fire-at-will merged 10 commits into
samsung-devfrom
purchase-galaxy-products
Dec 12, 2025
Merged

Galaxy Store Purchasing Happy Path#2922
fire-at-will merged 10 commits into
samsung-devfrom
purchase-galaxy-products

Conversation

@fire-at-will

@fire-at-will fire-at-will commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

Description

This PR enables support for making purchases through the Galaxy Store. To keep the PR size down, it primarily considers the happy path where the purchase succeeds with no issues.

It:

  • Sets the IapHelper's operation mode when the GalaxyBillingWrapper is initialized.
  • Forwards purchase requests to the IapHelper through the PurchaseHandler class
  • Converts PurchaseVo responses to StoreTransactions for successful purchases
  • Forwards errors to the purchase listener, but doesn't attempt to parse specific errors
  • Adds unit tests :)

To keep the PR size down, the PR does not:

  • Acknowledge purchases with Samsung
  • Attempt to parse specific error codes from the PurchaseVo object.
    We'll tackle these features in future PRs.

@fire-at-will fire-at-will added the pr:feat A new feature label Dec 11, 2025
@fire-at-will fire-at-will changed the title [WIP]: Purchase Galaxy Store Products Galaxy Store Purchasing Happy Path Dec 11, 2025
val iapHelper: IapHelper,
) : IAPHelperProvider {

override fun setOperationMode(

@fire-at-will fire-at-will Dec 11, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This function doesn't need to be @GalaxySerialOperation. Since the operation doesn't make a network request, Samsung doesn't take this function into account when restricting which operations can be performed in parallel.

),
)
clearInFlightRequest()
return

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This return isn't really necessary, but I included it in case we ever add anything beneath this block in the future :)

}

// TO DO: Map galaxy errors to PurchaseErrors so we can give better errors
val purchasesError = PurchasesError(PurchasesErrorCode.StoreProblemError, underlyingErrorMessage)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We'll flesh this out and parse specific error codes in a future PR

@fire-at-will fire-at-will marked this pull request as ready for review December 11, 2025 22:40
@fire-at-will fire-at-will requested a review from a team as a code owner December 11, 2025 22:40

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looking great! Amazing we're already doing purchases 🙌 . Just left some comments

productIds = listOf(productId),
type = type,
purchaseTime = purchaseDate.time,
purchaseToken = this.orderId,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So the orderId is what we need in the backend to validate the purchase, correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe so, but will confirm with the backend engineers!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Checked with the backend engineers, and this value should be the PurchaseVo's purchaseId. Updated this to use purchaseId in b978aa3 👍


internal fun String.parseDateFromGalaxyDateString(): Date {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT).apply {
timeZone = TimeZone.getDefault()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm is the date sent from the galaxy library timezone aware? Not sure if maybe matching the Samsung account timezone? We should make sure it's correct on different device timezones and with different Samsung account timezones

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, we should probably get confirmation from Samsung on this. I'll see if I can find it in the SDK's decompiled code, and if not, we can see if we can ask Samsung. In my testing, it came back in my device's timezone (which for some reason is 1 hour ahead of my own timezone 😅)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@tonidero I think we're good here now.

For future reference in case anyone sees this, it looks like this is how the date string is created:

  1. Samsung Store server sends down a timestamp in a JSON object
  2. PurchaseVo gets created from that JSON
  3. When PurchaseVo is created, it’s using simple DateFormat.format parsing:
String result = "";
String dateFormat = "yyyy-MM-dd HH:mm:ss";
result = DateFormat.format(dateFormat, _timeMills).toString();

}
val storeProduct = galaxyPurchaseInfo.storeProduct

if (!shouldFinishTransactions()) { return }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm I think the meaning of finishing a transaction is wrong here... In this case, seems we wouldn't be finishing the transaction at all. Whereas it should mean we won't actually "acknowledge" and/or "consume" the purchase. But we would still allow purchasing with our SDK even with finishTransactions set to false.

However, I'm not sure if Galaxy store has a similar "acknowledge" and/or "consume" step to consider this 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, the Galaxy Store has a concept of acknowledging purchases, and it's something we'll need to implement in a follow up PR. Here are their docs on it: https://developer.samsung.com/iap/programming-guide/iap-helper-programming.html#Notify-Samsung-IAP-that-the-purchase-was-processed

I think you're right, maybe we shouldn't do this here. I included this because this is what we're doing today on Amazon, not sure if that's a bug or not:

I'll go ahead and remove this check here for now, and then when we implement the logic to acknowledge Galaxy purchases, we can surround that with an if(shouldFinishTransactions()) check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the check in c20d602 :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm that's indeed a good point... we do allow purchasing in Google when not finishing transactions, but seems we don't for Amazon... From a conceptual POV, I think not allowing to purchase when we're not going to finish transactions might make sense (we can discuss it with the team), but in that case, we should return an error, unlike what we have currently in Amazon, where it seems it would be left hanging 😬

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But yeah, allowing to purchase, and just not handle the acknowledge makes sense, since it's what we do for Google

return if (finishTransactions) {
true
} else {
log(LogIntent.AMAZON_WARNING) { AmazonStrings.WARNING_AMAZON_NOT_FINISHING_TRANSACTIONS }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This shouldn't be Amazon :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed this helper for now since we don't need finishTransactions at the moment 👍

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚢

@fire-at-will fire-at-will merged commit 1ee1234 into samsung-dev Dec 12, 2025
3 of 19 checks passed
@fire-at-will fire-at-will deleted the purchase-galaxy-products branch December 12, 2025 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants