Google Play Billing - signature verification failed for sku android.test.purchased

android, in-app-billing

Solution

I was facing the same question as you a few days ago. For those who download your live application from Google Play, if the test id ("android.test.purchased") works as you said, they will be able to buy your in-app purchases. Google play treats it the same as a 'real purchase' and it goes through the same channel as your personal SKU's. See Below:

Test Purchases (In-app Billing Sandbox)

Once authorized with testing access, those users can side-load your app and test the full merchandising, purchase, and fulfillment flow for your products. Test purchases are real orders and Google Play processes them in the same way as other orders. When purchases are complete, Google Play prevents the orders from going to financial processing, ensuring that there are no actual charges to user accounts, and automatically canceling the completed orders after 14 days.

http://developer.android.com/google/play/billing/billing_testing.html#test-purchases

I just tested my own personal SKU's now and I can say for a fact they're working! (I saw the order in my Google Merchant account). So go out and there, and make some money :)

On a side note, developer to developer... could you show me any examples or links to tutorials on how to run my purchase verification in the Application class? I think that is an idea I definitely want to steal from you. Cheers!

Problem

EDIT: since some people are still checking out this thread, I want to mention that this is highly obsolete, because it is about v2 in app purchase, which is now deprecated. Please check out the latest (currently v3) documentation, it is pretty straightforward There are loads of threads about this issue, and I think I understand the problem, however, at the moment I cannot test with real purchases, since I don't currently have a valid credit card, what Google accepts, only a Maestro, which is not accepted. This is why I ask for help (not purchase verification, but verifying that my thought process is good). First, the problem comes from the new `verifyPurchase` method. The new method checks for signatures, which should be fine. However, Google does not provide any signature for test ids, such as `android.test.purchased`. This causes the method below to always fail, and it will always return false on the verification, even if the fake purchase has been completed, and I had a confirmation dialog, that the purchase is indeed succesful. The method: ``` public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { //if(BuildConfig.DEBUG) return true; if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || TextUtils.isEmpty(signature)) { Log.e(TAG, "Purchase verification failed: missing data."); return false; } PublicKey key = Security.generatePublicKey(base64PublicKey); return Security.verify(key, signedData, signature); } ``` The problem comes from the `TextUtils.isEmpty()` checks, since the signature will be empty, the code will return false. My temporary, testing workaround is in the code, commented out. If I add the `if(BuildConfig.DEBUG) return true;` at the beginning of the method for testing, everything is working fine, the user gets the premium features up and running, so the problem is indeed about signatures. Another problem is, if I purchase `android.test.purchased`, I cannot query the inventory of the user, so I cannot be sure, that my checker method, which checks if the user has purchased the premium feature, works. My two questions: If I remove the `if(BuildConfig.DEBUG) return true;` line from `verifyPurchase`, and replace the `android.test.purchased` id with the real id of the real SKU I am offering, can I be sure everything will work correctly in my case? I repeat, with the added debug functionality everything is working fine. If you need to see any more code, let me know! The method below checks if the user has purchased the premium feature, if he/she has, then it sets the corresponding preferences, otherwise, if anything goes south, it leaves everything as it is. Is this method correct? I am doing this in the `Application` class, on every app start up, to prevent tinkering. ``` private void checkPremium() { //get the helper up and running final IabHelper helper=new IabHelper(INSTANCE, getBase64Key()); helper.startSetup(new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { //if the helper is in a correct state, check the inventory if(result.isSuccess()) { helper.queryInventoryAsync(new IabHelper.QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResult result, Inventory inv) { //if the inventory is reachable, check if we got the premium if(result.isSuccess()) { setPremium(inv.hasPurchase(ActWidgetSearch.SKU)); } } }); } } }); } ``` Thanks in advance!

Original source

Related problems