Update google play billing library

This commit is contained in:
Jonas Lochmann 2022-05-09 02:00:00 +02:00
parent 620af536ce
commit aa06c8aaed
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
5 changed files with 80 additions and 51 deletions

View file

@ -200,8 +200,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp-tls:4.9.3'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
googleApiImplementation "com.android.billingclient:billing:4.1.0"
googleApiImplementation "com.android.billingclient:billing-ktx:4.1.0"
googleApiImplementation "com.android.billingclient:billing-ktx:5.0.0"
implementation('io.socket:socket.io-client:2.0.0') {
exclude group: 'org.json', module: 'json'

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -123,12 +123,16 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
}
}
suspend fun querySkus(skuIds: List<String>): List<SkuDetails> = initAndUseClient { client ->
val (billingResult, data) = client.querySkuDetails(
SkuDetailsParams.newBuilder()
.setSkusList(skuIds)
.setType(BillingClient.SkuType.INAPP)
suspend fun queryProducts(productIds: List<String>): List<ProductDetails> = initAndUseClient { client ->
val (billingResult, data) = client.queryProductDetails(
QueryProductDetailsParams.newBuilder()
.setProductList(productIds.map { skuId ->
QueryProductDetailsParams.Product.newBuilder()
.setProductId(skuId)
.setProductType(BillingClient.ProductType.INAPP)
.build()
})
.build()
)
billingResult.assertSuccess()
@ -137,7 +141,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
}
suspend fun queryPurchases() = initAndUseClient { client ->
val response = client.queryPurchasesAsync(BillingClient.SkuType.INAPP)
val response = client.queryPurchasesAsync(
QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.ProductType.INAPP)
.build()
)
response.billingResult.assertSuccess()
@ -153,7 +161,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
try {
initAndUseClient { client ->
val result = client.queryPurchasesAsync(BillingClient.SkuType.INAPP)
val result = client.queryPurchasesAsync(
QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.ProductType.INAPP)
.build()
)
result.billingResult.assertSuccess()
@ -223,7 +235,7 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
Log.d(LOG_TAG, "handlePurchase($purchase)")
}
val sku = purchase.skus.single()
val sku = purchase.products.single()
if (PurchaseIds.SAL_SKUS.contains(sku)) {
// just acknowledge
@ -262,14 +274,14 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
}
}
fun startPurchase(sku: String, checkAtBackend: Boolean, activity: Activity) {
fun startPurchase(productId: String, checkAtBackend: Boolean, activity: Activity) {
runAsync {
try {
val skuDetails = querySkus(listOf(sku)).single()
val productDetails = queryProducts(listOf(productId)).single()
if (skuDetails.sku != sku) throw IllegalStateException()
if (productDetails.productId != productId) throw IllegalStateException()
startPurchase(skuDetails, checkAtBackend, activity)
startPurchase(productDetails, checkAtBackend, activity)
} catch (ex: Exception) {
if (BuildConfig.DEBUG) {
Log.d(LOG_TAG, "could not start purchase", ex)
@ -280,7 +292,7 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
}
}
fun startPurchase(skuDetails: SkuDetails, checkAtBackend: Boolean, activity: Activity) {
private fun startPurchase(productDetails: ProductDetails, checkAtBackend: Boolean, activity: Activity) {
runAsync {
initAndUseClient { client ->
try {
@ -299,10 +311,14 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
}
client.launchBillingFlow(
activity,
BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
activity,
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build()
))
.build()
).assertSuccess()
} catch (ex: Exception) {
if (BuildConfig.DEBUG) {

View file

@ -62,11 +62,11 @@ class PurchaseModel(application: Application): AndroidViewModel(application) {
if (canDoPurchase.publicKey?.contentEquals(Base64.decode(BuildConfig.googlePlayKey, 0)) == false) {
statusInternal.value = PurchaseFragmentServerHasDifferentPublicKey
} else {
val skus = activityPurchaseModel.querySkus(PurchaseIds.BUY_SKUS)
val skus = activityPurchaseModel.queryProducts(PurchaseIds.BUY_SKUS)
statusInternal.value = PurchaseFragmentReady(
monthPrice = skus.find { it.sku == PurchaseIds.SKU_MONTH }?.price.toString(),
yearPrice = skus.find { it.sku == PurchaseIds.SKU_YEAR }?.price.toString()
monthPrice = skus.find { it.productId == PurchaseIds.SKU_MONTH }?.oneTimePurchaseOfferDetails?.formattedPrice.toString(),
yearPrice = skus.find { it.productId == PurchaseIds.SKU_YEAR }?.oneTimePurchaseOfferDetails?.formattedPrice.toString()
)
}
} else if (canDoPurchase == CanDoPurchaseStatus.NotDueToOldPurchase) {

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -37,18 +37,18 @@ class StayAwesomeModel(application: Application): AndroidViewModel(application)
}
try {
val skus = activityPurchaseModel.querySkus(PurchaseIds.SAL_SKUS)
val skus = activityPurchaseModel.queryProducts(PurchaseIds.SAL_SKUS)
val purchases = activityPurchaseModel.queryPurchases()
statusInternal.value = ReadyStayAwesomeStatus(
PurchaseIds.SAL_SKUS.map { skuId ->
val sku = skus.find { it.sku == skuId }
val sku = skus.find { it.productId == skuId }
StayAwesomeItem(
id = skuId,
title = sku?.description ?: skuId,
price = sku?.price ?: "???",
bought = purchases.find { purchase -> purchase.skus.find { sku -> sku == skuId } != null } != null
price = sku?.oneTimePurchaseOfferDetails?.formattedPrice.toString(),
bought = purchases.find { purchase -> purchase.products.find { sku -> sku == skuId } != null } != null
)
}
)

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -28,20 +28,18 @@ object BillingClient {
fun endConnection() {}
fun querySkuDetails(param: SkuDetailsParams) = QuerySkuDetailsResult.instance
fun queryProductDetails(param: QueryProductDetailsParams) = QueryProductDetailsResult.instance
fun launchBillingFlow(activity: Activity, params: BillingFlowParams) = BillingResult
fun acknowledgePurchase(params: AcknowledgePurchaseParams) = BillingResult
fun consumePurchase(params: ConsumeParams) = BillingResult
suspend fun queryPurchasesAsync(type: String) = QueryPurchasesResult
suspend fun queryPurchasesAsync(request: QueryPurchasesParams) = QueryPurchasesResult
object BillingResponseCode {
const val OK = 0
const val ERR = 1
}
object SkuType {
const val INAPP = ""
}
enum class ProductType { INAPP }
object Builder {
fun enablePendingPurchases() = this
@ -55,26 +53,20 @@ object BillingResult {
const val debugMessage = "only mock linked"
}
object SkuDetails {
const val sku = ""
const val price = ""
object ProductDetails {
const val productId = ""
const val description = ""
}
val oneTimePurchaseOfferDetails: OfferDetails? = OfferDetails
object SkuDetailsParams {
fun newBuilder() = Builder
object Builder {
fun setSkusList(list: List<String>) = this
fun setType(type: String) = this
fun build() = SkuDetailsParams
object OfferDetails {
const val formattedPrice = ""
}
}
object Purchase {
const val purchaseState = PurchaseState.PURCHASED
const val isAcknowledged = true
val skus = listOf("")
val products = emptyList<String>()
const val purchaseToken = ""
const val originalJson = ""
const val signature = ""
@ -103,11 +95,14 @@ object ConsumeParams {
}
object BillingFlowParams {
fun newBuilder() = Builder
fun newBuilder() = this
fun setProductDetailsParamsList(details: List<ProductDetailsParams>) = this
fun build() = this
object Builder {
fun setSkuDetails(details: SkuDetails) = this
fun build() = BillingFlowParams
object ProductDetailsParams {
fun newBuilder() = this
fun setProductDetails(details: ProductDetails) = this
fun build() = this
}
}
@ -116,9 +111,9 @@ object QueryPurchasesResult {
val purchasesList: List<Purchase> = emptyList()
}
data class QuerySkuDetailsResult(val billingResult: BillingResult, val details: List<SkuDetails>?) {
data class QueryProductDetailsResult(val billingResult: BillingResult, val details: List<ProductDetails>?) {
companion object {
val instance = QuerySkuDetailsResult(BillingResult, emptyList())
val instance = QueryProductDetailsResult(BillingResult, emptyList())
}
}
@ -130,3 +125,22 @@ interface BillingClientStateListener {
interface PurchasesUpdatedListener {
fun onPurchasesUpdated(p0: BillingResult, p1: MutableList<Purchase>?)
}
object QueryProductDetailsParams {
fun newBuilder() = this
fun setProductList(list: List<Product>) = this
fun build() = this
object Product {
fun newBuilder() = this
fun setProductId(id: String) = this
fun setProductType(type: BillingClient.ProductType) = this
fun build() = this
}
}
object QueryPurchasesParams {
fun newBuilder() = this
fun setProductType(type: BillingClient.ProductType) = this
fun build() = this
}