From 8cc26f47b18bbc1944404d3378b885742a1d7586 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 2 Jul 2017 11:57:57 -0700 Subject: Remap billing functionality --- .../kotlin/com/pitchedapps/frost/utils/iab/IAB.kt | 114 +++++++++++++++------ 1 file changed, 80 insertions(+), 34 deletions(-) (limited to 'app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt index e047e2ff..b9213ae7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt @@ -2,6 +2,7 @@ package com.pitchedapps.frost.utils.iab import android.app.Activity import android.content.Context +import android.content.Intent import ca.allanwang.kau.utils.isFromGooglePlay import com.crashlytics.android.answers.PurchaseEvent import com.pitchedapps.frost.BuildConfig @@ -9,39 +10,63 @@ import com.pitchedapps.frost.SettingsActivity import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.frostAnswers -import com.pitchedapps.frost.utils.frostAnswersCustom /** * Created by Allan Wang on 2017-06-23. */ object IAB { - var helper: IabHelper? = null + private var helper: IabHelper? = null - fun setupAsync(activity: Activity) { - if (helper == null) { - L.d("IAB setup async") - if (!activity.isFromGooglePlay && !BuildConfig.DEBUG) return L.d("IAB not from google play") - try { - helper = IabHelper(activity.applicationContext, PUBLIC_BILLING_KEY) - helper!!.enableDebugLogging(BuildConfig.DEBUG, "Frost:") - helper!!.startSetup { - result -> - L.d("IAB result ${result.message}") - if (!result.isSuccess) L.eThrow("IAB Setup error: $result") + /** + * Wrapper function to ensure that the helper exists before executing a command + * + * [mustHavePlayStore] decides if dialogs should be shown if play store errors occur + * + * [onStart] should return true if we wish to dispose the helper after the operation + * and false otherwise + * + */ + operator fun invoke(activity: Activity, mustHavePlayStore: Boolean = true, onStart: (helper: IabHelper) -> Boolean) { + with(activity) { + if (helper?.mDisposed ?: true) { + helper = null + L.d("IAB setup async") + if (!isFrostPlay) { + if (mustHavePlayStore) playStoreNotFound() + return } - } catch (e: Exception) { - L.e(e, "IAB error") - activity.playStoreNoLongerPro() - } + try { + helper = IabHelper(applicationContext, PUBLIC_BILLING_KEY) + helper!!.enableDebugLogging(BuildConfig.DEBUG, "Frost:") + helper!!.startSetup { + result -> + if (result.isSuccess) { + if (onStart(helper!!)) + helper!!.disposeWhenFinished() + } else if (mustHavePlayStore) + activity.playStoreGenericError("Setup error: ${result.response} ${result.message}") + } + } catch (e: Exception) { + L.e(e, "IAB error") + if (mustHavePlayStore) + playStoreGenericError(null) + } + } else if (onStart(helper!!)) + helper!!.disposeWhenFinished() } } + fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean + = helper?.handleActivityResult(requestCode, resultCode, data) ?: false + + /** - * If user has pro, check if it's valid and destroy the helper + * Call this after any execution to dispose the helper */ - fun validatePro(activity: Activity) { - + fun dispose() { + helper?.disposeWhenFinished() + helper = null } } @@ -54,29 +79,51 @@ private val Context.isFrostPlay: Boolean get() = isFromGooglePlay || BuildConfig.DEBUG fun SettingsActivity.restorePurchases() { + validatePro(this) +} +/** + * If user has pro, check if it's valid and destroy the helper + */ +fun Activity.validatePro(activity: Activity) { + IAB(activity, Prefs.previouslyPro) { //if pro, ensure that it is in inventory; if not, check quietly if it exists + helper -> + with(activity) { + helper.queryInventoryAsync { + res, inv -> + if (res.isFailure) return@queryInventoryAsync playStoreGenericError("Query res error") + if (inv?.getSkuDetails(FROST_PRO) != null) { + //owns pro + if (!Prefs.previouslyPro) + playStoreFoundPro() + } else if (Prefs.previouslyPro) { + //doesn't own pro but has it + playStoreNoLongerPro() + } + } + } + true + } } -fun Activity.openPlayProPurchase(code: Int) = openPlayPurchase(FROST_PRO, code) { - Prefs.previouslyPro = true +fun Activity.openPlayProPurchase(code: Int) { + if (!IS_FROST_PRO) + playStoreProNotAvailable() + else openPlayPurchase(FROST_PRO, code) { + Prefs.previouslyPro = true + } } fun Activity.openPlayPurchase(key: String, code: Int, onSuccess: (key: String) -> Unit) { L.d("Open play purchase $key $code") - if (!isFrostPlay) return playStoreNotFound() - frostAnswersCustom("PLAY_PURCHASE") { - putCustomAttribute("Key", key) - } - L.d("IAB flag end async") - IAB.helper?.flagEndAsync() ?: return playStoreGenericError("Null flag end async") - L.d("IAB query inv async") - try { - IAB.helper!!.queryInventoryAsync { + IAB(this, true) { + helper -> + helper.queryInventoryAsync { res, inv -> if (res.isFailure) return@queryInventoryAsync playStoreGenericError("Query res error") if (inv?.getSkuDetails(key) != null) return@queryInventoryAsync playStoreAlreadyPurchased(key) L.d("IAB: inventory ${inv.allOwnedSkus}") - IAB.helper!!.launchPurchaseFlow(this@openPlayPurchase, key, code) { + helper.launchPurchaseFlow(this@openPlayPurchase, key, code) { result, _ -> if (result.isSuccess) { onSuccess(key) @@ -90,7 +137,6 @@ fun Activity.openPlayPurchase(key: String, code: Int, onSuccess: (key: String) - } } } - } catch(e: IabHelper.IabAsyncInProgressException) { - L.e(e, "IAB query dup") + false } } \ No newline at end of file -- cgit v1.2.3