In apps billing signature verification

4.4k Views Asked by At

I got a question regards on developer payload, I've been reading the document and still finding myself to hard to understand the verifydeveloperpayload I still dont understand about :

boolean verifyDeveloperPayload(Purchase p) {
        String payload = p.getDeveloperPayload();
        /*
         * TODO: verify that the developer payload of the purchase is correct. It will be
         * the same one that you sent when initiating the purchase.
         *
         * WARNING: Locally generating a random string when starting a purchase and
         * verifying it here might seem like a good approach, but this will fail in the
         * case where the user purchases an item on one device and then uses your app on
         * a different device, because on the other device you will not have access to the
         * random string you originally generated.
         *
         * So a good developer payload has these characteristics:
         *
         * 1. If two different users purchase an item, the payload is different between them,
         *    so that one user's purchase can't be replayed to another user.
         *
         * 2. The payload must be such that you can verify it even when the app wasn't the
         *    one who initiated the purchase flow (so that items purchased by the user on
         *    one device work on other devices owned by the user).
         *
         * Using your own server to store and verify developer payloads across app
         * installations is recommended.
         */
        return true;
    }

If my code were

public void onClick(View v) {
    String item1;
    // TODO Auto-generated method stub
     switch(v.getId()) {
        case R.id.button1: {
            /* TODO: for security, generate your payload here for verification. See the comments on
             *        verifyDeveloperPayload() for more info. Since this is a SAMPLE, we just use
             *        an empty string, but on a production app you should carefully generate this. */

            item1 = "item1";
            String payload = email+item1;

            mHelper.launchPurchaseFlow(this, SKU_2006, RC_REQUEST,
                    mPurchaseFinishedListener, payload);
            break;
            }
         }

}

will the String payload from the boolean verifyDeveloperPayload equal to String payload from my onClick method?

How and where do i compare the payload?

1

There are 1 best solutions below

2
On BEST ANSWER

According to android documentation here it is stated that

The fifth argument contains a ‘developer payload’ string that you can use to send supplemental information about an order (it can be an empty string). Typically, this is used to pass in a string token that uniquely identifies this purchase request. If you specify a string value, Google Play returns this string along with the purchase response. Subsequently, when you make queries about this purchase, Google Play returns this string together with the purchase details.

Security Recommendation: It’s good practice to pass in a string that helps your application to identify the user who made the purchase, so that you can later verify that this is a legitimate purchase by that user. For consumable items, you can use a randomly generated string, but for non-consumable items you should use a string that uniquely identifies the user.

So , For the product ID SKU_2006 if you initiated the purchase flow with String payload = email+item1; then Google Play will return the same payload in the response and hence you would get it here as

boolean verifyDeveloperPayload(Purchase p) {
        String payload = p.getDeveloperPayload();
..
}

Now , let me define the whole scenario in terms of code :

First , you would initiate a purchase request like below

String payload = getUserEmailFromAndroidAccounts() + itemUniqueId;

mHelper.launchPurchaseFlow(new PurchaseFinishListener(itemUniqueId), SKU_GAS, 10001,   
   mPurchaseFinishedListener, payload);

If the purchase order is successful, the response data from Google Play is stored in an Purchase object that is passed back to the listener.

    private class PurchaseFinishListener implements IabHelper.OnIabPurchaseFinishedListener {
   private final String mItemUniqeId;
    public PurchaseFinishListener(String itemUniqeId) {

            mItemUniqeId = itemUniqeId;
        }

       public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
       {
          if (result.isFailure()) {
             Log.d(TAG, "Error purchasing: " + result);
             return;
          }      
    if (!verifyDeveloperPayLoad(mItemUniqeId , purchase)) {
     Log.d(TAG, "Authenticity verification failed");
             return;
    }

    // set your product as purchased in your DB or server

    }
    }

Now your verifyDeveloperPayLoad(purchase) method should look as below :

 private boolean verifyDeveloperPayLoad(String itemUniqueId , Purchase purchase) {
        String responsePayload = purchase.getDeveloperPayload();
        String computedPayload = getUserEmailFromAndroidAccounts() + itemUniqueId;

        return responsePayload != null && responsePayload.equals(computedPayload);
    }

If you have closely observed code , you would surely understand how is the work flow .

Further information about Subscription based purchase and one time purchase can be obtained from Android site.