我正在创建一个不需要用户帐户/登录的应用程序,并允许用户购买订阅。我想使用Google Play Developer API来验证用户是否有购买/有效订阅。从所有文档中,我收集了以下步骤。
他们是否正确,你能否回答其中的两个问题?
另外,我有一个Web服务,虽然我对Web服务或Web服务编程一无所知......我只知道它可能需要在这里使用。
编辑:这些步骤不正确。请参阅下面的答案,了解正确的步骤。但请注意,这仅适用于使用服务帐户(因为我不想要求用户必须明确允许API访问)
答案 0 :(得分:39)
事实证明,我的步骤不正确。我花了好几个星期来解决这个问题,似乎没有其他地方记录。不客气:
在Google APIs Console中创建 Web应用程序帐户。将任何网站作为“重定向URI”;没关系,因为你不会真正使用它。创建帐户时,您将获得客户端ID和客户端密码。
在计算机上的浏览器中,转到https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=[YOUR REDIRECT URI]&client_id=[YOUR CLIENT ID]
并在出现提示时允许访问。
查看地址栏。在您最初输入的URI的末尾将是您的刷新令牌。它看起来像1/....
您将在下一步中使用此“代码”。刷新令牌永不过期。
转到https://accounts.google.com/o/oauth2/token?client_id=[YOUR CLIENT ID]&client_secret=[YOUR CLIENT SECRET]&code=[CODE FROM PREVIOUS STEP]&grant_type=authorization_code&redirect_uri=[YOUR REDIRECT URI]
,将此“代码”转换为“刷新令牌”。您可以将结果值保存在程序中;除非明确撤销,否则它永不过期。 ( @BrianWhite插入此步骤 - 请参阅注释)
确保你使用的是POST。(由Gintas插入)
在您的代码中,使用BasicNameValuePairs https://accounts.google.com/o/oauth2/token
,"grant_type","refresh_token"
,"client_id",[YOUR CLIENT ID]
,"client_secret",[YOUR CLIENT SECRET]
向"refresh_token",[YOUR REFRESH TOKEN]
发送HttpPost请求。例如,here。您需要在单独的线程中执行此操作,可能使用AsyncTask。这将返回一个JSONObject。
从返回的JSONObject中获取访问令牌。例如,here。您需要获取字符串“access_token”。访问令牌在1小时后到期。
在您的代码中,向https://www.googleapis.com/androidpublisher/v1/applications/[YOUR APP'S PACKAGE NAME]/subscriptions/[THE ID OF YOUR PUBLISHED SUBSCRIPTION FROM YOUR ANDROID DEVELOPER CONSOLE]/purchases/[THE PURCHASE TOKEN THE USER RECEIVES UPON PURCHASING THE SUBSCRIPTION]?accesstoken="[THE ACCESS TOKEN FROM STEP 4]"
发送HttpGet请求。例如,查看here。
答案 1 :(得分:12)
.NET用户:我希望这个答案可以让别人感到悲痛。
@Christophe Fondacci在2015年指出,几年前公认的解决方案很有效。现在是2017年,这个过程更容易,更快。
我的用例是验证应用内订阅,我的移动应用会将订阅购买信息发送到我的RESTful服务器,后者又与Google联系以验证订阅购买。
策略是创建一个代表您运营的服务帐户。
自2017年1月起,将显示一个对话框,其中包含有关设置服务帐户的说明。该对话框将您带到Google API控制台;从那里,
A)点击创建服务帐户
B)创建有意义的服务帐户名称。由于我们对访问Android Publisher服务感兴趣,因此我选择了“发布者”。
C)对于角色,只需选择一些东西 - 您可以稍后更改。
D)为.Net实施选择“提供新私钥”和选择P12 。不要丢失这个文件!
5)现在你已经完成了#4,你会看到你的新服务帐户被列出;单击“授予访问权限”以启用它。
6)点击“查看权限”链接。您应该根据您的需求和API修改权限。
要验证应用内购买,请访问Cog->更改权限并启用GLOBAL“Visiblity”和“Manage Orders”权限。
好的,此时您已经在Google端配置了所有内容。现在设置服务器到服务器的东西。我建议创建 一个.Net控制台应用程序来测试你的实现,然后在需要的地方卸载它。
1)从Nuget
添加Android Publisher客户端库PM> Install-Package Google.Apis.AndroidPublisher.v2
2)将P12文件添加到项目根目录
3)更改P12属性,使“Build Action”为“Content”,“Copy To Output Directory”为“Copy if newer”。
4)实现类似这样的东西来测试你的访问和微调。
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Services;
using Google.Apis.Auth.OAuth2;
using Google.Apis.AndroidPublisher.v2;
...
public Task<SubscriptionPurchase> GetSubscriptionPurchase(string packageName, string productId, string purchaseToken)
{
var certificate = new X509Certificate2(
"{{your p12 file name}}",
"{{ your p12 secret }}",
X509KeyStorageFlags.Exportable
);
var credentials = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("{{ your service account email }}")
{
Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
}.FromCertificate(certificate))
;
var service = new AndroidPublisherService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "my server app name",
});
return service.Purchases.Subscriptions.Get(packageName, productId, purchaseToken).ExecuteAsync();
}
祝你好运,希望这有助于某人。
来源:
答案 2 :(得分:8)
如果你像我一样,并希望在 PHP 中执行此操作,请按照以下步骤操作...感谢Kalina的回答我花了三天时间才弄清楚它是怎么回事工作:)。
这里是:
转到Google开发者控制台https://console.developers.google.com/并创建网络应用。将'developers.google.com/oauthplayground'设为“重定向URI”;您将在步骤2中使用它。创建帐户时,您将获得客户端ID和客户端密码。确保添加了 Google Play Android Developer API 。
转到Google oauth2游乐场https://developers.google.com/oauthplayground/。这个伟大的工具是你未来几天最好的朋友。 现在转到设置:确保已设置使用您自己的OAuth凭据。只有这样,您才能在下面的表单中填写客户端ID 和客户端密码。
在 Google oauth2 playground 中,转到第1步选择&amp;授权API 在输入字段 https://www.googleapis.com/auth/androidpublisher 中填写范围。我无法在列表中找到Google Play Android Developer API,也许他们会在稍后添加一些时间。点击 AUTORIZE APIS 。做以下的授权事项。
在 Google oauth2 playground 中,转到步骤2 令牌的Exchange授权码。如果一切顺利,您将看到以/ 4开头的授权码。如果某些事情没有顺利,请检查右侧的错误消息。现在你点击'刷新访问令牌'。复制刷新令牌......它将以/ 1 ...
现在您可以随时获取访问令牌!这是如何:
$url ="https://accounts.google.com/o/oauth2/token";
$fields = array(
"client_id"=>"{your client id}",
"client_secret"=>"{your client secret}",
"refresh_token"=>"{your refresh token 1/.....}",
"grant_type"=>"refresh_token"
);
$ch = curl_init($url);
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//execute post
$lResponse_json = curl_exec($ch);
//close connection
curl_close($ch);
现在你有一个ACCESS TOKEN万岁... JSON将如下所示:
"access_token" : "{the access token}", "token_type" : "Bearer", "expires_in" : 3600
最后你准备问google了!以下是如何做到这一点:
$lAccessToken = "{The access token you got in}" ;
$lPackageNameStr = "{your apps package name com.something.something}";
$lURLStr = "https://www.googleapis.com/androidpublisher/v1.1/applications/$lPackageNameStr/subscriptions/$pProductIdStr/purchases/$pReceiptStr";
$curl = curl_init($lURLStr);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$curlheader[0] = "Authorization: Bearer " . $lAccessToken;
curl_setopt($curl, CURLOPT_HTTPHEADER, $curlheader);
$json_response = curl_exec($curl);
curl_close($curl);
$responseObj = json_decode($json_response,true);
返回的JSON将包含两个时间戳, initiateTimestampMsec 和 validUntilTimestampMsec 订阅有效的时间。两者都是将毫秒加到1970年1月1日的毫秒数。
答案 3 :(得分:6)
我不知道2012年,但在2015年你不应该手动执行这些步骤。我很难找到文档,所以我在这里发帖以防万一。
现在在服务器端(我认为如果你绝对需要,你仍然可以使用你的应用程序中的相同代码),将google-api-services-androidpublisher
客户端库包含在你的项目中(参见https://developers.google.com/api-client-library/java/apis/androidpublisher/v1)
正如您所提到的,您需要一个带有P12文件的服务帐户(客户端库只接受P12文件)。
然后,以下代码将验证并很好地获取购买信息:
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
List<String> scopes = new ArrayList<String>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
Credential credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(googleServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleServicePrivateKeyPath))
.setServiceAccountScopes(scopes).build();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential).build();
AndroidPublisher.Purchases purchases = publisher.purchases();
final Get request = purchases.get(packageName, productId, token);
final SubscriptionPurchase purchase = request.execute();
// Do whatever you want with the purchase bean
有关Java客户端身份验证的信息,请访问: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
答案 4 :(得分:2)
我可能会误解您的问题,但我认为您没有理由使用您引用的链接来获取Android应用的应用内结算功能。这个页面更有帮助:
http://developer.android.com/guide/google/play/billing/index.html
您可以试用它们包含的演示应用程序(Dungeons - http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-download)。这使用产品(一次性购买)而不是订阅,但您应该能够修改以测试您想要的产品。
我认为,对于您来说,关键是他们在示例中提供的restoreTransactions方法,以查看Google Play帐户是否有您的应用的任何订阅:
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request, int responseCode) {
if (responseCode == BillingVars.OK) {
// Update the shared preferences so that we don't perform a RestoreTransactions again.
// This is also where you could save any existing subscriptions/purchases the user may have.
SharedPreferences prefs = getSharedPreferences(my_prefs_file, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.commit();
} else {
Log.e(TAG, "RestoreTransactions error: " + responseCode);
}
}
答案 5 :(得分:2)
如果有人在接受的帖子最后一步(#7)中遇到问题,我发现?access_token=
代替?accessToken=
太糟糕的堆栈溢出不会让我直接向线程发表评论......
答案 6 :(得分:1)
由于您的应用可以拨打的网络服务,我建议您将私钥安全地存储在服务器上。您应该尽可能多地将应用程序内容移动到服务调用中,请参阅this link。我已经实现了应用内订阅,但是在此部分API出来之前。我必须自己进行注册和安全验证,但看起来这个API使用OAuth为您完成了大部分工作,尽管看起来您仍然负责存储订阅请求/验证。
在谈到使用现有库签署JWT时,它们似乎确实为您提供了到java库,Python库和PHP库的链接 - 它取决于您的Web服务或服务器组件的编写方式(我的是C#,所以我使用RSACryptoServiceProvider来验证签名购买。他们使用JSON对象进行实际的数据传输。