인 앱 결제 추가
This commit is contained in:
parent
f0a8ca5823
commit
2101cdeb86
|
@ -40,8 +40,8 @@ android {
|
||||||
applicationId "kr.co.vividnext.sodalive"
|
applicationId "kr.co.vividnext.sodalive"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 41
|
versionCode 46
|
||||||
versionName "1.8.16"
|
versionName "1.8.21"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
@ -85,7 +85,9 @@
|
||||||
<activity android:name=".settings.terms.TermsActivity" />
|
<activity android:name=".settings.terms.TermsActivity" />
|
||||||
<activity android:name=".user.find_password.FindPasswordActivity" />
|
<activity android:name=".user.find_password.FindPasswordActivity" />
|
||||||
<activity android:name=".mypage.can.status.CanStatusActivity" />
|
<activity android:name=".mypage.can.status.CanStatusActivity" />
|
||||||
<activity android:name=".mypage.can.charge.CanChargeActivity" />
|
<activity
|
||||||
|
android:name=".mypage.can.charge.CanChargeActivity"
|
||||||
|
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||||
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
||||||
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
||||||
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
||||||
|
|
|
@ -41,7 +41,8 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
changeFragment(IAP_TAG_KEY)
|
supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupView() {
|
override fun setupView() {
|
||||||
|
@ -59,13 +60,18 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
val tabs = binding.tabs
|
val tabs = binding.tabs
|
||||||
|
|
||||||
tabs.visibility = View.VISIBLE
|
tabs.visibility = View.VISIBLE
|
||||||
tabs.addTab(tabs.newTab().setText("인 앱 결제").setTag(IAP_TAG_KEY))
|
tabs.addTab(tabs.newTab().setText("인 앱 결제"))
|
||||||
tabs.addTab(tabs.newTab().setText("PG").setTag(PG_TAG_KEY))
|
tabs.addTab(tabs.newTab().setText("PG"))
|
||||||
|
|
||||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||||
val tag = tab.tag as String
|
when (tab.position) {
|
||||||
changeFragment(tag)
|
0 -> supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||||
|
|
||||||
|
1 -> supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.fl_container, CanChargePgFragment()).commit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTabUnselected(tab: TabLayout.Tab) {
|
override fun onTabUnselected(tab: TabLayout.Tab) {
|
||||||
|
@ -79,33 +85,6 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeFragment(tag: String) {
|
|
||||||
val fragmentManager = supportFragmentManager
|
|
||||||
val fragmentTransaction = fragmentManager.beginTransaction()
|
|
||||||
|
|
||||||
val currentFragment = fragmentManager.primaryNavigationFragment
|
|
||||||
if (currentFragment != null) {
|
|
||||||
fragmentTransaction.hide(currentFragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
var fragment = fragmentManager.findFragmentByTag(tag)
|
|
||||||
if (fragment == null) {
|
|
||||||
fragment = if (tag == PG_TAG_KEY) {
|
|
||||||
CanChargePgFragment()
|
|
||||||
} else {
|
|
||||||
CanChargeIapFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
fragmentTransaction.add(R.id.fl_container, fragment, tag)
|
|
||||||
} else {
|
|
||||||
fragmentTransaction.show(fragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
fragmentTransaction.setPrimaryNavigationFragment(fragment)
|
|
||||||
fragmentTransaction.setReorderingAllowed(true)
|
|
||||||
fragmentTransaction.commitNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun selectCan(model: CanResponse) {
|
fun selectCan(model: CanResponse) {
|
||||||
val intent = Intent(applicationContext, CanPaymentActivity::class.java)
|
val intent = Intent(applicationContext, CanPaymentActivity::class.java)
|
||||||
intent.putExtra(Constants.EXTRA_CAN, model)
|
intent.putExtra(Constants.EXTRA_CAN, model)
|
||||||
|
@ -123,9 +102,4 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val IAP_TAG_KEY = "iap"
|
|
||||||
const val PG_TAG_KEY = "pg"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
@ -13,10 +14,12 @@ import com.android.billingclient.api.BillingClient
|
||||||
import com.android.billingclient.api.BillingClientStateListener
|
import com.android.billingclient.api.BillingClientStateListener
|
||||||
import com.android.billingclient.api.BillingFlowParams
|
import com.android.billingclient.api.BillingFlowParams
|
||||||
import com.android.billingclient.api.BillingResult
|
import com.android.billingclient.api.BillingResult
|
||||||
|
import com.android.billingclient.api.ConsumeParams
|
||||||
import com.android.billingclient.api.ProductDetails
|
import com.android.billingclient.api.ProductDetails
|
||||||
import com.android.billingclient.api.Purchase
|
import com.android.billingclient.api.Purchase
|
||||||
import com.android.billingclient.api.PurchasesUpdatedListener
|
import com.android.billingclient.api.PurchasesUpdatedListener
|
||||||
import com.android.billingclient.api.QueryProductDetailsParams
|
import com.android.billingclient.api.QueryProductDetailsParams
|
||||||
|
import com.android.billingclient.api.QueryPurchasesParams
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
@ -37,57 +40,10 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private var selectedProductDetails: ProductDetails? = null
|
private var selectedProductDetails: ProductDetails? = null
|
||||||
|
|
||||||
private val purchaseUpdateListener = PurchasesUpdatedListener { billingResult, purchases ->
|
private lateinit var purchaseUpdateListener: PurchasesUpdatedListener
|
||||||
if (
|
|
||||||
billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
|
|
||||||
purchases != null &&
|
|
||||||
selectedProductDetails != null
|
|
||||||
) {
|
|
||||||
for (purchase in purchases) {
|
|
||||||
handlePurchase(purchase)
|
|
||||||
}
|
|
||||||
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
|
|
||||||
selectedProductDetails = null
|
|
||||||
handler.post {
|
|
||||||
Toast.makeText(requireActivity(), "구매를 취소했습니다.", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selectedProductDetails = null
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
"구매를 하지 못했습니다.\n다시 시도해 주세요.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handlePurchase(purchase: Purchase) {
|
fun safeContext(): Context? {
|
||||||
if (
|
return if (isAdded) context else null
|
||||||
purchase.purchaseState == Purchase.PurchaseState.PURCHASED &&
|
|
||||||
!purchase.isAcknowledged
|
|
||||||
) {
|
|
||||||
viewModel.chargeCan(
|
|
||||||
title = selectedProductDetails!!.name,
|
|
||||||
selectedProductDetails = selectedProductDetails!!,
|
|
||||||
purchase = purchase
|
|
||||||
) { chargeCan ->
|
|
||||||
handler.post {
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
"캔이 충전되었습니다",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
SharedPreferenceManager.can += chargeCan
|
|
||||||
|
|
||||||
val activity = requireActivity() as? CanChargeActivity
|
|
||||||
if (activity != null) {
|
|
||||||
activity.successIapCharge()
|
|
||||||
} else {
|
|
||||||
requireActivity().finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -100,6 +56,31 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
setupBillingClient()
|
setupBillingClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
billingClient.startConnection(object : BillingClientStateListener {
|
||||||
|
override fun onBillingServiceDisconnected() {
|
||||||
|
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||||
|
viewModel.setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||||
|
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
|
queryAndConsumeUnconsumedPurchases()
|
||||||
|
} else {
|
||||||
|
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||||
|
viewModel.setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
billingClient.endConnection()
|
||||||
|
}
|
||||||
|
|
||||||
private fun bindData() {
|
private fun bindData() {
|
||||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
@ -162,39 +143,34 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBillingClient() {
|
private fun setupBillingClient() {
|
||||||
|
purchaseUpdateListener = PurchasesUpdatedListener { billingResult, purchases ->
|
||||||
|
handler.post {
|
||||||
|
if (
|
||||||
|
billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
|
||||||
|
purchases != null &&
|
||||||
|
selectedProductDetails != null
|
||||||
|
) {
|
||||||
|
for (purchase in purchases) {
|
||||||
|
handlePurchase(purchase)
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED
|
||||||
|
) {
|
||||||
|
selectedProductDetails = null
|
||||||
|
viewModel.showToast("구매를 취소했습니다.")
|
||||||
|
} else {
|
||||||
|
selectedProductDetails = null
|
||||||
|
viewModel.showToast("구매를 하지 못했습니다.\n다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
billingClient = BillingClient.newBuilder(requireActivity())
|
billingClient = BillingClient.newBuilder(requireActivity())
|
||||||
.enablePendingPurchases()
|
.enablePendingPurchases()
|
||||||
.setListener(purchaseUpdateListener)
|
.setListener(purchaseUpdateListener)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
loadingDialog.show(screenWidth)
|
loadingDialog.show(screenWidth)
|
||||||
billingClient.startConnection(object : BillingClientStateListener {
|
|
||||||
override fun onBillingServiceDisconnected() {
|
|
||||||
handler.post {
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
"인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
loadingDialog.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
||||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
||||||
queryAvailableCans()
|
|
||||||
} else {
|
|
||||||
handler.post {
|
|
||||||
Toast.makeText(
|
|
||||||
requireActivity(),
|
|
||||||
"인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
loadingDialog.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
@ -224,16 +200,70 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
handler.post { adapter.addItems(productDetailsList) }
|
handler.post { adapter.addItems(productDetailsList) }
|
||||||
} else {
|
} else {
|
||||||
handler.post {
|
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||||
Toast.makeText(
|
}
|
||||||
requireActivity(),
|
|
||||||
"인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.",
|
viewModel.setLoading(false)
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.post { loadingDialog.dismiss() }
|
private fun queryAndConsumeUnconsumedPurchases() {
|
||||||
|
val queryPurchaseParams = QueryPurchasesParams.newBuilder()
|
||||||
|
.setProductType(BillingClient.ProductType.INAPP)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
billingClient.queryPurchasesAsync(
|
||||||
|
queryPurchaseParams
|
||||||
|
) { result, purchaseList ->
|
||||||
|
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
|
if (purchaseList.isNotEmpty()) {
|
||||||
|
for (purchase in purchaseList) {
|
||||||
|
if (!purchase.isAcknowledged) {
|
||||||
|
consumePurchase(purchase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queryAvailableCans()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consumePurchase(purchase: Purchase) {
|
||||||
|
val params = ConsumeParams.newBuilder()
|
||||||
|
.setPurchaseToken(purchase.purchaseToken)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
billingClient.consumeAsync(params) { billingResult, _ ->
|
||||||
|
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
|
queryAvailableCans()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlePurchase(purchase: Purchase) {
|
||||||
|
if (
|
||||||
|
purchase.purchaseState == Purchase.PurchaseState.PURCHASED &&
|
||||||
|
!purchase.isAcknowledged
|
||||||
|
) {
|
||||||
|
viewModel.chargeCan(
|
||||||
|
title = selectedProductDetails!!.name,
|
||||||
|
selectedProductDetails = selectedProductDetails!!,
|
||||||
|
purchase = purchase
|
||||||
|
) { chargeCan ->
|
||||||
|
handler.post {
|
||||||
|
viewModel.showToast("캔이 충전되었습니다")
|
||||||
|
SharedPreferenceManager.can += chargeCan
|
||||||
|
|
||||||
|
if (activity != null) {
|
||||||
|
if (activity as? CanChargeActivity != null) {
|
||||||
|
(activity as CanChargeActivity).successIapCharge()
|
||||||
|
} else {
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,4 +71,12 @@ class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewMod
|
||||||
_toastLiveData.value = "구매를 하지 못했습니다.\n고객센터로 문의해 주시기 바랍니다."
|
_toastLiveData.value = "구매를 하지 못했습니다.\n고객센터로 문의해 주시기 바랍니다."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showToast(message: String) {
|
||||||
|
_toastLiveData.value = message
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setLoading(isLoading: Boolean) {
|
||||||
|
_isLoading.value = isLoading
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue