Skip to content

[Experimental] Web purchase redemption#1889

Merged
tonidero merged 22 commits into
mainfrom
eco-1550-rcbillingmobilesdk-add-new-apis-to-read-deep-links-2
Oct 30, 2024
Merged

[Experimental] Web purchase redemption#1889
tonidero merged 22 commits into
mainfrom
eco-1550-rcbillingmobilesdk-add-new-apis-to-read-deep-links-2

Conversation

@tonidero

@tonidero tonidero commented Oct 24, 2024

Copy link
Copy Markdown
Contributor

Description

This adds experimental support to redeeming anonymous web purchases performed through RCBilling. The main API changes here are:

  • Adds a new Purchases.parseAsDeepLink that parses the intent and returns a deep link if it needs to be handled
  • Adds a new Purchases.sharedInstance.redeemWebPurchase that uses a parsed deep link to perform the redemption.
  • Adds a new DeepLink sealed class with the types of deep links
  • Adds a new RedeemWebPurchaseListener to listen to the result of the redemption.
  • Adds a new RedeemWebPurchaseListener.Result sealed class with the result of the redemption.

All these are currently experimental APIs

@tonidero tonidero changed the base branch from eco-1550-rcbillingmobilesdk-add-new-apis-to-read-deep-links to main October 24, 2024 13:25
@tonidero tonidero force-pushed the eco-1550-rcbillingmobilesdk-add-new-apis-to-read-deep-links-2 branch from 306ba28 to c158a87 Compare October 24, 2024 13:30

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.

Not a fan of the developer having to handle the deep links like this... I think there is a big chance of the developer passing us the same link multiple times (which could still happen with the approach in #1880 but less likely IMO).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we keep track of what is already redeemed? E.g. by storing those tokens/urls on disk or something.

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.

Yes we could... Though I guess there is also a chance it's a valid use case to redeem, as in, maybe the redemption failed the first time due to a connection error or something and they need to try again. I guess we could only "cache" it if there is a successful redemption in this case, but if we for example add deep links to display the paywall in the future, there would be valid use cases of showing the paywall multiple times.

Not to say it's not ok! This approach does provide much more flexibility to the developer, but also more responsibility :P

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yea indeed, I meant to cache successful redemptions. If only to alleviate our own backend. Paywall or other non web purchase deeplinks would indeed be excluded from this.

Comment thread gradle.properties Outdated
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
class MainActivity : AppCompatActivity() {

internal var rcDeepLink: Purchases.DeepLink? = null

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.

If multiple links are used continuously before redeeming each, the developer is in charge of handling each on their own... For this PoC, I'm just caching the last one used, but again, it's more logic the developer will need to handle.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see your point, but wouldn't they need to manage the WebPurchaseRedeemer objects in the other approach?

I'm also trying to think how much of an edge case this is. Is it realistic that a user is buying multiple things, clicking on the links for each (e.g. before being logged in in the app), and then starts a login flow and expects that all purchases are then redeemed? Let me know if you have a different scenario in mind, just trying to think this through haha.

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 it's certainly an edge case... And yeah it might be ok to just leave it to the developer. We can always try to provide some code samples if devs start asking for them.

}

@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
override fun onResume() {

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.

Could have done this on the Activity, but preferred to do it in the fragment to show how it would be to handle at the UI part of the app (whether it's using compose or fragments)


@ExperimentalPreviewRevenueCatPurchasesAPI
sealed class DeepLink {
class WebRedemptionLink internal constructor(internal val redemptionToken: String) : DeepLink()

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.

Made everything internal. Devs shouldn't need to build an instance of this on their own, nor access the token directly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good call! What's the reason this is nested in Purchases? (Don't really have an opinion, just curious haha.)

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.

Mostly seemed DeepLink was too generic as a top-level class 😅 So I wanted to namespace it inside the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Haha alright makes sense! (Devs can always use import aliasing of course.)

@tonidero tonidero requested a review from a team October 24, 2024 13:34
@codecov

codecov Bot commented Oct 24, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 73.75000% with 21 lines in your changes missing coverage. Please review.

Project coverage is 82.16%. Comparing base (dad3113) to head (019a898).
Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
...m/revenuecat/purchases/deeplinks/DeepLinkParser.kt 0.00% 8 Missing ⚠️
.../kotlin/com/revenuecat/purchases/common/Backend.kt 80.64% 5 Missing and 1 partial ⚠️
...purchases/deeplinks/WebPurchaseRedemptionHelper.kt 85.71% 2 Missing and 1 partial ⚠️
.../purchases/interfaces/RedeemWebPurchaseListener.kt 50.00% 3 Missing ⚠️
...otlin/com/revenuecat/purchases/IntentExtensions.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1889      +/-   ##
==========================================
- Coverage   82.25%   82.16%   -0.09%     
==========================================
  Files         227      231       +4     
  Lines        7968     8048      +80     
  Branches     1121     1132      +11     
==========================================
+ Hits         6554     6613      +59     
- Misses        967      986      +19     
- Partials      447      449       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@JayShortway JayShortway left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do like it! Had some naming suggestions mostly. I also think it speaks to its simplicity that it's about half the additional lines vs the other approach (342 vs 767).

I think the main decision boils down to how much we want to cater to the edge case you mentioned, and how big of an edge case that is. Let me know if you have a different take!

Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt Outdated
Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt Outdated

@ExperimentalPreviewRevenueCatPurchasesAPI
sealed class DeepLink {
class WebRedemptionLink internal constructor(internal val redemptionToken: String) : DeepLink()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good call! What's the reason this is nested in Purchases? (Don't really have an opinion, just curious haha.)

@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
class MainActivity : AppCompatActivity() {

internal var rcDeepLink: Purchases.DeepLink? = null

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see your point, but wouldn't they need to manage the WebPurchaseRedeemer objects in the other approach?

I'm also trying to think how much of an edge case this is. Is it realistic that a user is buying multiple things, clicking on the links for each (e.g. before being logged in in the app), and then starts a login flow and expects that all purchases are then redeemed? Let me know if you have a different scenario in mind, just trying to think this through haha.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we keep track of what is already redeemed? E.g. by storing those tokens/urls on disk or something.

Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt Outdated
Comment thread purchases/src/main/kotlin/com/revenuecat/purchases/deeplinks/DeepLinkParser.kt Outdated
@tonidero tonidero changed the title [Do not merge][PoC] Web purchase redemption (round 2) [Do not merge][PoC] Web purchase redemption Oct 29, 2024
@tonidero tonidero changed the title [Do not merge][PoC] Web purchase redemption [Experimental] Web purchase redemption Oct 29, 2024
@tonidero tonidero marked this pull request as ready for review October 29, 2024 18:10
@tonidero tonidero requested review from a team and JayShortway October 29, 2024 18:10

@JayShortway JayShortway left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Amazing! Great job on this! Also good to see it's extensively tested. Had some minor comments / suggestions, but no blockers. Feel free to ignore at your discretion.

Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt
Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt Outdated
Comment thread purchases/src/defaults/kotlin/com/revenuecat/purchases/Purchases.kt
import android.content.Intent

@ExperimentalPreviewRevenueCatPurchasesAPI
@JvmSynthetic

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good one!

@tonidero tonidero enabled auto-merge (squash) October 30, 2024 13:15
@tonidero tonidero merged commit 6354b93 into main Oct 30, 2024
@tonidero tonidero deleted the eco-1550-rcbillingmobilesdk-add-new-apis-to-read-deep-links-2 branch October 30, 2024 13:35
tonidero pushed a commit that referenced this pull request Nov 4, 2024
**This is an automatic release.**

## RevenueCat SDK
### ✨ New Features
* [Experimental] Web purchase redemption (#1889) via Toni Rico
(@tonidero)
### 🐞 Bugfixes
* Keeps the org.json package. (#1891) via JayShortway (@JayShortway)
### 📦 Dependency Updates
* Bump rexml from 3.3.8 to 3.3.9 (#1892) via dependabot[bot]
(@dependabot[bot])
* Bump danger from 9.5.0 to 9.5.1 (#1885) via dependabot[bot]
(@dependabot[bot])
* Bump fastlane from 2.224.0 to 2.225.0 (#1884) via dependabot[bot]
(@dependabot[bot])

## RevenueCatUI SDK
### 🐞 Bugfixes
* Fix application of modifiers in `Markdown` component (#1893) via Toni
Rico (@tonidero)

### 🔄 Other Changes
* [CI] Allow publishing snapshot releases manually from branches (#1888)
via Toni Rico (@tonidero)
* Detekt auto-fixes (#1886) via Toni Rico (@tonidero)

Co-authored-by: revenuecat-ops <ops@revenuecat.com>
tonidero added a commit that referenced this pull request Nov 8, 2024
### Description
This adds some new result types to a web purchase redemption:
- InvalidToken
- AlreadyRedeemed
- Expired. This one includes additional information like the obfuscated
email where a new token was/will be sent and whether that email was
sent.

This falls behind the experimental APIs introduced in #1889 

Additionally, this renames `parseAsDeepLink` to
`parseAsWebPurchaseRedemption` and removes the `DeepLink` type. This is
a breaking change, but should be ok since the API is marked as
experimental and not usable still by any customers.
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