Android in app purchase: Signature verification fa

2020-01-25 03:49发布

I have tried for several days to solve this problem, using the Dungeons demo code that comes with the SDK. I've tried to Google for an answer but can't find one.

  • In the Dungeons demo, I passed my public key from the dev console.
  • Signed the apk and uploaded to console without publish.
  • Testing for both android.test.purchased & product list created on console with published for subscription (The main feature I want for my app).

But still I get an error of Signature verification failed and then the signature does not match data. How can I solve this?

public static ArrayList<VerifiedPurchase> verifyPurchase(String signedData, String signature)
{
    if (signedData == null) {
        Log.e(TAG, "data is null");
        return null;
    }
    if (Consts.DEBUG) {
        Log.i(TAG, "signedData: " + signedData);
    }
    boolean verified = false;
    if (!TextUtils.isEmpty(signature)) {

        String base64EncodedPublicKey = "MIIBIjA....AQAB";
        PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
        verified = Security.verify(key, signedData, signature);
        if (!verified) {
            Log.w(TAG, "signature does not match data.");
            return null;
        }
    }
}

public static boolean verify(PublicKey publicKey, String signedData, String signature)
{
    if (Consts.DEBUG) {
        Log.i(TAG, "signature: " + signature);
    }
    Signature sig;
    try {
        sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initVerify(publicKey);
        sig.update(signedData.getBytes());
        if (!sig.verify(Base64.decode(signature))) {
            Log.e(TAG, "Signature verification failed.");
            return false;
        }
        return true;
    } catch (NoSuchAlgorithmException e) {
        Log.e(TAG, "NoSuchAlgorithmException.");
    } catch (InvalidKeyException e) {
        Log.e(TAG, "Invalid key specification.");
    } catch (SignatureException e) {
        Log.e(TAG, "Signature exception.");
    } catch (Base64DecoderException e) {
        Log.e(TAG, "Base64 decoding failed.");
    }
    return false;
}

14条回答
成全新的幸福
2楼-- · 2020-01-25 04:23

This problem is still going on in the current Google billing version. Basically the android.test.purchased is broken; After you buy android.test.purchased the verifyPurchase function in Security.java will always fail and the QueryInventoryFinishedListener will stop at the line if (result.isFailure()); this is because the android.test.purchased item always fails the TextUtils.isEmpty(signature) check in Security.java as it is not a real item and has no signature returned by the server.

My advice (from lack of any other solution) is to NEVER use "android.test.purchased". There are various code tweaks on the net but none of them work 100%.

If you have used the android.test.purchased then one way to get rid of the error is to do the following:-

  1. Edit Security.java and change the "return false" line in the verifyPurchase to "return true" - this is temporary, we'll be putting it back in a minute.
  2. In your QueryInventoryFinishedListener, after the "if (result.isFailure()) {...}" lines add the following to consume and get rid of your never ending android.test.purchased item:

    if (inventory.hasPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD)) {  
       mHelper.consumeAsync(inventory.getPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD),null);
       }
    
  3. Run your app so the consunmeAsync happens, this gets rid of the "android.test.purchased" item on the server.

  4. Remove the consumeAsync code (or comment it out).
  5. Back in the Security.java, change the "return true" back to "return false".

Your QueryInventoryFinishedListener will no longer error on the verify, everything is back to "normal" (if you can call it that). Remember - don't bother using android.test.purchased again as it will just cause this error again... it's broke! The only real way to test your purchasing it to upload an APK, wait for it to appear, and then test it (the same APK) on your device with logging enabled.

查看更多
够拽才男人
3楼-- · 2020-01-25 04:23

You can skip the verifying process for those "android.test.*" product ids. If you are using the sample code from the TrivialDrive example, open IabHelper.java, find the following line code, change it from

   if (Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... }

into

   boolean verifySignature = !sku.startsWith("android.test."); // or inplace the condition in the following line
   if (verifySignature && !Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... }

It's harmless, even if you forgot to rollback the code. So, you can continue to test the further workflow step.

查看更多
你好瞎i
4楼-- · 2020-01-25 04:27

The error is caused because of the wrong license key. Maybe the license key is probably from your another app.

The solution is to use the proper license key from :

Play console > App > Development Tools > Licensing & in-app billing

查看更多
霸刀☆藐视天下
5楼-- · 2020-01-25 04:27

Signature verification fails only for the default test product. A quick fix :

  • Goto IabHelper class.
  • Invert the if conditions of Security.verifyPurchase.

Thats it!

Remember to revert the changes when test product is replaced by actual product

查看更多
地球回转人心会变
6楼-- · 2020-01-25 04:29

This is what worked for me:

  1. Call BillingClient.querySkuDetailsAsync to query if item if available
  2. Wait for SkuDetailsResponseListener.onSkuDetailsResponse
  3. Wait another 500ms
  4. Start purchase using BillingClient.launchBillingFlow...

The step 3 shouldn't be necessary because when I received onSkuDetailsResponse it should be OK but it isn't, had to wait a little bit. After that purchase works, no more "Item not available error". This is how I tested it:

  1. clear my app data
  2. clear Google Play data
  3. run app
  4. purchase android.test.purchased
  5. try to purchase my items (it fails with item not available)
  6. use my solution above, it works
查看更多
倾城 Initia
7楼-- · 2020-01-25 04:31

This Solution worked for me. I changed the new verifyPurchase method in purchase class with old one.

查看更多
登录 后发表回答