Google Play Developer API - токен покупки запроса возвращает недопустимое значение

Я пытаюсь настроить веб-сервис для запроса покупок в Google Play. Мы храним информацию о заказах для клиентов, и эта служба будет вызывать Google Play API для запроса деталей подписки.

Каждый раз, когда я пытаюсь запросить покупку, она выдает мне ошибку:

HTTP/1.1 400 Bad Request
{  
   "error":{  
      "errors":[  
         {  
            "domain":"global",
            "reason":"invalid",
            "message":"Invalid Value"
         }
      ],
      "code":400,
      "message":"Invalid Value"
   }
}

Вот что я попробовал:

  • Созданный проект на https://console.developers.google.com/ включил "Google Play Android Developer API"
  • Создал oAuth 2.0 client_id и client_secret для веб-приложения типа
  • Войдите в систему как владелец учетной записи, я сгенерировал refresh_token
  • В https://play.google.com/apps/publish я зашел в Настройки -> Доступ к API и связал проект с моим приложением.

Код мудрый, я использовал 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");

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...

Это возвращает:

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

Теперь я хочу получить информацию о покупке. У меня есть информация о покупке как таковая:

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

Теперь я хочу получить информацию о покупке. У меня есть информация о покупке как таковая:

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

Так как packageName / productId и access_token, кажется, работают для первого вызова, и purchaseToken находится вне информации о заказе. Что дает ошибку недопустимого значения?

Любая помощь приветствуется - не уверен, что еще можно попробовать. Спасибо!

ОБНОВЛЕНИЕ: я прошел и проверил все имена пакетов и настройку учетной записи. Реальная проблема, казалось, была службой, которую я поражал. Я переключил его на: https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/purchaseToken

Я также поменялся местами, чтобы использовать клиентский API Google, так как он выглядел намного чище, чем создание запросов вручную.

Спасибо за помощь и ответы

2 ответа

Сначала я хочу поделиться с вами тем, что 400 неверных запросов и какова реальная причина их возникновения?

Ответ: Это указывает на то, что запрос был недействительным. Например, отсутствует родительский идентификатор или недопустимая комбинация запрошенных измерений или метрик.

Рекомендованное действие: Вам нужно внести изменения в запрос API, чтобы он работал.

Ссылка на ресурс: стандартные сообщения об ошибках

Твоя проблема:

Ваш код работал правильно и возвращал связанный json файл в качестве вывода. Но через некоторое времяit is not working when you want to get information about purchase, Выдает сообщение об ошибке "HTTP/1.1 400 Bad Request"

Первопричина:

Для токена обновления ответ всегда содержит новый токен доступа. Ответ показан ниже:

{
  "access_token":"1/fFBGRNJru1FQd44AzqT3ZgXXXXXX",
  "expires_in":3920,
  "token_type":"Bearer",
}

Итак, токен доступа имеет время истечения. после истечения срока действия токен доступа не будет работать.

Есть и другое ограничение. Существуют ограничения на количество токенов обновления, которые будут выпущены; один лимит для каждой комбинации клиент / пользователь и другой для пользователя для всех клиентов.

Итак, в вашем случае вы уже превысили лимит создания токенов обновления.

Решение:

Итак, сначала нужно отозвать токен. Затем сохраните токены обновления в долговременном хранилище и продолжайте использовать их, пока они остаются действительными.

Поскольку вы используете токен обновления, вам нужно изменить HTTP-запрос https://accounts.google.com/o/oauth2/token в https://www.googleapis.com/oauth2/v4/token

Так что ваш код будет выглядеть так:

String refreshToken = "1/ljll6d9ME3Uc13jMrBweqXugV4g4timYcXXXXXXXXX";
HttpPost request = new HttpPost("https://www.googleapis.com/oauth2/v4/token");
List<NameValuePair> params = new ArrayList<NameValuePair>();
...............
...............

Процедура отзыва:

Есть 2 способа отзыва.

  1. Пользователь может отозвать доступ, зайдя в настройки аккаунта
  2. Приложение также может программно аннулировать предоставленный ему доступ.

Чтобы программно отозвать токен, ваше приложение отправляет запрос https://accounts.google.com/o/oauth2/revoke и включает токен в качестве параметра:

curl https://accounts.google.com/o/oauth2/revoke?token={token}

token может быть токеном доступа или токеном обновления. Если токен является токеном доступа и имеет соответствующий токен обновления, токен обновления также будет аннулирован.

NB. Если отзыв успешно обработан, то код состояния ответа равен 200. Для условий ошибки возвращается код состояния 400 вместе с кодом ошибки.

Ссылка на ресурс:

  1. Автономный доступ, использование обновления токена и отзыв токена

Это случилось со мной, когда я тестировал со статическими ответами, т.е. использовал зарезервированные идентификаторы продуктов для тестирования (например, android.test.purchased). Решение SkyWalker не помогло в этом случае.

Затем я использовал реальные идентификаторы продуктов, опубликовал свое приложение как альфа-версию в google play и загрузил apk релиза на свое устройство, и теперь все работает как положено.

Внимательно прочитайте главу " Настройка для тестовых покупок" в документации Google, чтобы правильно подготовить свое приложение и аккаунт к тестированию.

Проверьте это, чтобы увидеть запрос и ответ API. Нужна помощь с API Explorer

API: https://www.googleapis.com/androidpublisher/v1.1/applications/packageName/subscriptions/subscriptionId/purchases/token

Параметры запроса:

packageName:PACKAGE_NAME

subscriptionId: SUBSCRIPTION_ID

токен:PURCHASE_TOKEN

Другие вопросы по тегам