对于那些想要使用 Java 在 Google 的 AppEngine 上检查订阅状态的人,这里是我基于 SO 上的许多代码的工作示例。我花了几天时间解决了许多由于缺乏经验而导致的错误。我看到很多建议检查服务器上的订阅状态,但我在 AppEngine 上做起来并不容易。如果没有在 SO 上找到答案,我无法想出这个。
步骤1
首先,我们需要通过 Jonathan Naguin 的答案中的“先决条件”部分,直到您从 Web 浏览器获取代码。现在你有;
准备好。
请注意,我们在 AppEngine 上运行下面显示的所有代码。我像这样使用记录器。
static final Logger log = Logger.getLogger(MyClassName.class.getName());
第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;
}
由于刷新令牌不会过期,我们可以将它保存在某个地方,或者只是在我们的代码中硬编码。(我们只需要运行一次上述代码即可获得刷新令牌。)
第 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;
}
第4步
我想知道的只是订阅的 UTC 过期时间。下面显示的代码返回过期 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;
}
注意产品 ID 或订阅 ID 是在开发者控制台上找到的字符串。您的订阅项目出现在名称/id 列中。它看起来像这样。
Description of item(product id)
最后一步(有趣的部分)
现在我们有所有组件来验证订阅是否有效。我确实喜欢这个。您需要将 [YOUR PACKAGE NAME]、[YOUR PRODUCT 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;
}
调试注意事项
Google 返回 JSON 字符串作为响应。如果代码无法按预期工作,记录 JSON 字符串可能有助于了解问题所在。
我希望这可以帮助别人。