Jon*_*uin 25 java android google-api subscription google-play
我正在使用Google API Client Library for Java来获取有关在我的Android应用程序中购买的用户订阅的信息.这就是我现在正在做的事情:
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(GOOGLE_CLIENT_MAIL)
.setServiceAccountScopes("https://www.googleapis.com/auth/androidpublisher")
.setServiceAccountPrivateKeyFromP12File(new File(GOOGLE_KEY_FILE_PATH))
.build();
Androidpublisher publisher = new Androidpublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).
setApplicationName(GOOGLE_PRODUCT_NAME).
build();
Androidpublisher.Purchases purchases = publisher.purchases();
Get get = purchases.get("XXXXX", subscriptionId, token);
SubscriptionPurchase subscripcion = get.execute(); //Exception returned here
Run Code Online (Sandbox Code Playgroud)
GOOGLE_CLIENT_MAIL是来自Google控制台的API Access的电子邮件地址.
GOOGLE_KEY_FILE_PATH是从API Access下载的p12文件.
GOOGLE_PRODUCT_NAME是品牌信息的产品名称.
在Google APIS控制台中,启用了"Google Play Android Developer API"服务.
我得到的是:
{
"code" : 401,
"errors" : [ {
"domain" : "androidpublisher",
"message" : "This developer account does not own the application.",
"reason" : "developerDoesNotOwnApplication"
} ],
"message" : "This developer account does not own the application."
}
Run Code Online (Sandbox Code Playgroud)
我真的很感谢你对这个问题的帮助......
Jon*_*uin 43
我搞定了!我遵循的步骤:
在开始之前,我们需要生成刷新令牌.首先,我们必须创建一个API控制台项目:
那么,现在我们可以生成刷新令牌:
创建一个主类:
public static String getRefreshToken(String code)
{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
try
{
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(5);
nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));
nameValuePairs.add(new BasicNameValuePair("client_id", GOOGLE_CLIENT_ID));
nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
nameValuePairs.add(new BasicNameValuePair("code", code));
nameValuePairs.add(new BasicNameValuePair("redirect_uri", GOOGLE_REDIRECT_URI));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
org.apache.http.HttpResponse response = client.execute(post);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String refreshToken = json.getString("refresh_token");
return refreshToken;
}
catch (Exception e) { e.printStackTrace(); }
return null;
}
Run Code Online (Sandbox Code Playgroud)
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET和GOOGLE_REDIRECT_URI是先前值.
最后,我们有刷新令牌!此值不会过期,因此我们可以存储在某个站点中,如属性文件.
获取访问令牌.我们需要我们的普遍刷新令牌:
private static String getAccessToken(String refreshToken){
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
try
{
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("grant_type", "refresh_token"));
nameValuePairs.add(new BasicNameValuePair("client_id", GOOGLE_CLIENT_ID));
nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
nameValuePairs.add(new BasicNameValuePair("refresh_token", refreshToken));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
org.apache.http.HttpResponse response = client.execute(post);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String accessToken = json.getString("access_token");
return accessToken;
}
catch (IOException e) { e.printStackTrace(); }
return null;
Run Code Online (Sandbox Code Playgroud)
}
现在,我们可以访问Android API.我对订阅的到期时间感兴趣,所以:
private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static JsonFactory JSON_FACTORY = new com.google.api.client.json.jackson2.JacksonFactory();
private static Long getSubscriptionExpire(String accessToken, String refreshToken, String subscriptionId, String purchaseToken){
try{
TokenResponse tokenResponse = new TokenResponse();
tokenResponse.setAccessToken(accessToken);
tokenResponse.setRefreshToken(refreshToken);
tokenResponse.setExpiresInSeconds(3600L);
tokenResponse.setScope("https://www.googleapis.com/auth/androidpublisher");
tokenResponse.setTokenType("Bearer");
HttpRequestInitializer credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
.build()
.setFromTokenResponse(tokenResponse);
Androidpublisher publisher = new Androidpublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).
setApplicationName(GOOGLE_PRODUCT_NAME).
build();
Androidpublisher.Purchases purchases = publisher.purchases();
Get get = purchases.get(GOOGLE_PACKAGE_NAME, subscriptionId, purchaseToken);
SubscriptionPurchase subscripcion = get.execute();
return subscripcion.getValidUntilTimestampMsec();
}
catch (IOException e) { e.printStackTrace(); }
return null;
Run Code Online (Sandbox Code Playgroud)
}
就这样!
部分步骤来自https://developers.google.com/android-publisher/authorization.
您可以使用com.google.api-client和google-api-services-androidpublisher库。
首先,在Google Developer Console(https://console.developers.google.com)上转到该项目。
然后将刚刚为服务帐户生成的电子邮件地址添加到您的Google Play开发者控制台(https://play.google.com/apps/publish/)
@developer.gserviceaccount.com电子邮件帐户现在到代码。将以下依赖项添加到pom.xml文件:
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.18.0-rc</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.18.0-rc</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v1.1-rev25-1.18.0-rc</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
然后首先验证签名:
byte[] decoded = BASE64DecoderStream.decode(KEY.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decoded));
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (sig.verify(BASE64DecoderStream.decode(signature.getBytes())))
{
// Valid
}
Run Code Online (Sandbox Code Playgroud)
如果签名验证获取订阅详细信息,请执行以下操作:
// fetch signature details from google
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(ACCOUNT_ID)
.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/androidpublisher"))
.setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
.build();
AndroidPublisher pub = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
.setApplicationName(APPLICATION_NAME)
.build();
AndroidPublisher.Purchases.Get get = pub.purchases().get(
APPLICATION_NAME,
PRODUCT_ID,
token);
SubscriptionPurchase subscription = get.execute();
System.out.println(subscription.toPrettyString());
Run Code Online (Sandbox Code Playgroud)
通过生成JWT令牌,这将解决所有令牌问题,因此您不必自己处理它。
对于那些想要使用 Java 检查 Google AppEngine 上的订阅状态的人,这里是我基于 SO 上找到的许多代码的工作示例。我花了几天的时间解决了很多由于缺乏经验而导致的错误。我看到很多建议在服务器上检查订阅状态,但对我来说在 AppEngine 上做到这一点并不容易。如果没有在 SO 上找到答案,我无法想出这个。
步骤1
首先,我们需要浏览 Jonathan Naguin 答案中的“先决条件”部分,直到您从网络浏览器获取代码。现在你有;
准备好。
请注意,我们在 AppEngine 上运行下面显示的所有代码。我这样使用记录器。
static final Logger log = Logger.getLogger(MyClassName.class.getName());
Run Code Online (Sandbox Code Playgroud)
第2步
我们需要获取刷新令牌。将 [YOUR CLIENT ID]、[YOUR CLIENT SECRET]、[YOUR CODE]、[YOUR REDIRECT URI] 替换为您的字符串后,运行下面所示的代码。
private String getRefreshToken()
{
try
{
Map<String,Object> params = new LinkedHashMap<>();
params.put("grant_type","authorization_code");
params.put("client_id",[YOUR CLIENT ID]);
params.put("client_secret",[YOUR CLIENT SECRET]);
params.put("code",[YOUR CODE]);
params.put("redirect_uri",[YOUR REDIRECT URI]);
StringBuilder postData = new StringBuilder();
for(Map.Entry<String,Object> param : params.entrySet())
{
if(postData.length() != 0)
{
postData.append('&');
}
postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
URL url = new URL("https://accounts.google.com/o/oauth2/token");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.getOutputStream().write(postDataBytes);
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String refreshToken = json.getString("refresh_token");
return refreshToken;
}
catch (Exception ex)
{
log.severe("oops! " + ex.getMessage());
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
由于刷新令牌不会过期,我们可以将其保存在某处或简单地在代码中进行硬编码。(我们只需要运行上面的代码一次即可获取刷新令牌。)
步骤3
我们需要获取访问令牌。将 [YOUR CLIENT ID]、[YOUR CLIENT SECRET]、[YOUR REFRESH TOKEN] 替换为您的字符串后,运行下面所示的代码。
private String getAccessToken()
{
try
{
Map<String,Object> params = new LinkedHashMap<>();
params.put("grant_type","refresh_token");
params.put("client_id",[YOUR CLIENT ID]);
params.put("client_secret",[YOUR CLIENT SECRET]);
params.put("refresh_token",[YOUR REFRESH TOKEN]);
StringBuilder postData = new StringBuilder();
for(Map.Entry<String,Object> param : params.entrySet())
{
if(postData.length() != 0)
{
postData.append('&');
}
postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
URL url = new URL("https://accounts.google.com/o/oauth2/token");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.getOutputStream().write(postDataBytes);
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String accessToken = json.getString("access_token");
return accessToken;
}
catch (Exception ex)
{
log.severe("oops! " + ex.getMessage());
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
步骤4
我想知道的是订阅的 UTC 到期时间。下面显示的代码在发现错误时返回expire UTC, 0。您需要提供您的软件包名称、产品 ID(=订阅 ID)、您在第 3 步中获得的访问令牌以及在购买数据中找到的购买令牌。
private long getExpireDate(String packageName,String productId,String accessToken,String purchaseToken)
{
try
{
String charset = "UTF-8";
String query = String.format("access_token=%s",URLEncoder.encode(accessToken,charset));
String path = String.format("https://www.googleapis.com/androidpublisher/v1/applications/%s/subscriptions/%s/purchases/%s",packageName,productId,purchaseToken);
URL url = new URL(path + "?" + query);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestProperty("Accept-Charset",charset);
connection.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer buffer = new StringBuffer();
for(String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
return json.optLong("validUntilTimestampMsec");
}
catch (Exception ex)
{
log.severe("oops! " + ex.getMessage());
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意产品 ID 或订阅 ID 是在开发人员控制台上找到的字符串。您的订阅项目将显示在名称/ID 列中。看起来像这样。
Description of item(product id)
Run Code Online (Sandbox Code Playgroud)
最后一步(有趣的部分)
现在我们拥有验证订阅是否有效的所有组件。我确实喜欢这个。您需要将 [您的包名称]、[您的产品 ID] 替换为您的。
您需要提供购买数据,您可以通过iabHelper 代码中的Purchase#getOriginalJson() 获取这些数据。
private boolean checkValidSubscription(String purchaseData)
{
String purchaseToken;
JSONObject json;
try
{
json = new JSONObject(purchaseData);
}
catch (JSONException e)
{
log.severe("purchaseData is corrupted");
return true; // false positive
}
purchaseToken = json.optString("purchaseToken");
if(purchaseToken.length() == 0)
{
log.severe("no purchase token found");
return true; // false positive
}
String accessToken = getAccessToken();
if(accessToken == null)
{
return true; // false positive
}
long expireDate = getExpireDate([YOUR PACKAGE NAME],[YOUR PRODUCT ID],accessToken,purchaseToken);
if(expireDate == 0)
{
log.severe("no expire date found");
return true; // false positive
}
expireDate += 86400000l; // add one day to avoid mis judge
if(expireDate < System.currentTimeMillis())
{
log.severe("subscription is expired");
return false;
}
// just for log output
long leftDays = (expireDate - System.currentTimeMillis()) / 86400000l;
log.info(leftDays + " days left");
return true;
}
Run Code Online (Sandbox Code Playgroud)
调试注意事项
Google 返回 JSON 字符串作为响应。如果代码无法按预期工作,记录 JSON 字符串可能有助于了解问题所在。
我希望这可以帮助别人。
| 归档时间: |
|
| 查看次数: |
24852 次 |
| 最近记录: |