Save SDK configuration on paywall activity so it can reconfigure automatically#1872
Conversation
JayShortway
left a comment
There was a problem hiding this comment.
Pretty cool! Some suggestions, but this should be a nice improvement!
| } | ||
|
|
||
| fun getLatestConfiguration(): PurchasesConfiguration { | ||
| return configuration.copy(appUserID = this.appUserID) |
There was a problem hiding this comment.
We could also make configuration always be the latest? Otherwise we might get confused between configuration and getLatestConfiguration(), and when to use which.
There was a problem hiding this comment.
yeah good point... can probably clean this up a bit.
|
|
||
| private fun getSdkConfigArgs(savedInstanceState: Bundle): SdkConfigArgs? { | ||
| return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
| savedInstanceState.getParcelable(SDK_CONFIG_EXTRA, SdkConfigArgs::class.java) |
There was a problem hiding this comment.
I always found the warning in the docs for this one a bit scary:
Warning: the class that implements
Parcelablehas to be the immediately enclosing class of the runtime type of its CREATOR field (that is,Class.getEnclosingClass()has to return the parcelable implementing class), otherwise this method might throw an exception. If theParcelableclass does not enclose the CREATOR, use the deprecatedgetParcelable(String)instead.
We should be good, but we can also just use the deprecated variant to avoid it altogether. If we ever change things around in the future, we might run into this exception.
| private fun configureSdkWithSavedData(savedInstanceState: Bundle) { | ||
| val sdkConfigArgs = getSdkConfigArgs(savedInstanceState) | ||
| if (sdkConfigArgs == null) { | ||
| Logger.e("TEST: Missing SDK configuration arguments") |
There was a problem hiding this comment.
Good log, but maybe without the "TEST"? 😛
There was a problem hiding this comment.
😅 Yeah my bad, I didn't clean it up :P
| } | ||
|
|
||
| override fun hashCode(): Int { | ||
| var result = context.hashCode() |
There was a problem hiding this comment.
I think we can't compare the context nor the ExecutorService to do this since they can potentially be different. Wdyt?
There was a problem hiding this comment.
I think so too. For the purpose of checking whether the configuration set in PaywallActivity is the same as one set in a different Activity, we can ignore the Context and ExecutorService in the equality check. I don't know if we're doing any other equality checks though, or are intending to do so in the future?
| private fun configureSdkWithSavedData(savedInstanceState: Bundle) { | ||
| val sdkConfigArgs = getSdkConfigArgs(savedInstanceState) | ||
| if (sdkConfigArgs == null) { | ||
| Logger.e("TEST: Missing SDK configuration arguments") |
There was a problem hiding this comment.
😅 Yeah my bad, I didn't clean it up :P
| } | ||
|
|
||
| fun getLatestConfiguration(): PurchasesConfiguration { | ||
| return configuration.copy(appUserID = this.appUserID) |
There was a problem hiding this comment.
yeah good point... can probably clean this up a bit.
|
I changed the base to |
| } | ||
|
|
||
| val latestConfiguration: PurchasesConfiguration | ||
| get() = if (initialConfiguration.appUserID == null) { |
There was a problem hiding this comment.
I had to add this condition... Basically, the condition to avoid reconfiguration was never wrong if the developer doesn't set an appUserId. In this case, we should just reuse the last configured user id, so it should be safe.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1872 +/- ##
==========================================
- Coverage 82.41% 82.23% -0.19%
==========================================
Files 226 226
Lines 7915 7958 +43
Branches 1105 1119 +14
==========================================
+ Hits 6523 6544 +21
- Misses 952 967 +15
- Partials 440 447 +7 ☔ View full report in Codecov by Sentry. |
JayShortway
left a comment
There was a problem hiding this comment.
Looks good! Just had 2 more minor suggestions.
| get() = if (initialConfiguration.appUserID == null) { | ||
| initialConfiguration | ||
| } else { | ||
| initialConfiguration.copy(appUserID = this.appUserID) |
There was a problem hiding this comment.
We're now creating new copies every time this is read. Could we keep the up-to-date configuration in a backing var maybe? We can update it whenever the appUserId changes.
There was a problem hiding this comment.
Hmm I've been thinking whether this would be more work right now to calculate on user change or as it is now, when there is a configuration or the PaywallActivity's onSaveInstanceState is called... And I think it might be less work as it is right now? Normally users only configure once, so this won't be called, but there is a bigger chance of logging a different user (though also an uncommon case)... In any case I think we might be trying to early optimizing and I prefer to calculate it on the fly rather than trying to cache the value which might be outdated later... Lmk if you think otherwise!
There was a problem hiding this comment.
Yea this is less error prone, and the performance difference is probably negligible. I'm okay with it!
| } | ||
|
|
||
| @Test | ||
| fun `Calling configure multiple times with same configuration does not create a new instance`() { |
| Purchases.configure( | ||
| PurchasesConfiguration.Builder(this, sdkConfigArgs.apiKey) | ||
| .appUserID(sdkConfigArgs.appUserId) | ||
| .purchasesAreCompletedBy(sdkConfigArgs.purchasesAreCompletedBy) | ||
| .showInAppMessagesAutomatically(sdkConfigArgs.showInAppMessagesAutomatically) | ||
| .store(sdkConfigArgs.store) | ||
| .diagnosticsEnabled(sdkConfigArgs.diagnosticsEnabled) | ||
| .entitlementVerificationMode(sdkConfigArgs.verificationMode) | ||
| .dangerousSettings(sdkConfigArgs.dangerousSettings) | ||
| .pendingTransactionsForPrepaidPlansEnabled(sdkConfigArgs.pendingTransactionsForPrepaidPlansEnabled) | ||
| .build(), | ||
| ) |
There was a problem hiding this comment.
If we ever add a configuration option, we have to remember to add it to SdkConfigArgs. Can't really think of a solution though haha (other than some custom Detekt stuff or something).
There was a problem hiding this comment.
Yeah... it's not great but we are missing the mandatory Context parameter so can't think of a good solution either 😞
**This is an automatic release.** ## RevenueCat SDK ### 🐞 Bugfixes * Save SDK configuration on paywall activity so it can reconfigure automatically (#1872) via Toni Rico (@tonidero) ### 📦 Dependency Updates * Bump fastlane from 2.223.1 to 2.224.0 (#1870) via dependabot[bot] (@dependabot[bot]) * Bump fastlane-plugin-revenuecat_internal from `5b2e35c` to `3b1e7cf` (#1865) via dependabot[bot] (@dependabot[bot]) * Bump fastlane from 2.222.0 to 2.223.1 (#1860) via dependabot[bot] (@dependabot[bot]) * Bump fastlane-plugin-revenuecat_internal from `55a0455` to `5b2e35c` (#1858) via dependabot[bot] (@dependabot[bot]) ### 🔄 Other Changes * [CustomerCenter] Fix help path deserializing when unknown type (#1869) via Toni Rico (@tonidero) * [CustomerCenter] Create `CustomerCenter` composable and view model with some initial UI (#1867) via Toni Rico (@tonidero) * [CustomerCenter] Add networking layer and models (#1859) via Toni Rico (@tonidero) * [CustomerCenter] Adds SubscriptionDetailsView (#1863) via JayShortway (@JayShortway) Co-authored-by: revenuecat-ops <ops@revenuecat.com>
### Motivation & Description This is a follow-up of #1872 We're getting some errors like this one in flutter: ``` Purchases$Companion.getSharedInstance pf.K - There is no singleton instance. Make sure you configure Purchases before trying to get the default instance. ``` The theory is that this might be related to a similar bug we fixed for paywalls of the app getting backgrounded and killed while on the CustomerCenter activity, and then crashing when coming back
Description
In here we store the latest known state for
Purchasesso we can reconfigure when displaying thePaywallActivityand the SDK is not configured. This may happen if the app is killed while displaying thePaywallActivity, the developer is not configuring in the application but on an activity and the user returns through the app through the recent apps menu.Additionally, it includes the changes from #1866 so we avoid reconfiguring the SDK if the configuration parameters are the same.