I am in the process of integrating In-App Billing in my application for unmanaged products. I've configured my application in the market already to implement the BILLING permission. I've published the product ids as expected by my in-development version of my application. I've used test products so far, but for quality assurance have been trying to test with real products, charging to an AMEX card as well as personal VISA/Mastercard cards.
When I have a transaction go through, everything in my application works without a hitch. I'm even confirming all of the notification ids, so no problems there.
Throughout the process though, I have run into an issue where there is an inability to purchase the products.
The Market application responds to the user with a dialog with text
"Purchase canceled
Your payment could not be processed. Sign in to your Google Wallet account to request support."
This issue is seen on 2 Galaxy Nexus 4G devices as well as an HTC Sensation 4G. The issue occurs on WiFi, 3G, and 4G networks. The accounts purchasing initially receive an "Order receipt" email, followed by an "Order cancellation" email. The order receipt email properly includes the full information for the transaction including product name, cost, order number, date, etc. The order cancellation also includes all of this information and describes the reason for cancellation as, "Took too long to deliver". The application gets a broadcast of a purchase state change at this time, which is the cancelation of the transaction.
Any insight into what's happening and why I'm having all of my transactions fail to complete?
Through email feedback from an Android Developer Advocate, I have confirmed that this is a risk/settlement issue.
Full response from him:
Dallas,
I'm sorry to hear that you've been having difficulty getting adequate support for this issue. My apologies.
The issue you describe is currently a known issue. Your assessment was correct when you said that this was a settlement/risk issue.
Specifically, these users are being flagged by Google Checkout as being in a "risk bin" by our automated systems. These users' orders are temporarily delayed while we manually investigate the account. In the majority of cases, the orders are released for processing within 24 hours without problem.
In-app billing is a special case, as all in-app billing orders are subject to a 45 second processing timeout. (This was based on feedback from several prominent app developers.) Unfortunately, this means that any user who is placed into a risk bin will have their order canceled. Attempting the purchase again 24 hours later should work correctly.
In particular, all the orders mentioned in your bug report are from the same user, whose account is currently listed as "On Hold" while a risk review is completed. (Note that accounts used for developer testing are much more likely to get flagged for risk review, as they tend to display anomalous purchasing patterns.)
Again, the Market team is aware of this issue and is actively working on improving the customer experience.
Thanks for your patience.
Apparently, this is a Google Issue. Please check this link for more info:
http://groups.google.com/group/android-developers/browse_thread/thread/66e26d87a7226000?pli=1
Related
Not a "how to test in-app-billing" question!!
Initially, I did not think this limitation would cause me any grief:
However, now that my application is in production and I frequently find myself providing a live demo on my device to someone, I find this to be a large enough inconvenience that I need a workaround. It's embarrassing to inform a potential large customer, that I can't show them all features on this device because I am the main developer. They just hear Bla Blah blah - something this guy wrote doesn't work.
How do others go about using the in-app products on their own device for their own app? I'd rather not carry around another device. I tried adding a second account to my device but somehow Android/Google still knows it is tied to my account / I am the publisher (maybe because my Gmail address is listed as a recovery account?) I can think of a dozen ways to give myself a back door and make everything free, but all of those options open up potential security holes. At this point, I'm considering a special APK / Build that I will manually create and install on my device only that always returns "true" when checking if a product is purchased or not.
The most common answer which most developers do is have a different account for publishing their app from their personal account. They then add their personal account as a user on the developer account For app publishing, the account has an awful lot of power. Creating a new gmail account to use for the developer console is not too hard.
So I might have nickssoftware#gmail.com as my Play Console account owner, and nick#gmail.com (both made up addresses) as the account on my phone. The Play Console account never gets added to any phone.
I use Google LVL and Google Inapp Billing API ver 3 in my java application for Android. Of course I use (slightly modified) LVL library project from Google extras and IAP jar that Google suggests.
LVL library LicenseValidator in verifyLicense receives ResponseData with user-id in it.
It is said in Google docs that it is an unique user ID, representing user's google account used for purchase.
So I assumed (and made sure in tests) it is the same string (for example, "ANlOH<...>ppA==") on all devices where user has logged in with the same Google account.
So here is my iap purchase protection scheme in short.
Before the purchase app sends user-id to my server. It generates an encrypted payload from user-id and sends it back. App makes a purchase request and puts payload in it. App receives a receipt signed by Google, that holds the same payload. App sends this receipt to my server with the current user-id. Server makes signature and other checks, compares user-ids from payload and from sender and if everything is fine sends files of iap item to the app.
In another scenario, when the user reinstalls the app to this or another device, app gets receipts belonging to him from InAppBilling, sends them to my server with the current user-id. Server performs the same checks and - if everything is fine - sends all needed files to the app.
This approach with small differences works well on other platforms. But I have experiencing some strange glitches recently on Android app.
My server logs receipt check issues and I have found strange errors: user with one user-id sent correctly signed receipts belonging to another user-id (payload in receipt holds that another user-id). When I started to investigate I've found that one of such strange "hacker attack" messages belongs to
one of my test devices while other belong to real users (according to order-ids in receipts).
This test device with Android 4.4.2 has several google accounts added in Settings.
Previously I was sure that Google uses the first account. I saw such log messages:
InAppBillingUtils.getPreferredAccount: com.mypackage.appname: Account from first account - [jbC...FgH]
But now I see that sometimes LVL uses not the first account, but another one. I see such messages in LogCat:
InAppBillingUtils.pickAccount: smpxg.mythdefdf: Account determined from library ownership - [boL...M5E]
Moreover, after fresh installation of my app InAppBilling returned receipts for one account, but LVL gave user-id of another! But this behaviour is not stable. For example, now I see that LVL and InAppBilling both think that second account is my primary and work with it as expected.
I assumed that both libraries will work side by side but it looks like I was wrong. Obviously when the app sends receipt belonging to user-id "...yUQ" along with current use-id "...ppA" to server it refuses to send purchased content. And he is right.
If user could change current account used for purchases, I'd just added this trick in FAQ. BUT I can't see a way to select it manually in settings. In addition, system somehow selects it in a random way! The only way to make things work is to ask a user to delete all accounts from the device except his primary, but it's a bad solution.
When user purchases iap item being logged into one account and then switches to another account he should expect not to see purchased item. It's a predictable behaviour, just like with purchasing apps. But he doesn't even know what account is used in the moment!
AFAIK, there's not way to get from InAppBilling service google user-id it selected for purchases.
But even if I could - having user-id changed randomly by system makes iap items to appear and disappear from time to time :)
Looks like Google advises to use developer payload for protection, but doesn't give any stable ID which can be used to identify particular account.
So my questions are:
Does anybody experience this strange account switching?
How can I be sure which account is current?
Is there any way to synchronize LVL and InAppBilling account
selection? Any workarounds?
Thank you in advance!
I havent had an exact experience with your issue, but this might be somewhat relevant
According to the In app billing documentation
If the device has more than one account, the purchase will be made with the account that downloaded the app. If none of the accounts has downloaded the app, the purchase is made with the first account.Users can confirm the account that is making a purchase by expanding the purchase dialog.
I have implemented subscription with android inapp billing, and used Trivial Drive example for it as is (util package)
With "inapp" items all fine, I can buy this type's item, but if I try to buy subscription (type = "subs"), I get the strange error from google: Your order was declined because it was considered high-risk
In the google wallet of buyer's account is:
Status Canceled Your purchase has been canceled. You won't be charged.
Oct 25 ยป Google has canceled this purchase. Comments from Google:
Your order was declined because it was considered high-risk. Please
try again in 30 minutes.
What could be wrong here?
This is a message from a fraud detection system Google uses to prevent malicious payment transactions from been executed. Before executing a payment transaction, Google tried to analyze how safe this transaction is. Multiple parameters can impact this check. A probability of "bad transaction" rises, for instance, when multiple payments are executed by different devices using the same credit card very often, or when same credit card is used by multiple accounts, or when user pays and then cancels payments multiple times in a row, etc.
This is a temporal error, which can disappear next day. Is you have no time to wait with testing, contact Google Play support and explain the situation. They will fix this issue for your development account. This is how I've got it solved.
I have added in-app billing to my app, and everything seems to work fine on the Android side. But the orders in Google Checkout cannot be charged, even though the status is chargeable, because the Charge Order button is disabled. Apart from this, everything about the order appears to be correct.
The same thing happens with the Dungeons sample app, so I am a bit stuck at this point.
You give very little informations about your problem.
What is the purchase type you're using ? If they are "managed per user account", then they can only be purchased once for a given user. Maybe the charge has been successful once, and is now blocked (in which case you should use "unmanaged" purchases)
Or maybe I'm totally wrong, and you should give us some additional infos.
Yes, Google will block you from charging unless your app is published or you register your self as a test user.
Test users can parches when the app is not published.
You don't use the Charge button when selling Android apps. Charging occurs automatically.
Maybe the Charge button is there for other kind of goods sold on Google Play, but for software sales it's useless, thus it's grayed.
Worth a general read: In-app Billing.
On the Google checkout side of things, one potential cause for this issue is that there is a delay period with purchases for fraud detection, etc. (source "Charge Order" button greyed out). More reading on this here: In-app billing and Google Checkout setup. It is typical for the "charge order" button to be greyed out during this period.
I'm guessing that this isn't your issue however, because it would have been resolved already. In can't press charge order button but order is chargeable one of the most relevant points is given as
#sounddoctorin: If you click the order details, you will see why - its likely the order is in some pending state "Reviewing", etc.
The point is that if you can't click the "Charge" button, it means the order is still pending for one reason or another.
For more information on charge states visit "Understanding Order States".
If this still doesn't help resolve your issue I would look into figuring out why it is misbehaving. What other data can you gather?
I have a few questions connected to Android In-App Billing:
Is it possible to make a purchase from non-Market app? I understand that it would be a vulnerability, but I have no opportunity to find out if it's possible or not.
How can I get purchase state for a particular product? As far as I understand it can be done using RESTORE_TRANSACTIONS request, but it's not recommended to use very often. That's not a theoretical problem. My application allows users to buy content using in-app billing. Content can be downloaded from a server, and server must allow content downloading only if it was purchased. But it can't check if content was purchased or not without using signed response from Android Market.
How can I get price and description of an item from Android Market? Seems that I know the answer and it's "there's no way it can be done", but maybe I'm wrong. It would be very useful to have a possibility of retrieving item's price.
It's very interesting to me how you solved/are going to solve these problems in your apps. Answer to any of these questions will be appreciated.
In order:
1- Nope. The in-app billing process is part of Market. If the app comes from elsewhere, there's no way for Market to verify the origin/authenticity of the application.
2- It's your responsibility to store the purchase state for a particular product. From the doc:
You must set up a database or some other mechanism for storing users' purchase information.
RESTORE_TRANSACTIONS should be reserved for reinstalls or first-time installs on a device.
3- Unfortunately, at this time you're right. File a feature request!
In the meantime, one option is to set up a website with appengine, store listings of all your content & pricing there, and then manually sync prices listed on your appengine server with the updated prices in Market. Then have your Android app pull the data from the AppEngine server. This is much better than hardcoding price values into the app itself, since you don't need to have everyone update the app immediately to see accurate pricing whenever you change something. The only caveat of this method is that if the user is in a different country, in-app billing will display an approximated price in their native currency, and there's no way for you to determine exactly what price will be displayed to them.
Related, One of the Android Developer Advocates is giving a talk on LVL/IAP at IO, called "Evading Pirates and Stopping Vampires using License Verification Library, In-App Billing, and App Engine." - It would definitely be worth your while to watch when they release the session videos on the website.