java Google Play Developer API - 查询购买令牌返回无效值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35019357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Google Play Developer API - Query purchase token returns Invalid Value
提问by Fid
I am trying to set up a web service to query Google Play purchases. We store the order information for customers and this service would call Google Play API to query the subscription details.
我正在尝试设置一个网络服务来查询 Google Play 购买。我们为客户存储订单信息,此服务将调用 Google Play API 来查询订阅详细信息。
Every time i try to query a purchase, it gives me the error:
每次我尝试查询购买时,它都会给我错误:
HTTP/1.1 400 Bad Request
{
"error":{
"errors":[
{
"domain":"global",
"reason":"invalid",
"message":"Invalid Value"
}
],
"code":400,
"message":"Invalid Value"
}
}
Here is what I tried:
这是我尝试过的:
- Created a project in https://console.developers.google.comenabled the "Google Play Android Developer API"
- Created an oAuth 2.0 client_id and client_secret for type Web application
- Logged in as the account owner, I generated a refresh_token
- In https://play.google.com/apps/publishI went to Settings -> API Access and linked the the project to my app
- 在https://console.developers.google.com创建项目启用“Google Play Android Developer API”
- 为类型 Web 应用程序创建了 oAuth 2.0 client_id 和 client_secret
- 以帐户所有者身份登录,我生成了一个 refresh_token
- 在https://play.google.com/apps/publish 中,我转到 Settings -> API Access 并将项目链接到我的应用程序
Code wise, I used the refresh_token to get an access_token:
在代码方面,我使用 refresh_token 来获取 access_token:
String refreshToken = "1/ljll6d9ME3Uc13jMrBweqXugV4g4timYcXXXXXXXXX";
HttpPost request = new HttpPost("https://accounts.google.com/o/oauth2/token");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("client_id", client_id));
params.add(new BasicNameValuePair("client_secret", client_secret));
params.add(new BasicNameValuePair("refresh_token", refreshToken));
params.add(new BasicNameValuePair("grant_type", "refresh_token"));
request.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
JSONObject json = new JSONObject(body);
String accessToken = json.getString("access_token");
The access_token from this works because i can call this API with it and get the response back:
来自这个的 access_token 有效,因为我可以用它调用这个 API 并得到响应:
String url = String.format("https://www.googleapis.com/androidpublisher/v2/applications/%s/inappproducts/%s", packageName, productId);
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
get.setHeader("Authorization", "Bearer " + accessToken);
HttpResponse response = client.execute(get);
// parse response etc...
This returns:
这将返回:
{
"packageName":"com.my.app",
"sku":"com.my.app.premium",
"status":"active",
"purchaseType":"subscription",
"defaultPrice":{
//...
}
},
"listings":{
"en-US":{
"title":"My App Premium",
"description":"My App"
}
},
"defaultLanguage":"en-US",
"subscriptionPeriod":"P1Y"
}
Now, I want to get informatoin about a purchase. I have a information from a purchase as such:
现在,我想获取有关购买的信息。我有这样的购买信息:
{
"orderId":"GPA.1111-1111-1111-11111",
"packageName":"com.my.app",
"productId":"com.my.app.premium",
"purchaseTime":1452801843877,
"purchaseState":0,
"developerPayload":"XXXXXXXd9261023a407ae5bb6ab8XXXXXXX",
"purchaseToken":"xxxxxxxxxxxxxx.YY-J123o12-xxxxxxxxxxxxxxxmYRk2itBkNdlXhyLMjXsxxxxxxxxxxxxLfBxabaAjKbeBC0PVhHnHd1DDbFkgZtbQxxk5pDIAH3xBHu8HrcWfRgewAYnFeW9xxxxxxxxxxxxxC5TDjcBL8fhf",
"autoRenewing":true
}
String url = String.format("https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/products/%s/tokens/%s",packageName, productId, purchaseToken);
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
get.setHeader("Authorization", "Bearer " + accessToken);
HttpResponse response = client.execute(get);
// parse response etc...
Since the packageName / productId and access_token seem to work for the first call, and the purchaseToken is right out of the order info. What is giving the invalid value error?
由于 packageName / productId 和 access_token 似乎适用于第一次调用,并且 purchaseToken 正好在订单信息之外。什么是无效值错误?
Any help appreciated - not sure what else to try. Thanks!
任何帮助表示赞赏 - 不知道还有什么可以尝试的。谢谢!
UPDATE: I went through and validated all the package names and account setup The real issue seemed to be the service i was hitting. I switched it to: https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/purchaseToken
更新:我检查并验证了所有包名称和帐户设置 真正的问题似乎是我正在使用的服务。我把它切换到:https: //www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/purchaseToken
I also swapped to use the Google Client API as it was much cleaner looking that manually creating requests.
我还改用了 Google Client API,因为手动创建请求看起来更简洁。
Thanks for help and replies
感谢您的帮助和回复
回答by SkyWalker
First I want to share with you what is 400 bad requestand what is the real cause for occuring it?
首先我想和大家分享一下什么是400 bad request,产生它的真正原因是什么?
Ans:It indicates that the query was invalid. E.g., parent ID was missing or the combination of dimensions or metrics requested was not valid.
Ans:表示查询无效。例如,缺少父 ID 或请求的维度或指标的组合无效。
Recommended Action:You need to make changes to the API query in order for it to work.
推荐的操作:您需要对 API 查询进行更改才能使其正常工作。
Resource Link:Standard Error Responses
资源链接:标准错误响应
Your problem:
你的问题:
Your code was running properly and returning related json
file as output. But after a period,it is not working when you want to get information about purchase
. It gives error message "HTTP/1.1 400 Bad Request"
您的代码运行正常并返回相关json
文件作为输出。但一段时间后,it is not working when you want to get information about purchase
。它给出错误消息“HTTP/1.1 400 Bad Request”
Root cause:
根本原因:
For refresh token, the response always includes a new access token. A response is shown below:
对于刷新令牌,响应始终包含新的访问令牌。响应如下所示:
{
"access_token":"1/fFBGRNJru1FQd44AzqT3ZgXXXXXX",
"expires_in":3920,
"token_type":"Bearer",
}
So, access token has a expiry time. after a expiry time, the access token will not work.
因此,访问令牌有一个到期时间。到期后,访问令牌将不起作用。
There is another restriction also. There are limits on the number of refresh tokens that will be issued; one limit per client/user combination, and another per user across all clients.
还有另一个限制。将发行的刷新令牌数量有限制;每个客户端/用户组合一个限制,所有客户端每个用户另一个限制。
So, in your case, you have already crossed your limit of creating refresh token.
因此,就您而言,您已经超出了创建刷新令牌的限制。
Solution:
解决方案:
So, you first need to revoke the token. Then save refresh tokens in long-term storage and continue to use them as long as they remain valid.
因此,您首先需要撤销令牌。然后将刷新令牌保存在长期存储中,只要它们保持有效就继续使用它们。
As you are using refresh token, then you need to change the http post request https://accounts.google.com/o/oauth2/token
to https://www.googleapis.com/oauth2/v4/token
当您使用刷新令牌时,您需要将 http post 请求更改https://accounts.google.com/o/oauth2/token
为https://www.googleapis.com/oauth2/v4/token
So your code will be look like below:
所以你的代码将如下所示:
String refreshToken = "1/ljll6d9ME3Uc13jMrBweqXugV4g4timYcXXXXXXXXX";
HttpPost request = new HttpPost("https://www.googleapis.com/oauth2/v4/token");
List<NameValuePair> params = new ArrayList<NameValuePair>();
...............
...............
Revoking procedure:
撤销程序:
There are 2 ways for revoking.
有2种撤销方式。
- A user can revoke access by visiting Account Settings
- It is also possible for an application to programmatically revoke the access given to it.
- 用户可以通过访问帐户设置来撤销访问
- 应用程序也可以以编程方式撤销授予它的访问权限。
To programmatically revoke a token, your application makes a request to https://accounts.google.com/o/oauth2/revoke
and includes the token as a parameter:
要以编程方式撤销令牌,您的应用程序会https://accounts.google.com/o/oauth2/revoke
向该令牌发出请求并将其作为参数包含在内:
curl https://accounts.google.com/o/oauth2/revoke?token={token}
The token
can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.
该token
可以的访问令牌或刷新令牌。如果令牌是访问令牌并且它有相应的刷新令牌,则刷新令牌也将被撤销。
N.B: If the revocation is successfully processed, then the status code of the response is 200. For error conditions, a status code 400 is returned along with an error code.
注意:如果撤销成功处理,则响应的状态代码为 200。对于错误情况,状态代码 400 与错误代码一起返回。
Resource Link:
资源链接:
回答by David Riha
This happened to me when I was testing with Static Responses, i.e. using reserved product IDs for testing (like android.test.purchased
). SkyWalker's solution did not help in this case.
当我使用静态响应进行测试时,这发生在我身上,即使用保留的产品 ID 进行测试(如android.test.purchased
)。SkyWalker 的解决方案在这种情况下没有帮助。
Then I used real product IDs, published my app as alpha to google play and side-loaded the release apk into my device and now everything works as expected.
然后我使用真实的产品 ID,将我的应用作为 alpha 发布到 google play 并将发布的 apk 侧加载到我的设备中,现在一切都按预期工作。
Be sure to read carefully chapter Setting Up for Test Purchasesin google docs to prepare your app and account properly for testing.
请务必仔细阅读google 文档中的“设置测试购买”一章,以正确准备您的应用程序和帐户以进行测试。
回答by Prashant Arvind
Check out this to see API request and response. Need help with the API Explorer
查看这个以查看 API 请求和响应。需要有关API Explorer 的帮助
API: https://www.googleapis.com/androidpublisher/v1.1/applications/packageName/subscriptions/subscriptionId/purchases/token
Request parameters:
请求参数:
packageName:PACKAGE_NAME
subscriptionId:SUBSCRIPTION_ID
token:PURCHASE_TOKEN
包名称:PACKAGE_NAME
订阅 ID:SUBSCRIPTION_ID
令牌:PURCHASE_TOKEN