onBillingSetupFinished 从未调用过
onBillingSetupFinished never called
我一直与 Java 合作,但这次我尝试在 Kotlin 中开发,我有一个应用程序,该应用程序将有一个付费按钮来删除广告(使用 Google Play 的计费系统),但我无法让它工作。
我已经将签名的 apk 上传到 Play 管理中心并创建了 ID 为 remove_ads
的产品
这是我在 AndroidManifest.xml 文件 "android.permission.INTERNET"
和 "com.android.vending.BILLING"
中的内容
在build.gradle中:
implementation("com.android.billingclient:billing:4.0.0") implementation("com.android.billingclient:billing-ktx:4.0.0")
在我的 Kotlin Class“设置”中:
创建时:
btnRemoveAds.setOnClickListener {
Toast.makeText(this@Settings, "Click Button", Toast.LENGTH_SHORT).show()
billingClient = BillingClient.newBuilder(this)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
Toast.makeText(this@Settings, "SetupFinished", Toast.LENGTH_SHORT).show()
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
Toast.makeText(this@Settings, "OK", Toast.LENGTH_SHORT).show()
// The BillingClient is ready. You can query purchases here.
billingClient.queryPurchasesAsync(
SkuType.INAPP
) { billingResult, list ->
if (list.size != 0){
if (list.get(0).purchaseState == Purchase.PurchaseState.PURCHASED){
setPlus(true)
setResult(RESULT_OK)
} else{
queryAvaliableProducts()
}
} else{
queryAvaliableProducts()
}
}
} else{
Toast.makeText(this@Settings, "NO", Toast.LENGTH_SHORT).show()
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(this@Settings, "Disconnected", Toast.LENGTH_SHORT).show()
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
按下按钮时我唯一能看到的 Toast 是“单击按钮”
这些是我的方法:
private fun queryAvaliableProducts() {
val skuList: MutableList<String> = ArrayList()
skuList.add("remove_ads")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(INAPP)
billingClient.querySkuDetailsAsync(
params.build()
) { billingResult, skuDetailsList -> // Process the result.
if (skuDetailsList!!.size != 0) {
val billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
val responseCode = billingClient.launchBillingFlow(
this@Settings,
billingFlowParams
).responseCode
}
}
}
private val purchasesUpdatedListener =
PurchasesUpdatedListener { billingResult, purchases ->
// To be implemented in a later section.
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK
&& purchases != null
) {
for (purchase in purchases) {
handlePurchase(purchase)
}
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
fun handlePurchase(purchase: Purchase) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(
acknowledgePurchaseParams,
acknowledgePurchaseResponseListener
)
}
}
}
var acknowledgePurchaseResponseListener =
AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
setPlus(true)
setResult(RESULT_OK)
finish()
}
}
我还在billingClient.startConnection
之后实现了一个按钮来检查连接状态
btnConnectionState.setOnClickListener {
Toast.makeText(this@Settings, billingClient.connectionState.toString(), Toast.LENGTH_SHORT).show()
}
结果我得到 2(已连接),所以我觉得 onBillingSetupFinished 和 onBillingServiceDisconnected 从未执行过,这对我来说似乎很奇怪,我的代码中是否有任何错误?
除了 Toast 本身,您的代码 afaik 中没有任何错误。 onBillingServiceDisconnected
未在主线程上调用。如果你像这样尝试抓住它:
try {
Toast.makeText(this@Settings, "NO", Toast.LENGTH_SHORT).show()
} catch (ex: Exception) {
Log.e("MyApp", "Error", ex)
}
它会打印这样的错误
06-05 00:00:38.713 8595 9215 E MyApp :
java.lang.NullPointerException: Can't toast on a thread that has not
called Looper.prepare()
您还可以打印调用回调的线程:
Log.e("MyApp", "Running on ${Thread.currentThread().name}")
它会告诉你
Running on PlayBillingLibrary-1
所以切换回Toast的主线程(有方法)或者使用简单的Log语句来验证调用了方法。
我一直与 Java 合作,但这次我尝试在 Kotlin 中开发,我有一个应用程序,该应用程序将有一个付费按钮来删除广告(使用 Google Play 的计费系统),但我无法让它工作。
我已经将签名的 apk 上传到 Play 管理中心并创建了 ID 为 remove_ads
的产品这是我在 AndroidManifest.xml 文件
中的内容"android.permission.INTERNET"
和"com.android.vending.BILLING"
在build.gradle中:
implementation("com.android.billingclient:billing:4.0.0") implementation("com.android.billingclient:billing-ktx:4.0.0")
在我的 Kotlin Class“设置”中:
创建时:
btnRemoveAds.setOnClickListener {
Toast.makeText(this@Settings, "Click Button", Toast.LENGTH_SHORT).show()
billingClient = BillingClient.newBuilder(this)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
Toast.makeText(this@Settings, "SetupFinished", Toast.LENGTH_SHORT).show()
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
Toast.makeText(this@Settings, "OK", Toast.LENGTH_SHORT).show()
// The BillingClient is ready. You can query purchases here.
billingClient.queryPurchasesAsync(
SkuType.INAPP
) { billingResult, list ->
if (list.size != 0){
if (list.get(0).purchaseState == Purchase.PurchaseState.PURCHASED){
setPlus(true)
setResult(RESULT_OK)
} else{
queryAvaliableProducts()
}
} else{
queryAvaliableProducts()
}
}
} else{
Toast.makeText(this@Settings, "NO", Toast.LENGTH_SHORT).show()
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(this@Settings, "Disconnected", Toast.LENGTH_SHORT).show()
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
按下按钮时我唯一能看到的 Toast 是“单击按钮”
这些是我的方法:
private fun queryAvaliableProducts() {
val skuList: MutableList<String> = ArrayList()
skuList.add("remove_ads")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(INAPP)
billingClient.querySkuDetailsAsync(
params.build()
) { billingResult, skuDetailsList -> // Process the result.
if (skuDetailsList!!.size != 0) {
val billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
val responseCode = billingClient.launchBillingFlow(
this@Settings,
billingFlowParams
).responseCode
}
}
}
private val purchasesUpdatedListener =
PurchasesUpdatedListener { billingResult, purchases ->
// To be implemented in a later section.
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK
&& purchases != null
) {
for (purchase in purchases) {
handlePurchase(purchase)
}
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
fun handlePurchase(purchase: Purchase) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(
acknowledgePurchaseParams,
acknowledgePurchaseResponseListener
)
}
}
}
var acknowledgePurchaseResponseListener =
AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
setPlus(true)
setResult(RESULT_OK)
finish()
}
}
我还在billingClient.startConnection
之后实现了一个按钮来检查连接状态btnConnectionState.setOnClickListener {
Toast.makeText(this@Settings, billingClient.connectionState.toString(), Toast.LENGTH_SHORT).show()
}
结果我得到 2(已连接),所以我觉得 onBillingSetupFinished 和 onBillingServiceDisconnected 从未执行过,这对我来说似乎很奇怪,我的代码中是否有任何错误?
除了 Toast 本身,您的代码 afaik 中没有任何错误。 onBillingServiceDisconnected
未在主线程上调用。如果你像这样尝试抓住它:
try {
Toast.makeText(this@Settings, "NO", Toast.LENGTH_SHORT).show()
} catch (ex: Exception) {
Log.e("MyApp", "Error", ex)
}
它会打印这样的错误
06-05 00:00:38.713 8595 9215 E MyApp : java.lang.NullPointerException: Can't toast on a thread that has not called Looper.prepare()
您还可以打印调用回调的线程:
Log.e("MyApp", "Running on ${Thread.currentThread().name}")
它会告诉你
Running on PlayBillingLibrary-1
所以切换回Toast的主线程(有方法)或者使用简单的Log语句来验证调用了方法。