Can a consumable inapp purchase be verified after it is consumed - in-app-billing

The documentation states all inapp products are managed now. However, you must still make a distinction of whether your inapp product is managed or not when you set it up, so it appears there is still a difference. Thus I've been setting up consumable products as unmanaged.
I've set up the "getpurchase" and "verifydeveloperpayload" function for each item to check whether anything has been bought. I'm assuming this would return false for a consumed consumable, since otherwise you call the consume function. Would using the "getpurchase" function for each item and checking if it is null be enough?
It would be nice to be able to check whether a game app player has bought anything, consumable (unmanaged?) or otherwise (managed), in order to eliminate ads for that player.

Related

How do I distinguish between for consumeable products and for products that aren't consumed?

I used 'com.android.billingclient: billing: 2.0.3'.
How do I distinguish between for consumable products and for products that aren't consumed?
Consumables are approved for purchase with consumeAsync() and non-consumable products are approved for purchase with acknowledgePurchase().
It seems like consumable products and non-consumable products are classified through whether consumeAsync() is called or not.
1. Are there other methods of classification?
(https://developer.android.com/google/play/billing/billing_library_overview#acknowledge/)
2. acknowledgePurchase () is directed to apis for non-consumable products. Shouldn't it be used for consumable products?
I can add a developer paylaod this way:
For consumable products, consumeAsync() takes a ConsumeParams object that includes a developer payload field, as shown in the following example:
BillingClient client = ...
ConsumeResponseListener listener = ...
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.consumeAsync(consumeParams, listener);
For products that aren't consumed, acknowledgePurchase() takes an AcknowledgePurchaseParams object that includes a developer payload field, as shown in the following example:
BillingClient client = ...
AcknowledgePurchaseResponseListener listener = ...
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.acknowledgePurchase(acknowledgePurchaseParams, listener);
(https://developer.android.com/google/play/billing/billing_library_overview#attach_a_developer_payload)
3. Do you plan to add management type for consumable and non-consumable products in the future?
4. Could the call be restricted for mistyped functions?
Google Play doesn't have the knowledge of consumable SKUs vs non-consumable SKUs. Only developers have this knowledge.
If you would like users to repeated purchase one SKU (like coins, gems), then you can call consumeAsync() to remove it from user's library. Google Play won't allow users to repurchase a SKU if it is already in his library. Therefore, you have to consume it (remove it from his library).
For some other SKU, such as subscription or ads free, premium content unlock, limited item, if you want users only buy once then don't consume it. Instead, use acknowledgePurchase API. Google Play introduced this as a contract to make sure that you have granted the products to users.
Therefore, I would say keep a catalog of consumable, non-consumable SKUs on your side. And based on the type, call the correct Google's API.
For what I understand so far,
non-consumable product call acknowledgePurchase() is to set the purchase record to acknowledged in Google side, so when u trying to trigger queryPurchase(), it will show the product is purchased with acknowledged (parse the json data to view the data)
consumable product call consumeAsync() is to remove the data in Google side. So when trigger queryPurchase() should be no record for that.
Why consumable product can purchase again?
Because the record ady removed from the record. When trigger purchase again will not return error code 7 (BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED)
both consumeAsync() and acknowledgePurchase() also will set the payment to done. If didn't trigger anyone of them, then it will auto refund after 3 days. Both of the action also work as acknowledge the payment.
So for your question
1. Are there other methods of classification?
Those acknowledged one should be non-consumable product, since consumable product record should be removed after success record to our side. Or if want to classify, maybe can set developer payload for the acknowledgement(can't changed after set)
2. acknowledgePurchase () is directed to apis for non-consumable products. Shouldn't it be used for consumable products?
no, use it separately based on your requirement
The answer maybe incorrect. Just some sharing about it.
welcome to answer my question also related to this, acknowledgement perform at server side
Server side can do something similar to mobile side comsumeAsync() in Google Billing Library?

How to get purchaseHistory for IAPs with BillingClient

As the documentation says:
queryPurchaseHistoryAsync():
Returns the most recent purchase made by the user for each SKU, even if that purchase is expired, canceled, or consumed.
So lets say I would like to make an IAP for the user to remove Ads forever from my app.
How do I decide with a fresh install if that user already purchased that IAP if this function also returns the "canceled" IAPS?
I would like to query the actually purchased IAPS, not everything. Becuase that way a user could unlock the Ad free version with a cancelled IAP.
To make it worse, the Purchase class doesn't have status like "cancelled" or "consumed" I cannot decide the state of the user's purchased IAPS.
Am I missing something here?
Thanks in advance
The billing client documentation states it checks for the user.
Then we have the question: Who is the user
If you look at the steps taken for the billing api on https://developer.android.com/google/play/billing/billing_library_overview then you see that a connection to google play is needed.
What happens then is that the current user on android, the account they are signed in with on google play and their mobile device is determined to be the user.
So if they purchased it via google play in app, it will always be assigned to that user on google play and that is what's being queried by this. No matter on which device they are logged in, Their tablet, smartwatch, phone, television, etc...
How to get a list of actually bought products
Instead of using async that gives you everything included abandoned shopping carts I suggest you use https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases
That way Get purchases details for all the items actually bought and paid within your app. This method uses a cache of Google Play Store app without initiating a network request.
Note: It's recommended for security purposes to go through purchases
verification on your backend (if you have one) by calling the
following API:
https://developers.google.com/android-publisher/api-ref/purchases/products/get
If you read that API link it's easy to check with the online cache if the purchase was valid with a simple GET request.
Personally I would build in a check if the phone is suspect to be rooted before doing the manual background check with the purchases API that sends a request to the store.
Phones that are not rooted have a higher trust level, as the user are probaly not very tech savvy and will not have a shimmer of a clue how to circumvent such checks, and the google play cache will be updated regularly, reflecting trustworthy data.
When a phone is suspect to be rooted(you can read protected directories/write to them), then perform the check online if they bought the stuff each time you deem it neccesary.

Removing autorenewable subscriptions from iPhone App

I have an iPhone app that also features autorenewable products as an in-app purchase. The products are subscriptions to our service for up to 1 year in the future. We wanted to remove the whole in-app-purchase and autorenewable product from our app in the next version.
To accomplish this, we removed the signup option inside our app, so no new user should be able to sign up. Now we would like to disable the automatic renewal for all existing users.
How can I accomplish this? Is it sufficient to remove the in-app-products for our app inside iTunes Connect? Do the users get notified about this?
According to Apple (see WWDC 2011 Session 510, In App Purchases for iOS and OS X, at the 48:55 mark), the only things you can do as a developer to prevent subscriptions from auto-renewing are:
Raise the price.
Remove the auto-renewing IAP product from iTunes connect.
In both cases, notification emails are sent to subscribers, though not immediately. The talk says Apple checks 10 days before a (yearly) subscription renewal and sends email at that time. It's not documented anywhere, though, so I'd treat that as an implementation detail.
I've done the latter (removing the product) several times with my own (monthly) apps, and it seems to work as advertised.
One important note: if your app is a Newsstand app, it must have at least one auto-renewing subscription available. If you remove the last one, the app will be removed form the App Store. Users who have already purchased it will still be able to use it, and will be able to download copies from the "previously purchased" section of the app store, but no new copies will show up for purchase in the App Store proper.
It will depend on how you've implemented your system. Do you check receipts (and provide data/service) from your own server, or do it all within the app directly with Apple's servers?
In iTunes Connect you can remove a product from sale, effective immediately or at a future date. I suspect that's enough to stop a renewing subscription. (Remember you can test this with shortened timescales in the Sandbox.) But if not:
If you use your own server to validate receipts, go and give it an incorrect shared secret so that the verification step fails. That means the subscription validity will return as false (although for the 'wrong' reason) so your customers won't be able to renew.
If you do it within the app, generate a new shared secret so the one within your existing structures is incorrect. Then, as above.
If you can, I suggest sending a notification to your current users notifying them of the change, suggesting that they change, and letting them know it will 'fail' in the future but that's ok.

iOS in-app purchase keeping track of items purchased

I am new to the world of in-app purchase and I just watched the tutorial on iTunes about how to integrate it to my app. I am wondering how the developer would keep track of the items purchased WITHOUT having to verify the receipt. I thinking it would be nice if we could just store the purchased items in the app because then we would be able to identify items purchased without having internet connection.
What's the convention to do this? Is this a bad practice?
There are 2 way you can keep track of purchased items:
1 - Storage - Temporary / Permanent. Obviously Temporary storage doesn't protect you against deletion / device change. Permanent storage can be ensured if you store it in keychain or on your own server soon after purchase is successful.
2 - Apple's own API tells you - based on certain rules / condition.
Condition: If this is non-consumable purchase, and you try to purchase again.([SKPaymentQueue addPayment])
The response from itunes store will cause storekit to invoke updatedtransactions - with status - SKPaymentTransactionStateRestored. This simply means that product is already purchased, needs to be restored - so it is your responsibility to unlock it.
In short, it won't allow you to purchase again if it's nonconsumable purchase. Same must be true for subscriptions that haven't yet expired (not sure about it).
If you need step by step tutorial on how to integrate IAP - here is my own lecture series with SWIFT and Objective C. It also accompanies code sample.
This is a bad practice because, what happens when your user deletes and re-installs the app?
He won't have his purchased items anymore.
This tutorial is a very good one, it should point you in the right direction.
There should be an app or device feature that is allowed or is capable of recording and managing EVERY in-app purchase made through the Apple ID.
Problem is… The current setup of in-app purchases is not user friendly.
In short: Buying is your problem and recording your purchases is only a "convenient feature provided generously" by Apple Inc and app developers.
It shouldn't be like this though. Apple Inc and the app developers should consolidate user purchase info and make it transparent and easy to access/understand by the user.
This is the 21st century, after all.

You've already purchase this subscription. Tap Buy to renew or extend it

We are developing an app that uses the non-renewing subscription IAP model. While testing the subscription purchase process in the sandbox, we are seeing two messages with ‘buy’ buttons pop up.
The first message is displayed with the product information: “Do you want to buy one subscription for $xx.xx?”
After you click ‘buy’ for the first message, a second message (with another buy button) is displayed: “You’ve already purchased this subscription. Tap Buy to renew or extend it.”
Is this normal iTunes/sandbox behavior for re-purchasing non-renewing subscriptions after they have expired? Does iTunes require you to tap a ‘buy’ button twice?
I checked the behavior of EverNote by extending their non-renweing-subs, and it seems that is the behavior which we can't avoid.
I encountered the same issue with Non-Renewing-Subs + MKStoreKit, and thought it has something to do with my settings first, but I don't think there is nothing we can do about it.
One thing you could try (although I'm not sure Apple will like this) is creating a bunch of identical products in the store (say 48 identical products but with different identifiers: subscription1, subscription2, ..., subscription48). Then, when you need to extend the subscription you just pick the next subscription. This way the user will not get that annoying message. With 48 different products you should be good for 4 years. Hopefully by then Apple has its sanity back :)
may be you have purchased it and it hasnt expired. or it may have been purchased in a diffferent device, but you still have old one. when its tried to purchase its found that its already bought hence asked to extend. IAP is tied to apple id.