-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Paywalls can use custom in-app purchase/restore code (#1777)
This allows someone who's adopting RevenueCat paywalls to use their own app purchase/restore logic rather than RevenueCat's. This is done by implementing `MyAppPurchaseLogic`, which has two functions that implement the custom purchase and restore functions. ```kotlin interface MyAppPurchaseLogic { suspend fun performPurchase(activity: Activity, rcPackage: Package): MyAppPurchaseResult suspend fun performRestore(customerInfo: CustomerInfo): MyAppRestoreResult } ``` Users can also use completion handlers by implementing this abstract class instead: ```kotlin abstract class MyAppPurchaseLogicCompletion : MyAppPurchaseLogic { abstract fun performPurchaseWithCompletion(activity: Activity, rcPackage: Package, completion: (MyAppPurchaseResult) -> Unit) abstract fun performRestoreWithCompletion(completion: (MyAppRestoreResult) -> Unit) final override suspend fun performPurchase(activity: Activity, rcPackage: Package): MyAppPurchaseResult = suspendCoroutine { continuation -> performPurchaseWithCompletion(activity, rcPackage) { result -> continuation.resume(result) } } final override suspend fun performRestore(customerInfo: CustomerInfo): MyAppRestoreResult = suspendCoroutine { continuation -> performRestoreWithCompletion { result -> continuation.resume(result) } } } ``` An nullable instance of this interface is now part of `PaywallOptions` and `PaywallDialogOptions`, and settable via the builders. These classes are used when creating a Paywall. Builder function: ```kotlin fun setMyAppPurchaseLogic(myAppPurchaseLogic: MyAppPurchaseLogic?) = apply { this.myAppPurchaseLogic = myAppPurchaseLogic } ``` When a `MyAppPurchaseLogic` is provided, the paywall viewmodel will use this logic instead of RevenueCat's _if_ `Purchases` is configured such that `PurchasesAreCompletedBy.MY_APP`. This happens in `PaywallViewModelImpl`, methods `awaitRestorePurchases` and `awaitRestorePurchases`. If a `PaywallViewModel` is constructed _without_ being provided with an instance of MyAppPurchaseLogic when PurchasesAreCompletedBy.MY_APP, it will throw: ```kotlin // called by constructor private fun validateState() { if (purchases.purchasesAreCompletedBy == PurchasesAreCompletedBy.MY_APP && options.myAppPurchaseLogic == null) { error( "myAppPurchaseLogic is null, but is required when purchases.purchasesAreCompletedBy is .MY_APP." ) } } ``` PaywallViewModel` refactored a bit to make awaitable versions of purchase and restore functions. This has made the PaywallViewModel.kt diff a bit messy, but the change here was breaking it up so that the awaitable versions wouldn't create a co-routine context, and the code that checks what `purchasesAreCompletedBy` is, and executing either the customer code or (as previous) the RC code to do the purchase/restore. To make the paywalls tester app run the custom code blocks, make these temporary additional changes: <img width="646" alt="image" src="https://github.com/user-attachments/assets/c1570723-fafe-41f4-86d2-abf6411016cd"> --------- Co-authored-by: JayShortway <29483617+JayShortway@users.noreply.github.com>
- Loading branch information
1 parent
cabcff0
commit 4c89ab6
Showing
12 changed files
with
823 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
...ster/src/defaults/kotlin/com/revenuecat/apitester/kotlin/revenuecatui/PurchaseLogicAPI.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.revenuecat.apitester.kotlin.revenuecatui | ||
|
||
import android.app.Activity | ||
import com.revenuecat.purchases.CustomerInfo | ||
import com.revenuecat.purchases.Package | ||
import com.revenuecat.purchases.PurchasesError | ||
import com.revenuecat.purchases.PurchasesErrorCode | ||
import com.revenuecat.purchases.ui.revenuecatui.PurchaseLogic | ||
import com.revenuecat.purchases.ui.revenuecatui.PurchaseLogicResult | ||
import com.revenuecat.purchases.ui.revenuecatui.PurchaseLogicWithCallback | ||
|
||
@Suppress("unused", "UNUSED_VARIABLE") | ||
private class PurchaseLogicAPI { | ||
|
||
suspend fun check( | ||
mySuspendLogic: PurchaseLogic, | ||
activity: Activity, | ||
rcPackage: Package, | ||
customerInfo: CustomerInfo, | ||
) { | ||
val suspendLogicPurchase: PurchaseLogicResult = mySuspendLogic.performPurchase(activity, rcPackage) | ||
val suspendLogicRestore: PurchaseLogicResult = mySuspendLogic.performRestore(customerInfo) | ||
} | ||
} | ||
|
||
@Suppress("unused") | ||
private class PurchaseLogicWithCallbackAPI : PurchaseLogicWithCallback() { | ||
|
||
override fun performPurchaseWithCompletion( | ||
activity: Activity, | ||
rcPackage: Package, | ||
completion: (PurchaseLogicResult) -> Unit, | ||
) { | ||
val success = PurchaseLogicResult.Success | ||
val cancelled = PurchaseLogicResult.Cancellation | ||
val failed = PurchaseLogicResult.Error(PurchasesError(PurchasesErrorCode.StoreProblemError)) | ||
completion(success) | ||
} | ||
|
||
override fun performRestoreWithCompletion(customerInfo: CustomerInfo, completion: (PurchaseLogicResult) -> Unit) { | ||
val success = PurchaseLogicResult.Success | ||
val cancelled = PurchaseLogicResult.Cancellation | ||
val failed = PurchaseLogicResult.Error(PurchasesError(PurchasesErrorCode.StoreProblemError)) | ||
completion(failed) | ||
} | ||
|
||
@Suppress("unused") | ||
fun check( | ||
activity: Activity, | ||
rcPackage: Package, | ||
customerInfo: CustomerInfo, | ||
) { | ||
performPurchaseWithCompletion( | ||
activity, | ||
rcPackage, | ||
) { result: PurchaseLogicResult -> } | ||
|
||
performRestoreWithCompletion( | ||
customerInfo, | ||
) { result: PurchaseLogicResult -> } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.