Skip to content

Commit

Permalink
Billing (Dynamic Pricing)
Browse files Browse the repository at this point in the history
  • Loading branch information
epegasus committed Jun 13, 2023
1 parent 1a10aad commit 8acd876
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 14 deletions.
10 changes: 4 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ android {
targetSdk 33
versionCode 6
versionName "1.1.6"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
Expand All @@ -34,12 +32,12 @@ android {

dependencies {

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

// Billing Library
// implementation 'com.github.hypersoftdev:inappbilling:1.1.6'
//implementation 'com.github.hypersoftdev:inappbilling:1.1.6'
implementation project(path: ':billing')
}
41 changes: 40 additions & 1 deletion app/src/main/java/com/hypersoft/inappbilling/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.hypersoft.billing.BillingManager
import com.hypersoft.billing.constants.SubscriptionPlans
import com.hypersoft.billing.constants.SubscriptionProductIds
import com.hypersoft.billing.dataClasses.ProductDetail
import com.hypersoft.billing.helper.BillingHelper.Companion.TAG
import com.hypersoft.billing.interfaces.OnPurchaseListener
import com.hypersoft.billing.status.State
import com.hypersoft.billing.constants.SubscriptionPlans
import dev.epegasus.billinginapppurchases.interfaces.OnConnectionListener

class MainActivity : AppCompatActivity() {
Expand Down Expand Up @@ -38,6 +41,42 @@ class MainActivity : AppCompatActivity() {
Log.d("BillingManager", "initObserver: $it")
tvTitle.text = it.toString()
}

//Observe Your Products
billingManager.productDetailsLiveData.observe(this) { list ->
var month = 0L
var year = 0L
list.forEach { productDetail: ProductDetail ->
Log.d(TAG, "initObservers: $productDetail")
when (productDetail.productId) {
SubscriptionProductIds.basicProductMonthly -> {
//binding.mtvOfferPrice1.text = productDetail.price
month = productDetail.priceAmountMicros / 1000000
}

SubscriptionProductIds.basicProductYearly -> {
//binding.mtvOfferPrice2.text = productDetail.price
year = productDetail.priceAmountMicros / 1000000
}

SubscriptionProductIds.basicProductSemiYearly -> {
//binding.mtvOfferPrice3Premium.text = productDetail.price
}

productId -> {
//binding.mtvOfferPrice3Premium.text = productDetail.price
}
}
}
// Best Offer
if (month == 0L || year == 0L) return@observe
val result = 100 - (year * 100 / (12 * month))
val text = "Save $result%"
//binding.mtvBestOffer.text = text

val perMonth = (year / 12L).toString()
//binding.mtvOffer.text = perMonth
}
}

private fun initBilling() {
Expand Down
8 changes: 4 additions & 4 deletions billing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ android {

dependencies {

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'

// Google Play Billing
implementation "com.android.billingclient:billing-ktx:5.2.0"
implementation "com.android.billingclient:billing-ktx:6.0.0"

// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
}
6 changes: 4 additions & 2 deletions billing/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-renamesourcefileattribute SourceFile

-keep class com.hypersoft.billing.dataClasses.**
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.hypersoft.billing.dataClasses

import com.hypersoft.billing.enums.ProductType

/**
* @Author: SOHAIB AHMED
* @Date: 13,June,2023
* @Accounts
* -> https://github.com/epegasus
* -> https://stackoverflow.com/users/20440272/sohaib-ahmed
*/
/**
* @property productId: Unique ID (Console's ID
* @property price: e.g. Rs 750.00
* @property currencyCode: e.g. USD, PKR, etc
* @property freeTrialPeriod: e.g. 3, 5, 7
* @property priceAmountMicros: e.g. 750000000
* @property freeTrial: isAvailable or not
*/

data class ProductDetail(
var productId: String,
var price: String,
var currencyCode: String,
var freeTrialPeriod: Int,
var priceAmountMicros: Long = 0,
var freeTrial: Boolean = false,
var productType: ProductType = ProductType.SUBS
) {
constructor() : this(productId = "", price = "", currencyCode = "", 0, 0, false)
}
14 changes: 14 additions & 0 deletions billing/src/main/java/com/hypersoft/billing/enums/ProductType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.hypersoft.billing.enums

/**
* @Author: SOHAIB AHMED
* @Date: 13,June,2023
* @Accounts
* -> https://github.com/epegasus
* -> https://stackoverflow.com/users/20440272/sohaib-ahmed
*/

enum class ProductType {
INAPP,
SUBS
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import android.net.NetworkCapabilities
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.billingclient.api.AcknowledgePurchaseParams
import com.android.billingclient.api.AcknowledgePurchaseResponseListener
import com.android.billingclient.api.BillingClient
Expand All @@ -21,6 +23,8 @@ import com.android.billingclient.api.QueryPurchasesParams
import com.android.billingclient.api.queryProductDetails
import com.hypersoft.billing.constants.SubscriptionPlans
import com.hypersoft.billing.constants.SubscriptionProductIds
import com.hypersoft.billing.dataClasses.ProductDetail
import com.hypersoft.billing.enums.ProductType
import com.hypersoft.billing.dataProvider.DataProviderInApp
import com.hypersoft.billing.dataProvider.DataProviderSub
import com.hypersoft.billing.enums.BillingState
Expand All @@ -47,6 +51,12 @@ abstract class BillingHelper(private val context: Context) {
@JvmField
protected var checkForSubscription = false

private val _productDetailList = ArrayList<ProductDetail>()
private val productDetailList: List<ProductDetail> get() = _productDetailList.toList()

private val _productDetailsLiveData = MutableLiveData<List<ProductDetail>>()
val productDetailsLiveData: LiveData<List<ProductDetail>> = _productDetailsLiveData

/* ------------------------------------------------ Initializations ------------------------------------------------ */

private val billingClient by lazy {
Expand Down Expand Up @@ -181,6 +191,17 @@ abstract class BillingHelper(private val context: Context) {
if (productDetailsResult.productDetailsList.isNullOrEmpty()) {
setBillingState(BillingState.CONSOLE_PRODUCTS_IN_APP_NOT_EXIST)
} else {
productDetailsResult.productDetailsList?.forEach {
val item = ProductDetail()
item.productId = it.productId
item.price = it.oneTimePurchaseOfferDetails?.formattedPrice.toString().removeSuffix(".00")
item.currencyCode = it.oneTimePurchaseOfferDetails?.priceCurrencyCode.toString()
item.productType = ProductType.INAPP
item.priceAmountMicros = it.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0L

_productDetailList.add(item)
_productDetailsLiveData.postValue(productDetailList)
}
dataProviderInApp.setProductDetailsList(productDetailsResult.productDetailsList!!)
setBillingState(BillingState.CONSOLE_PRODUCTS_IN_APP_AVAILABLE)
}
Expand All @@ -200,7 +221,33 @@ abstract class BillingHelper(private val context: Context) {
if (productDetailsResult.productDetailsList.isNullOrEmpty()) {
setBillingState(BillingState.CONSOLE_PRODUCTS_SUB_NOT_EXIST)
} else {
Log.d(TAG, "queryForAvailableSubProducts: ${productDetailsResult.productDetailsList}")
productDetailsResult.productDetailsList?.forEach { productDetails ->
if (!productDetails.subscriptionOfferDetails.isNullOrEmpty()) {
val purchaseList = productDetails.subscriptionOfferDetails!![0].pricingPhases.pricingPhaseList

val item = ProductDetail()
item.productId = productDetails.productId

purchaseList.forEach { temp ->
if (temp.priceAmountMicros == 0L) {
item.freeTrial = true
item.freeTrialPeriod = when (temp.billingPeriod) {
"P3D" -> 3
"P5D" -> 5
"P7D" -> 7
"P1M" -> 30
else -> 1
}
} else {
item.currencyCode = temp.priceCurrencyCode
item.price = temp.formattedPrice.removeSuffix(".00")
item.priceAmountMicros = temp.priceAmountMicros
}
}
_productDetailList.add(item)
}
}
_productDetailsLiveData.postValue(productDetailList)
dataProviderSub.setProductDetailsList(productDetailsResult.productDetailsList!!)
setBillingState(BillingState.CONSOLE_PRODUCTS_SUB_AVAILABLE)
}
Expand Down

0 comments on commit 8acd876

Please sign in to comment.