Skip to content

Commit

Permalink
Keep adding fallbacks and workaround for billing
Browse files Browse the repository at this point in the history
  • Loading branch information
Nain57 committed Sep 14, 2024
1 parent 202489a commit a478271
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ internal class BillingDataSource @Inject constructor(
private val coroutineScopeIo: CoroutineScope =
CoroutineScope(SupervisorJob() + ioDispatcher)

private var billingClient: BillingClientProxy? = null

val product: Flow<InAppProduct?> =
productDetailsManager.productDetails
Expand All @@ -67,24 +68,29 @@ internal class BillingDataSource @Inject constructor(
}

private fun onBillingClientConnected(client: BillingClientProxy) {
billingClient = client

coroutineScopeIo.launch {
productDetailsManager.startMonitoring(client::fetchInAppProductDetails)
refreshPurchases()
}
}

private fun onBillingClientDisconnected() {
billingClient = null
productDetailsManager.stopMonitoring()
}

private fun onPurchaseUpdatedFromBillingUiFlow(purchase: Purchase?) {
val client = billingClient ?: return

coroutineScopeIo.launch {
billingServiceConnection.clientProxy?.refreshPurchases(purchase, fromQuery = false)
client.refreshPurchases(purchase, fromQuery = false)
}
}

fun refreshPurchases() {
val client = billingServiceConnection.clientProxy ?: return
val client = billingClient ?: return

coroutineScopeIo.launch {
client.refreshPurchases(
Expand All @@ -95,13 +101,12 @@ internal class BillingDataSource @Inject constructor(
}

fun launchBillingFlow(activity: Activity): StateFlow<BillingUiFlowState>? {
val client = billingServiceConnection.clientProxy ?: return null
val client = billingClient ?: return null
val details = productDetailsManager.productDetails.value ?: return null

return client.launchBillingFlow(activity, details)
}


private suspend fun BillingClientProxy.refreshPurchases(purchase: Purchase?, fromQuery: Boolean) {
purchaseManager.handleNewPurchases(
purchase = purchase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
Expand All @@ -45,20 +46,15 @@ internal class BillingServiceConnection @Inject constructor(
private val coroutineScopeMain: CoroutineScope =
CoroutineScope(SupervisorJob() + dispatcherMain)

private val clientConnectionListener = object : BillingClientStateListener {
override fun onBillingServiceDisconnected(): Unit = onDisconnected()
override fun onBillingSetupFinished(p0: BillingResult): Unit = onSetupResult(p0)
}

/** How long before the data source tries to reconnect to Google play. */
private var reconnectMilliseconds = RECONNECT_TIMER_START_MILLISECONDS
private var reconnectJob: Job? = null

private var connectionListener: ((BillingClientProxy?) -> Unit)? = null
private var monitoredProductId: String? = null
private var productPurchaseListener: ((Purchase?) -> Unit)? = null
private var clientProxy: BillingClientProxy? = null

var clientProxy: BillingClientProxy? = null
private set

fun monitorConnection(
productId: String,
Expand All @@ -78,9 +74,19 @@ internal class BillingServiceConnection @Inject constructor(
val productId = monitoredProductId ?: return
val clientListener = productPurchaseListener ?: return

// Documentation is unclear about what kind of error to expect here, just catch everything
try {
clientProxy?.client?.endConnection()
} catch (ex: Exception) {
Log.e(TAG, "Can't end connection with current client.")
}

clientProxy = BillingClientProxy(context, productId, clientListener)
try {
clientProxy?.client?.startConnection(clientConnectionListener)
clientProxy?.client?.startConnection(object : BillingClientStateListener {
override fun onBillingServiceDisconnected(): Unit = onDisconnected()
override fun onBillingSetupFinished(p0: BillingResult): Unit = onSetupResult(p0)
})
} catch (isex: IllegalStateException) {
Log.e(TAG, "connectToBillingService", isex)
retryBillingServiceConnectionWithExponentialBackoff()
Expand Down Expand Up @@ -116,15 +122,21 @@ internal class BillingServiceConnection @Inject constructor(
* specified by RECONNECT_TIMER_MAX_TIME_MILLISECONDS.
*/
private fun retryBillingServiceConnectionWithExponentialBackoff() {
coroutineScopeMain.launch {
if (reconnectJob != null) {
Log.e(TAG, "Reconnection job is already running")
return
}

reconnectJob = coroutineScopeMain.launch {
delay(reconnectMilliseconds)
reconnectMilliseconds = min(reconnectMilliseconds * 2, RECONNECT_TIMER_MAX_TIME_MILLISECONDS)

reconnectJob = null
connect()
}
}
}

private const val TAG = "BillingService"
private const val TAG = "BillingDataSource"
private const val RECONNECT_TIMER_START_MILLISECONDS = 1000L
private const val RECONNECT_TIMER_MAX_TIME_MILLISECONDS = 1000L * 60L * 15L // 15 minutes

0 comments on commit a478271

Please sign in to comment.