mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 17:59:51 +02:00
Update google play billing library
This commit is contained in:
parent
620af536ce
commit
aa06c8aaed
5 changed files with 80 additions and 51 deletions
|
@ -200,8 +200,7 @@ dependencies {
|
||||||
implementation 'com.squareup.okhttp3:okhttp-tls:4.9.3'
|
implementation 'com.squareup.okhttp3:okhttp-tls:4.9.3'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor: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:5.0.0"
|
||||||
googleApiImplementation "com.android.billingclient:billing-ktx:4.1.0"
|
|
||||||
|
|
||||||
implementation('io.socket:socket.io-client:2.0.0') {
|
implementation('io.socket:socket.io-client:2.0.0') {
|
||||||
exclude group: 'org.json', module: 'json'
|
exclude group: 'org.json', module: 'json'
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -123,11 +123,15 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun querySkus(skuIds: List<String>): List<SkuDetails> = initAndUseClient { client ->
|
suspend fun queryProducts(productIds: List<String>): List<ProductDetails> = initAndUseClient { client ->
|
||||||
val (billingResult, data) = client.querySkuDetails(
|
val (billingResult, data) = client.queryProductDetails(
|
||||||
SkuDetailsParams.newBuilder()
|
QueryProductDetailsParams.newBuilder()
|
||||||
.setSkusList(skuIds)
|
.setProductList(productIds.map { skuId ->
|
||||||
.setType(BillingClient.SkuType.INAPP)
|
QueryProductDetailsParams.Product.newBuilder()
|
||||||
|
.setProductId(skuId)
|
||||||
|
.setProductType(BillingClient.ProductType.INAPP)
|
||||||
|
.build()
|
||||||
|
})
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -137,7 +141,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun queryPurchases() = initAndUseClient { client ->
|
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()
|
response.billingResult.assertSuccess()
|
||||||
|
|
||||||
|
@ -153,7 +161,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
||||||
|
|
||||||
try {
|
try {
|
||||||
initAndUseClient { client ->
|
initAndUseClient { client ->
|
||||||
val result = client.queryPurchasesAsync(BillingClient.SkuType.INAPP)
|
val result = client.queryPurchasesAsync(
|
||||||
|
QueryPurchasesParams.newBuilder()
|
||||||
|
.setProductType(BillingClient.ProductType.INAPP)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
result.billingResult.assertSuccess()
|
result.billingResult.assertSuccess()
|
||||||
|
|
||||||
|
@ -223,7 +235,7 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
||||||
Log.d(LOG_TAG, "handlePurchase($purchase)")
|
Log.d(LOG_TAG, "handlePurchase($purchase)")
|
||||||
}
|
}
|
||||||
|
|
||||||
val sku = purchase.skus.single()
|
val sku = purchase.products.single()
|
||||||
|
|
||||||
if (PurchaseIds.SAL_SKUS.contains(sku)) {
|
if (PurchaseIds.SAL_SKUS.contains(sku)) {
|
||||||
// just acknowledge
|
// 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 {
|
runAsync {
|
||||||
try {
|
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) {
|
} catch (ex: Exception) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Log.d(LOG_TAG, "could not start purchase", ex)
|
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 {
|
runAsync {
|
||||||
initAndUseClient { client ->
|
initAndUseClient { client ->
|
||||||
try {
|
try {
|
||||||
|
@ -301,7 +313,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
||||||
client.launchBillingFlow(
|
client.launchBillingFlow(
|
||||||
activity,
|
activity,
|
||||||
BillingFlowParams.newBuilder()
|
BillingFlowParams.newBuilder()
|
||||||
.setSkuDetails(skuDetails)
|
.setProductDetailsParamsList(listOf(
|
||||||
|
BillingFlowParams.ProductDetailsParams.newBuilder()
|
||||||
|
.setProductDetails(productDetails)
|
||||||
|
.build()
|
||||||
|
))
|
||||||
.build()
|
.build()
|
||||||
).assertSuccess()
|
).assertSuccess()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
|
|
|
@ -62,11 +62,11 @@ class PurchaseModel(application: Application): AndroidViewModel(application) {
|
||||||
if (canDoPurchase.publicKey?.contentEquals(Base64.decode(BuildConfig.googlePlayKey, 0)) == false) {
|
if (canDoPurchase.publicKey?.contentEquals(Base64.decode(BuildConfig.googlePlayKey, 0)) == false) {
|
||||||
statusInternal.value = PurchaseFragmentServerHasDifferentPublicKey
|
statusInternal.value = PurchaseFragmentServerHasDifferentPublicKey
|
||||||
} else {
|
} else {
|
||||||
val skus = activityPurchaseModel.querySkus(PurchaseIds.BUY_SKUS)
|
val skus = activityPurchaseModel.queryProducts(PurchaseIds.BUY_SKUS)
|
||||||
|
|
||||||
statusInternal.value = PurchaseFragmentReady(
|
statusInternal.value = PurchaseFragmentReady(
|
||||||
monthPrice = skus.find { it.sku == PurchaseIds.SKU_MONTH }?.price.toString(),
|
monthPrice = skus.find { it.productId == PurchaseIds.SKU_MONTH }?.oneTimePurchaseOfferDetails?.formattedPrice.toString(),
|
||||||
yearPrice = skus.find { it.sku == PurchaseIds.SKU_YEAR }?.price.toString()
|
yearPrice = skus.find { it.productId == PurchaseIds.SKU_YEAR }?.oneTimePurchaseOfferDetails?.formattedPrice.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (canDoPurchase == CanDoPurchaseStatus.NotDueToOldPurchase) {
|
} else if (canDoPurchase == CanDoPurchaseStatus.NotDueToOldPurchase) {
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -37,18 +37,18 @@ class StayAwesomeModel(application: Application): AndroidViewModel(application)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val skus = activityPurchaseModel.querySkus(PurchaseIds.SAL_SKUS)
|
val skus = activityPurchaseModel.queryProducts(PurchaseIds.SAL_SKUS)
|
||||||
val purchases = activityPurchaseModel.queryPurchases()
|
val purchases = activityPurchaseModel.queryPurchases()
|
||||||
|
|
||||||
statusInternal.value = ReadyStayAwesomeStatus(
|
statusInternal.value = ReadyStayAwesomeStatus(
|
||||||
PurchaseIds.SAL_SKUS.map { skuId ->
|
PurchaseIds.SAL_SKUS.map { skuId ->
|
||||||
val sku = skus.find { it.sku == skuId }
|
val sku = skus.find { it.productId == skuId }
|
||||||
|
|
||||||
StayAwesomeItem(
|
StayAwesomeItem(
|
||||||
id = skuId,
|
id = skuId,
|
||||||
title = sku?.description ?: skuId,
|
title = sku?.description ?: skuId,
|
||||||
price = sku?.price ?: "???",
|
price = sku?.oneTimePurchaseOfferDetails?.formattedPrice.toString(),
|
||||||
bought = purchases.find { purchase -> purchase.skus.find { sku -> sku == skuId } != null } != null
|
bought = purchases.find { purchase -> purchase.products.find { sku -> sku == skuId } != null } != null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -28,20 +28,18 @@ object BillingClient {
|
||||||
|
|
||||||
fun endConnection() {}
|
fun endConnection() {}
|
||||||
|
|
||||||
fun querySkuDetails(param: SkuDetailsParams) = QuerySkuDetailsResult.instance
|
fun queryProductDetails(param: QueryProductDetailsParams) = QueryProductDetailsResult.instance
|
||||||
fun launchBillingFlow(activity: Activity, params: BillingFlowParams) = BillingResult
|
fun launchBillingFlow(activity: Activity, params: BillingFlowParams) = BillingResult
|
||||||
fun acknowledgePurchase(params: AcknowledgePurchaseParams) = BillingResult
|
fun acknowledgePurchase(params: AcknowledgePurchaseParams) = BillingResult
|
||||||
fun consumePurchase(params: ConsumeParams) = BillingResult
|
fun consumePurchase(params: ConsumeParams) = BillingResult
|
||||||
suspend fun queryPurchasesAsync(type: String) = QueryPurchasesResult
|
suspend fun queryPurchasesAsync(request: QueryPurchasesParams) = QueryPurchasesResult
|
||||||
|
|
||||||
object BillingResponseCode {
|
object BillingResponseCode {
|
||||||
const val OK = 0
|
const val OK = 0
|
||||||
const val ERR = 1
|
const val ERR = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
object SkuType {
|
enum class ProductType { INAPP }
|
||||||
const val INAPP = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
object Builder {
|
object Builder {
|
||||||
fun enablePendingPurchases() = this
|
fun enablePendingPurchases() = this
|
||||||
|
@ -55,26 +53,20 @@ object BillingResult {
|
||||||
const val debugMessage = "only mock linked"
|
const val debugMessage = "only mock linked"
|
||||||
}
|
}
|
||||||
|
|
||||||
object SkuDetails {
|
object ProductDetails {
|
||||||
const val sku = ""
|
const val productId = ""
|
||||||
const val price = ""
|
|
||||||
const val description = ""
|
const val description = ""
|
||||||
}
|
val oneTimePurchaseOfferDetails: OfferDetails? = OfferDetails
|
||||||
|
|
||||||
object SkuDetailsParams {
|
object OfferDetails {
|
||||||
fun newBuilder() = Builder
|
const val formattedPrice = ""
|
||||||
|
|
||||||
object Builder {
|
|
||||||
fun setSkusList(list: List<String>) = this
|
|
||||||
fun setType(type: String) = this
|
|
||||||
fun build() = SkuDetailsParams
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Purchase {
|
object Purchase {
|
||||||
const val purchaseState = PurchaseState.PURCHASED
|
const val purchaseState = PurchaseState.PURCHASED
|
||||||
const val isAcknowledged = true
|
const val isAcknowledged = true
|
||||||
val skus = listOf("")
|
val products = emptyList<String>()
|
||||||
const val purchaseToken = ""
|
const val purchaseToken = ""
|
||||||
const val originalJson = ""
|
const val originalJson = ""
|
||||||
const val signature = ""
|
const val signature = ""
|
||||||
|
@ -103,11 +95,14 @@ object ConsumeParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
object BillingFlowParams {
|
object BillingFlowParams {
|
||||||
fun newBuilder() = Builder
|
fun newBuilder() = this
|
||||||
|
fun setProductDetailsParamsList(details: List<ProductDetailsParams>) = this
|
||||||
|
fun build() = this
|
||||||
|
|
||||||
object Builder {
|
object ProductDetailsParams {
|
||||||
fun setSkuDetails(details: SkuDetails) = this
|
fun newBuilder() = this
|
||||||
fun build() = BillingFlowParams
|
fun setProductDetails(details: ProductDetails) = this
|
||||||
|
fun build() = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,9 +111,9 @@ object QueryPurchasesResult {
|
||||||
val purchasesList: List<Purchase> = emptyList()
|
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 {
|
companion object {
|
||||||
val instance = QuerySkuDetailsResult(BillingResult, emptyList())
|
val instance = QueryProductDetailsResult(BillingResult, emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,3 +125,22 @@ interface BillingClientStateListener {
|
||||||
interface PurchasesUpdatedListener {
|
interface PurchasesUpdatedListener {
|
||||||
fun onPurchasesUpdated(p0: BillingResult, p1: MutableList<Purchase>?)
|
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
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue