Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check android purchase status but return the purchase token was not found

I refered google play android api to check the purchase and consumption status of an in-app item. For some orders, I can get right result,but some return the error as below:

error: {
errors: [
{
domain: "global",
reason: "purchaseTokenNotFound",
message: "The purchase token was not found.",
locationType: "parameter",
location: "token"
}
],
code: 404,
message: "The purchase token was not found."
}

Purchase token is provided by google, does it can be faked?

I found if I cancel the google order, then check the purchase status,it will return the purchase token was not found. if not, i will get the right purchase status.

Hope somebody can help.

like image 394
pangpang Avatar asked Aug 20 '14 09:08

pangpang


People also ask

How do I set up in-app purchases on Android?

On the Google Play Store app, in-app purchases will be by the Price or Install button. On play.google.com/store, you'll see "Offers in-app purchases" below the name of the app.

Can't connect to Google Play billing?

Log out of your Google account Go to Android Settings > Accounts > Google and tap on Remove account. Data will not be lost as normally all of it will be synced with Google's cloud services (true for Google accounts). Re-add your account then restart your device. Try buying again.


2 Answers

If you are selling the same INAPP product to the same user muliple times within a short period, then it's very likely that all access tokens except the last purchase will return a 404 code.

For example:

[email protected] went to your app and purchased com.example.test.product a few times, you will probaly notice within your records (or Google Wallet Merchant account) that it's the same user buying the product.

When you go to check the last purchase from this user, then the following is likely to appear

{
kind: "androidpublisher#inappPurchase",
purchaseTime: "1409823171827",
purchaseState: "0",
consumptionState: "1",
developerPayload: "My Product | Ref | 1409823162466"
}

and yet if you were to check his previous tokens, then it's very likely that his purchases will return 404!

I had read somewhere (can't remember where) that the purchase token created for each purchase is basically based on the inapp product and google user. Therefore, it's very likely that each purchase will "destroy" any previous purchase token created for the same user.

Hope this explanation helps. I am constantly having this problem everyday when my server is attempting to connect to the Google API and check the transactions. Perhaps one day somebody will read this and provide a solution :)

like image 149
Daniel Fernandes Avatar answered Sep 30 '22 05:09

Daniel Fernandes


The documents are misleading. You don't need to use this API to verify purchases.

Mobile app have INAPP_PURCHASE_DATA and INAPP_DATA_SIGNATURE from getBuyIntent method.

You can verify the purchase with the signature and your public key.

https://developer.android.com/google/play/billing/billing_reference.html#getBuyIntent

You can find the public key on Google Play Developer Console -> YOUR_APP -> service and API

package main

import (
        "crypto"
        "crypto/rsa"
        "crypto/sha1"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
)

//replace const below with your own.
const (
        pubKeyPEM=`-----BEGIN PUBLIC KEY-----
Some thing like this
-----END PUBLIC KEY-----`
        data = `purchase data from getBuyIntent API`
        sign = `purchase data signature from getBuyIntent API`

)

func Panic(err error) {
        if err != nil {
                panic(err)
        }
}

func main() {

        PEMBlock, _ := pem.Decode([]byte(pubKeyPEM))
        if PEMBlock == nil {
                Panic(fmt.Errorf("Could not parse Public Key PEM"))
        }
        if PEMBlock.Type != "PUBLIC KEY" {
                Panic(fmt.Errorf("Found wrong key type"))
        }
        pubkey, err := x509.ParsePKIXPublicKey(PEMBlock.Bytes)
        if err != nil {
                Panic(err)
        }

        // compute the sha1
        h := sha1.New()
        h.Write([]byte(data))

        // decode b64 signature
        signature, err := base64.StdEncoding.DecodeString(sign)
        Panic(err)

        // Verify
        err = rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), crypto.SHA1, h.Sum(nil), signature)
        Panic(err)

        // It verified!
        fmt.Println("OK")
}
like image 31
supei Avatar answered Sep 30 '22 06:09

supei