Skip to content

Commit 09f0940

Browse files
authored
Merge pull request #408 from superwall/develop
2.7.14
2 parents f5cc4ca + 6eaf64e commit 09f0940

7 files changed

Lines changed: 46 additions & 19 deletions

File tree

.github/badges/branches.svg

Lines changed: 1 addition & 1 deletion
Loading

.github/badges/jacoco.svg

Lines changed: 1 addition & 1 deletion
Loading

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
The changelog for `Superwall`. Also see the [releases](https://github.com/superwall/Superwall-Android/releases) on GitHub.
44

5+
## 2.7.14
6+
7+
## Fixes
8+
9+
- Fixes test mode products not being loaded properly in PW
10+
- Improve exponential backoff retry for Play Service unavailable
11+
- Fix Custom Info date serialization issues
12+
513
## 2.7.13
614

715
## Fixes

superwall/src/main/java/com/superwall/sdk/billing/BillingClientUseCase.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ internal typealias ExecuteRequestOnUIThreadFunction = (delayInMillis: Long, onEr
1414
private const val MAX_RETRIES_DEFAULT = 3
1515
private const val RETRY_TIMER_START_MILLISECONDS = 878L // So it gets close to 15 minutes in last retry
1616
internal const val RETRY_TIMER_MAX_TIME_MILLISECONDS = 1000L * 60L * 15L // 15 minutes
17+
private const val FOREGROUND_BACKOFF_START_MILLISECONDS = 250L
18+
private const val FOREGROUND_BACKOFF_MAX_ATTEMPTS = 2
1719

1820
internal interface UseCaseParams {
1921
val appInBackground: Boolean
@@ -33,6 +35,7 @@ internal abstract class BillingClientUseCase<T>(
3335
private val maxRetries: Int = MAX_RETRIES_DEFAULT
3436
private var retryAttempt: Int = 0
3537
private var retryBackoffMilliseconds = RETRY_TIMER_START_MILLISECONDS
38+
private var foregroundBackoffAttempt: Int = 0
3639

3740
fun run(delayMilliseconds: Long = 0) {
3841
executeRequestOnUIThread(delayMilliseconds) { connectionError ->
@@ -144,11 +147,28 @@ internal abstract class BillingClientUseCase<T>(
144147
} else {
145148
onError(billingResult)
146149
}
150+
} else if (retryAttempt < maxRetries) {
151+
Logger.debug(
152+
logLevel = LogLevel.warn,
153+
scope = LogScope.productsManager,
154+
message = "Billing unavailable in foreground. Retry ${retryAttempt + 1}/$maxRetries (immediate).",
155+
)
156+
retryAttempt++
157+
executeAsync()
158+
} else if (foregroundBackoffAttempt < FOREGROUND_BACKOFF_MAX_ATTEMPTS) {
159+
val delay = FOREGROUND_BACKOFF_START_MILLISECONDS shl foregroundBackoffAttempt
160+
Logger.debug(
161+
logLevel = LogLevel.warn,
162+
scope = LogScope.productsManager,
163+
message = "Billing unavailable in foreground. Backoff retry ${foregroundBackoffAttempt + 1}/$FOREGROUND_BACKOFF_MAX_ATTEMPTS in ${delay}ms.",
164+
)
165+
foregroundBackoffAttempt++
166+
run(delay)
147167
} else {
148168
Logger.debug(
149169
logLevel = LogLevel.error,
150170
scope = LogScope.productsManager,
151-
message = "Billing is unavailable. App is in foreground. Won't retry.",
171+
message = "Billing unavailable. Foreground retries exhausted.",
152172
)
153173
onError(billingResult)
154174
}

superwall/src/main/java/com/superwall/sdk/models/customer/CustomerInfo.kt

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ package com.superwall.sdk.models.customer
33
import com.superwall.sdk.models.entitlements.Entitlement
44
import com.superwall.sdk.models.entitlements.SubscriptionStatus
55
import com.superwall.sdk.models.product.Store
6+
import com.superwall.sdk.network.JsonFactory
67
import com.superwall.sdk.storage.LatestDeviceCustomerInfo
78
import com.superwall.sdk.storage.LatestRedemptionResponse
89
import com.superwall.sdk.storage.Storage
910
import com.superwall.sdk.storage.core_data.convertFromJsonElement
1011
import kotlinx.serialization.SerialName
1112
import kotlinx.serialization.Serializable
1213
import kotlinx.serialization.Transient
13-
import kotlinx.serialization.json.Json
14-
import kotlinx.serialization.json.JsonNamingStrategy
1514
import kotlinx.serialization.json.jsonObject
1615

1716
/**
@@ -58,7 +57,7 @@ data class CustomerInfo(
5857
*/
5958
fun toParams(): Map<String, Any?> {
6059
if (isPlaceholder) return emptyMap()
61-
val obj = paramsJson.encodeToJsonElement(serializer(), this).jsonObject
60+
val obj = JsonFactory.JSON.encodeToJsonElement(serializer(), this).jsonObject
6261
return obj
6362
.mapValues { (_, value) -> value.convertFromJsonElement() }
6463
}
@@ -87,16 +86,6 @@ data class CustomerInfo(
8786
}
8887

8988
companion object {
90-
private val paramsJson = Json {
91-
try {
92-
93-
namingStrategy = JsonNamingStrategy.SnakeCase
94-
} catch (e: Throwable) {
95-
}
96-
encodeDefaults = true;
97-
ignoreUnknownKeys = true
98-
}
99-
10089
/**
10190
* Creates a blank CustomerInfo instance for testing or default states.
10291
*/

superwall/src/main/java/com/superwall/sdk/store/StoreManager.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,21 @@ class StoreManager(
133133
}
134134

135135
private suspend fun fetchOrAwaitProducts(fullProductIds: Set<String>): Map<String, StoreProduct> {
136+
val testProducts = testMode?.takeIf { it.isTestMode }?.testProductsByFullId.orEmpty()
137+
val testHits: Map<String, StoreProduct> =
138+
if (testProducts.isEmpty()) {
139+
emptyMap()
140+
} else {
141+
fullProductIds.mapNotNull { id -> testProducts[id]?.let { id to it } }.toMap()
142+
}
143+
val remainingIds = fullProductIds - testHits.keys
144+
if (remainingIds.isEmpty()) return testHits
145+
136146
val cached = mutableMapOf<String, StoreProduct>()
137147
val loading = mutableListOf<CompletableDeferred<StoreProduct>>()
138148
val newDeferreds = mutableMapOf<String, CompletableDeferred<StoreProduct>>()
139149

140-
for (id in fullProductIds) {
150+
for (id in remainingIds) {
141151
val state =
142152
productsByFullId.getOrPut(id) {
143153
val deferred = CompletableDeferred<StoreProduct>()
@@ -181,7 +191,7 @@ class StoreManager(
181191

182192
val fetched = fetchNewProducts(newDeferreds)
183193

184-
return cached + awaited + fetched
194+
return testHits + cached + awaited + fetched
185195
}
186196

187197
private suspend fun fetchNewProducts(deferreds: Map<String, CompletableDeferred<StoreProduct>>): Map<String, StoreProduct> {

version.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
SUPERWALL_VERSION=2.7.13
1+
SUPERWALL_VERSION=2.7.14

0 commit comments

Comments
 (0)