26

Androidアプリで購入したユーザーのサブスクリプションに関する情報を取得するために、Java用のGoogleAPIクライアントライブラリを使用しようとしています。これが私が今している方法です:

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_MAILGoogleコンソールからのAPIAccessからのメールアドレスです。 GOOGLE_KEY_FILE_PATHAPIAccessからダウンロードしたp12ファイルです。
GOOGLE_PRODUCT_NAMEブランド情報からの製品名です。
Google APISコンソールでは、サービス「Google PlayAndroidDeveloperAPI」が有効になっています。

私が得ているのは:

{
  "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."
}

この問題についてご協力いただきありがとうございます...

4

6 に答える 6

46

動作しました!私が従った手順:

前提条件

開始する前に、更新トークンを生成する必要があります。これを最初に行うには、APIコンソールプロジェクトを作成する必要があります。

  1. APIコンソールに移動し、 Android開発者アカウント( Android開発者コンソールでAPKをアップロードするために使用したのと同じアカウント)でログインします。
  2. [プロジェクトの作成]を選択します。
  3. 左側のナビゲーションパネルで[サービス]に移動します。
  4. Google Play AndroidDeveloperAPIをオンにします。
  5. 利用規約に同意します。
  6. 左側のナビゲーションパネルで[APIアクセス]に移動します。
  7. [OAuth2.0クライアントIDの作成]を選択します。
    • 最初のページで、製品名を入力する必要がありますが、ロゴは必須ではありません。
    • 2ページ目で、Webアプリケーションを選択し、リダイレクトURI とJavascriptオリジンを設定します。後でリダイレクトURIを使用します。
  8. [クライアントIDの作成]を選択します。クライアントIDクライアントシークレットを覚えておいてください。後で使用します。

これで、更新トークンを生成できます。

  1. 次のURIに移動します(リダイレクトURIは、末尾のバックスラッシュを含め、クライアントIDに入力された値と正確に一致する必要があることに注意してください)。

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID

  1. プロンプトが表示されたら、[アクセスを許可する]を選択します。
  2. ブラウザは、4/eWdxD7b-YSQ5CNNb-c2iI83KQx19.wp6198ti5Zc7dJ3UXOl0T3aRLxQmbwIのようなコードパラメータを使用してリダイレクトURIにリダイレクトされます。この値をコピーします。

次のコマンドでメインクラスを作成します。

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_IDGOOGLE_CLIENT_SECRETおよびGOOGLE_REDIRECT_URIは以前の値です。

最後に、更新トークンがあります。この値は期限切れにならないため、プロパティファイルなどのサイトに保存できます。

Google Play AndroidDeveloperAPIへのアクセス

  1. アクセストークンを取得します。以前に更新したトークンが必要になります。

    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;
    

    }

  2. これで、AndroidAPIにアクセスできるようになりました。サブスクリプションの有効期限に興味があるので、次のようにします。

    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からのものです。

于 2012-10-03T14:42:29.643 に答える
8

com.google.api-clientgoogle-api-services-androidpublisherライブラリを使用できます。

まず、Googleデベロッパーコンソール(https://console.developers.google.com)でプロジェクトにアクセスします

  • APIと認証->API
  • 「GooglePlayAndroidDeveloperAPI」を有効にする
  • [資格情報]->[新しいクライアントIDの作成]に移動します
  • サービスアカウントを選択
  • クライアントIDを作成する
  • p12ファイルを安全な場所に保存します

次に、サービスアカウント用に生成されたばかりのメールアドレスを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トークンを生成することですべてのトークンの問題が処理されるため、自分で処理する必要はありません。

于 2014-06-17T13:08:39.847 に答える
5

GoogleのAppEnginewithJavaでサブスクリプションのステータスを確認したい方のために、SOで見つかった多くのコードに基づいた私の作業例を次に示します。私は経験不足によって引き起こされた多くの間違いを解決するために数日を費やしました。サーバーでサブスクリプションのステータスを確認するための提案がたくさんありますが、AppEngineで行うのは簡単ではありませんでした。SOで答えが見つからなければ、私はこれを思い付くことができませんでした。

ステップ1

まず、Webブラウザーからコードを取得するまで、JonathanNaguinの回答にある「前提条件」セクションを確認する必要があります。今、あなたは持っています。

  • クライアントID
  • クライアントシークレット
  • URIをリダイレクトする
  • コード

準備。

以下に示すすべてのコードを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回実行するだけで済みます。)

ステップ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)

最後のステップ(楽しい部分)

これで、サブスクリプションが有効かどうかを確認するためのすべてのコンポーネントができました。私はこれが好きでした。[あなたのパッケージ名]、[あなたの製品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文字列をログに記録すると何が問題なのかを理解するのに役立つ場合があります。

これが誰かに役立つことを願っています。

于 2015-04-19T10:50:21.763 に答える
4

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();
于 2014-02-04T20:23:42.603 に答える
0

AndroidPublisher v3でより最新の回答をお探しの方は、https ://stackoverflow.com/a/57943483/1028256をご覧ください。

refreshTokenとaccessTokenを処理する必要はなく、数行のコードを処理するだけです。

Androidクライアントの場合、この「公式」サンプルコードを見つけました:https ://github.com/googlesamples/android-play-publisher-api/blob/master/v3/java/src/com/google/play/developerapi/samples/ AndroidPublisherHelper.javaと、.p12ファイルまたはアプリの資格情報の両方でAndroidPublisherを取得するオプションがあります。

于 2021-10-08T15:39:25.610 に答える
-1

メールアドレスではなく、クライアントIDを使用する必要があると確信しています。次のようになります:37382847321922.apps.googleusercontent.com

https://developers.google.com/android-publisher/authorizationを参照してください

client_id=<the client ID token created in the APIs Console>

そして、私はあなたがP12ファイルを必要としないとかなり確信しています。必要なのは

client_secret=<the client secret corresponding to the client ID>

最初にコマンドラインから「wget」を使用して手動で実行してみてください。

于 2012-07-04T21:24:30.943 に答える