Java=のGoogle APIクライアントライブラリを使用して、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
GOOGLE_CLIENT_MAIL
は、GoogleコンソールからのAPIアクセスからのメールアドレスです。 GOOGLE_KEY_FILE_PATH
は、APIアクセスからダウンロードされた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."
}
この問題についてあなたの助けに本当に感謝しています...
うまくいきました!私が従った手順:
開始する前に、更新トークンを生成する必要があります。これを行うには、まず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;
}
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;
}
これで、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;
}
そしてそれだけです!
一部の手順は https://developers.google.com/Android-publisher/authorization からです。
com.google.api-client
およびgoogle-api-services-androidpublisher
ライブラリを使用できます。
まず、Googleデベロッパーコンソールでプロジェクトに移動します( 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>
次に、最初に署名を検証します。
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
}
署名がフェッチサブスクリプションの詳細を確認する場合:
// 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());
これは、JWTトークンを生成することですべてのトークンの問題を処理するため、自分で処理する必要はありません。
Javaを使用したGoogleのAppEngineでサブスクリプションのステータスを確認したい人のために、SOで見つかった多くのコードに基づく実際の例を示します。私は数日を費やして、経験不足によって引き起こされた多くの間違いを解決しました。サーバーでサブスクリプションのステータスを確認するための提案がたくさんありますが、AppEngineでそれを行うのは簡単ではありませんでした。 SOで答えが見つからなければ、私はこれを思い付くことができませんでした。
ステップ1
最初に、Webブラウザからcodeが表示されるまで、Jonathan Naguinの回答にある「前提条件」セクションを確認する必要があります。今あなたが持っています。
準備ができています。
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;
}
更新トークンは期限切れにならないので、どこかに保存するか、コードにハードコードすることができます。 (上記のコードを1回実行するだけで、更新トークンを取得できます。)
ステップ
アクセストークンを取得する必要があります。 [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)
最後のステップ(楽しい部分)
これで、サブスクリプションが有効かどうかを確認するためのすべてのコンポーネントがあります。私はこれが好きでした。 [パッケージ名]、[製品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文字列をログに記録すると、何が問題かを理解するのに役立ちます。
これが誰かの役に立つことを願っています。
Jonathan Naguinの素晴らしい答えに便乗するために、更新とアクセストークンを取得するnodejsバージョンを次に示します。
//This script is to retreive a refresh token and an access token from Google API.
//NOTE: The refresh token will only appear the first time your client credentials are used.
// I had to delete my client id within api console and create a new one to get the refresh token again.
//This is the downloaded json object from Google API Console. Just copy and paste over the template below.
var googleJson = {"web":{"auth_uri":"","client_secret":"","token_uri":"","client_email":"","redirect_uris":[""],"client_x509_cert_url":"","client_id":"","auth_provider_x509_cert_url":"","javascript_origins":[""]}};
//Retrieved from OAuth
var code = ''; // Retrieved from the response of the URL generated by printGoogleAuthUrl(). You will need to be logged in as your publisher. Copy and paste the generated url. Copy the code parameter into this variable.
var refreshToken = ''; // Retrieved from the printRefreshToken() function call. Requires the code variable to be filled out.
var accessToken = ''; // Retrieved from the printAccessToken() function call. Requires the refreshToken variable to be filled out.
var querystring = require('querystring');
var https = require('https');
var fs = require('fs');
function printGoogleAuthUrl()
{
console.log("https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=" + googleJson.web.redirect_uris[0] + "&client_id=" + googleJson.web.client_id);
}
function printRefreshToken()
{
var post_data = querystring.stringify({
'grant_type' : 'authorization_code',
'client_id' : googleJson.web.client_id,
'client_secret' : googleJson.web.client_secret,
'code' : code,
'redirect_uri' : googleJson.web.redirect_uris[0]
});
var post_options = {
Host: 'accounts.google.com',
port: '443',
path: '/o/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var post_req = https.request(post_options, function(res) {
res.setEncoding('utf8');
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function(){
var obj = JSON.parse(data);
if(obj.refresh_token)
{
refreshToken = obj.refresh_token;
}
else
{
console.log("No refresh token found. I had to clear the web client id in Google Api Console and create a new one. There might be a better way here.");
}
console.log(data);
});
});
post_req.write(post_data);
post_req.end();
}
function printAccessToken()
{
var post_data = querystring.stringify({
'grant_type' : 'refresh_token',
'client_id' : googleJson.web.client_id,
'client_secret' : googleJson.web.client_secret,
'refresh_token' : refreshToken
});
var post_options = {
Host: 'accounts.google.com',
port: '443',
path: '/o/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var post_req = https.request(post_options, function(res) {
res.setEncoding('utf8');
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function(){
var obj = JSON.parse(data);
if(obj.access_token)
accessToken = obj.access_token;
else
console.log("No access token found.");
console.log(data);
});
});
post_req.write(post_data);
post_req.end();
}
printGoogleAuthUrl();
//printRefreshToken();
//printAccessToken();