I've moved from an old gradle of billing api, to the most recent to date, and now I've tried adding
BillingClient.Builder enablePendingPurchases = BillingClient.newBuilder(this).setListener(this);
but I can not get it to work, here's the error
Caused by: java.lang.IllegalArgumentException: Support for pending purchases must be enabled. Enable this by calling 'enablePendingPurchases()' on BillingClientBuilder.
at com.android.billingclient.api.BillingClient$Builder.build(BillingClient.java:309)
at com.aplicacion.vivaluganoapp.ar.ponerDineroActivity.setupBillingClient(ponerDineroActivity.java:144)
at com.aplicacion.vivaluganoapp.ar.ponerDineroActivity.onCreate(ponerDineroActivity.java:125)
complete code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_poner_dinero);
recyclerProduct.setHasFixedSize(true);
recyclerProduct.setLayoutManager(new LinearLayoutManager(this));
BillingClient.Builder enablePendingPurchases = BillingClient.newBuilder(this).setListener(this);
enablePendingPurchases.build();
setupBillingClient();
}
private void setupBillingClient() {
billingClient = BillingClient.newBuilder (this).setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(BillingResult responseCode) {
int maca = BillingClient.BillingResponseCode.OK;
String maca2 = String.valueOf(maca);
String maca3 = String.valueOf(responseCode);
if (maca3 == maca2)
{
Toast.makeText(ponerDineroActivity.this, "WORKS", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(ponerDineroActivity.this, "ERROR", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onBillingServiceDisconnected() {
Toast.makeText(ponerDineroActivity.this, "Disconnected from Billing", Toast.LENGTH_SHORT).show();
}
});
}
if I place only:
BillingClient.Builder enablePendingPurchases = BillingClient.newBuilder(this);
the error is:
Caused by: java.lang.IllegalArgumentException: Please provide a valid listener for purchases updates.
any help? i'm tired of trying
From the first stacktrace in your question
Enable this by calling 'enablePendingPurchases()'
we can find documentation for method enablePendingPurchases()
This method is required to be called to acknowledge your application
has been updated to support purchases that are pending. Pending
purchases are not automatically enabled since your application will
require updates to ensure entitlement is not granted before payment
has been secured. For more information on how to handle pending
transactions see
https://developer.android.com/google/play/billing/billing_library_overview
If this method is not called, BillingClient instance creation fails.
Your line of code should be:-
enablePendingPurchases = BillingClient.newBuilder(this)
.enablePendingPurchases()
.setListener(this);
Instead of :-
enablePendingPurchases = BillingClient.newBuilder(this).setListener(this);
This worked for me.
Just add enablePendingPurchases() like below:
billingClient = BillingClient.newBuilder(this)
.setListener(this)
.enablePendingPurchases()
.build();
BillingClient billingClient =
BillingClient.newBuilder(context!!)
.enablePendingPurchases()
.setListener(this)
build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode==BillingClient.BillingResponseCode.OK) {
skuList = HashMap()
skuList.put(BillingClient.SkuType.SUBS, listOf(getString(R.string.subscription_monthly),getString(R.string.subscription_yearly)))
querySkuDetailsAsync(BillingClient.SkuType.SUBS,skuList.get(BillingClient.SkuType.SUBS),object :SkuDetailsResponseListener{
override fun onSkuDetailsResponse(billingResult: BillingResult?, skuDetailsList: MutableList<SkuDetails>?) {
DebugLog.e("DATAAA "+skuDetailsList?.size+"")
}
})
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
Related
I am trying to add a subscription to my app. I have created a subscription called "pro_subscription" in the Google Play Console and made sure it's enabled. I then created a new Alpha build and released it to myself, with an account I have configured for testing.
We added com.android.vending.BILLING to the permissions and already had the internet permission.
No matter what we've tried, when we try to fetch the subscription in order to purchase it, no results are found.
We have tried to fetch using Android APIs directly, in which mutableList?.isEmpty() is true:
fun querySkuDetails() {
val purchasesUpdatedListener =
PurchasesUpdatedListener { billingResult, purchases ->
// To be implemented in a later section.
}
var billingClient = BillingClient.newBuilder(activity as MainActivity)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
val skuList = ArrayList<String>()
skuList.add("subscription")
skuList.add("pro_subscription")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
billingClient.querySkuDetailsAsync(params.build(), SkuDetailsResponseListener() { billingResult: BillingResult, mutableList: MutableList<SkuDetails>? ->
if (mutableList?.isEmpty()!!) {
Log.d("OFFERS: ", "mutableList is empty")
return#SkuDetailsResponseListener
}
})
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
And we also tried using the third-party revenuecat by configuring an offering and then fetching it, in which offerings.all.isEmpty() is true:
Purchases.sharedInstance.getOfferingsWith(
onError = { error ->
/* Optional error handling */
throw IllegalArgumentException()
},
onSuccess = { offerings ->
if (offerings.current == null) {
Log.d("OFFERS: ", "offerings.current is null")
}
if (offerings.all.isEmpty()) {
Log.d("OFFERS: ", "offerings.all.size is 0")
}
// Display current offering with offerings.current
Purchases.sharedInstance.purchasePackageWith(
activity as MainActivity,
offerings.current?.getPackage("pro")!!,
onError = { error, userCancelled -> /* No purchase */
if (userCancelled) {
val requestCancelledToast = Toast.makeText(
context,
R.string.purchase_request_cancelled_toast,
Toast.LENGTH_LONG
)
requestCancelledToast.show()
} else {
throw IllegalArgumentException()
}
},
onSuccess = { product, purchaserInfo ->
if (purchaserInfo.entitlements["pro"]?.isActive == true) {
// Unlock that great "pro" content
try {
val adView =
container!!.findViewById<AdView>(R.id.adView)
(adView.parent as ViewGroup).removeView(
adView
)
} catch (e: Exception) {
val errorRemoveToast = Toast.makeText(
context,
R.string.error_remove_ad,
Toast.LENGTH_LONG
)
errorRemoveToast.show()
}
}
})
})
In both cases, no error is printed, caught, or otherwise identified.
Anyone know why we are not able to fetch the purchases based on the above steps? Thanks!
Did you add Library of billing on the app's gradle?
It is;
dependencies {
val billing_version = "4.0.0"
implementation("com.android.billingclient:billing-ktx:$billing_version")
}
It does not work. As simple as that. I used default code given in google docs.
private fun initBilling() {
val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchase ->
Log.d("Billing", billingResult.debugMessage)
}
val billingClient = BillingClient.newBuilder(this#Home)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
Log.d("Billing", billingResult.debugMessage
?: "billing setup finished with response code ${billingResult.responseCode}")
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
CoroutineScope(Dispatchers.IO).launch {
querySkuDetails(billingClient)
}
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Log.d("Billing", "disconnected")
}
})
}
None of the Logs that I used were printed and no errors were showing. Start connection just does not trigger any methods from BillingClientStateListener.
There is an unknown issue with android billing library v3.0.0. Just switching to 2.1.0 helped.
I am trying to use the billing library and I am getting info from the official Android Developer site here. But I am finding a lot of trouble. Mainly compiling problems. It looks like that documentation is not completed. When I started following step by step I had to search for a lot of extra information. Now I am stuck trying to do querySkuDetailsAsync()
This is my code:
billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
List<String> skuList = new ArrayList<> ();
skuList.add("sp_hide_ads_year_01");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
//*** I want to Continue here ***
}
});
}
}
#Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
The compiler (Android Studio) says:
'onSkuDetailsResponse(BillingResult, List)' in 'Anonymous
class derived from
com.android.billingclient.api.SkuDetailsResponseListener' clashes with
'onSkuDetailsResponse(BillingResult, List)' in
'com.android.billingclient.api.SkuDetailsResponseListener'; both
methods have erasure, yet neither overrides the other
I have no idea what this means. any help here?
By the way, I use
implementation 'com.android.billingclient:billing:2.1.0'
I changed the line:
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList)
for this one, and everything compiled:
public void onSkuDetailsResponse(BillingResult billingResult, List<com.android.billingclient.api.SkuDetails> skuDetailsList)
I think to have followed all the steps correctly from the documentation but I can't reach the callback of querySkuDetailsAsync, no errors reported. The app is working correctly with IAB, now I'm only migrating from old library to the new 'com.android.billingclient:billing:2.0.3' but many problems.
Another question, in the new library is also necessary the use of License Key from Play Console? I don't find documentation about using that in the new library.
I can correctly and without errors reach this line billingClient.querySkuDetailsAsync(params, (billingResult2, skuDetailsList) ->
Sku ids are correctly
private void setupIab()
{
billingClient = BillingClient.newBuilder(getApplicationContext()).enablePendingPurchases().setListener(this).build();
billingClient.startConnection(new BillingClientStateListener()
{
#Override
public void onBillingSetupFinished(BillingResult billingResult)
{
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
{
List<String> skuList = new ArrayList<> ();
skuList.add("test_sku_1");
SkuDetailsParams params = SkuDetailsParams.newBuilder().setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
billingClient.querySkuDetailsAsync(params, (billingResult2, skuDetailsList) ->
{
// Process the result.
if (billingResult2.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null)
{
}
});
}
}
#Override
public void onBillingServiceDisconnected()
{
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
}
Best regards
The code seems correct form me and is similar to what I use, but I do not call querySkuDetailsAsync within onBillingSetupFinished, I call it only when the user buy something.
Maybe when onBillingSetupFinished runs, the setup is not really finished yet, you could try using this, so it will be called just later:
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
new Handler().post(() -> {
List<String> skuList = new ArrayList<>();
skuList.add("test_sku_1");
SkuDetailsParams params = SkuDetailsParams.newBuilder().setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
billingClient.querySkuDetailsAsync(params, (billingResult2, skuDetailsList) ->
{
// Process the result.
if (billingResult2.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
}
});
});
}
I have implemented the Billing library in order to have in-app products in my app. I can make a successful purchase and everything works fine. If I try to make a purchase again, I get the response "Product already owned" which shows that the purchase is fine. I am using as productID the test id: "android.test.purchased"
Moreover, in the Main's Activity onResume() method, I call the queryPurchases() method in order to restore the product in case the user deletes the app and re-installs it. However, this method returns an empty purchases list although the response code is OK.
This is the way I am using the method:
private fun startServiceConnectionIfNeeded(executeOnSuccess: Runnable?) {
if (mBillingClient.isReady) {
executeOnSuccess?.run()
} else {
mBillingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(#BillingClient.BillingResponse billingResponse: Int) {
if (billingResponse == BillingClient.BillingResponse.OK) {
Log.i(TAG, "onBillingSetupFinished() response: $billingResponse")
executeOnSuccess?.run()
} else {
Log.w(TAG, "onBillingSetupFinished() error code: $billingResponse")
}
}
override fun onBillingServiceDisconnected() {
Log.w(TAG, "onBillingServiceDisconnected()")
}
})
}
}
// I call this method in Main's onResume()
fun updateBillingSharedPreferencesKey() {
val executeOnConnectedService = Runnable {
val purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP)
val purchasesList = purchasesResult?.purchasesList
purchasesList?.let {
// this list is always empty, although I have a valid product
for (purchase in it) {
// I never enter this loop to handle the product functionality
Log.d(TAG, "purchase.sku = ${purchase?.sku}")
}
}
}
startServiceConnectionIfNeeded(executeOnConnectedService)
}
Am I doing something wrong? The service connection and the response code is ok.
How should I call the queryPurchases() method to get my valid in-app product?