我是否正确地validation了用户的Android应用内订阅?

我正在制作一个不需要用户帐户/登录的应用程序,并允许用户购买订阅。 我想使用Google Play Developer API来validation用户是否有购买/有效订阅。 从所有文档中,我收集了以下步骤。

它们是否正确,你能回答其中的两个问题吗?

  1. 在Google API控制台中创建服务帐户 。
  2. 保存给我的私钥(其中?当然不在我的代码/设备上, 如此示例代码所示)
  3. 使用Google API Client Library for Java使用私钥创建和签署JWT( 文档如何给我这个 ,但这不是Java代码……我该怎么办?)
  4. 构造访问令牌请求,并获得对API的访问权限
  5. 应用程序现在可以向API发送GET请求,以确定用户是否具有订阅
  6. 访问令牌过期后,请返回步骤3。

此外,我有一个Web服务,虽然我对Web服务或Web服务编程一无所知……我只知道它可能需要在这里使用。

编辑:这些步骤不正确。 请参阅下面的答案,了解正确的步骤。 但请注意,这仅适用于使用服务帐户(因为我不想要求用户必须明确允许API访问)

Solutions Collecting From Web of "我是否正确地validation了用户的Android应用内订阅?"

事实certificate,我的步骤不正确。 我用了几个星期来解决这个问题,似乎没有其他地方记录。 别客气:

  1. 在Google API控制台中创建Web应用程序帐户。 将任何网站作为“重定向URI”; 没关系,因为你不会真正使用它。 创建帐户时,您将获得客户端ID和客户端密码。

  2. 在计算机上的浏览器中,访问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]并在出现提示时允许访问。

  3. 查看地址栏。 在您最初输入的URI的末尾将是您的刷新令牌。 它看起来像1/....你将在下一步中需要这个“代码”。 刷新令牌永不过期。

  4. 转到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]将此“代码”转换为“刷新令牌” 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插入)

  5. 在您的代码中,使用BasicNameValuePairs "grant_type","refresh_token""client_id",[YOUR CLIENT ID]"client_secret",[YOUR CLIENT SECRET]发送HttpPost请求到https://accounts.google.com/o/oauth2/token "client_secret",[YOUR CLIENT SECRET]"refresh_token",[YOUR REFRESH TOKEN] 。 这里有一个例子。 您需要在单独的线程中执行此操作,可能使用AsyncTask。 这将返回一个JSONObject。

  6. 从返回的JSONObject获取访问令牌。 这里有一个例子。 您需要获取字符串“access_token”。 访问令牌在1小时后到期。

  7. 在您的代码中,将HttpGet请求发送到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]" 。 这里有一个例子。

.NET用户:我希望这个答案能让人感到悲伤。

正如@Christophe Fondacci在2015年指出的那样,几年前公认的解决方案非常有效。 现在是2017年,这个过程变得更加容易和快捷

我的用例是validation应用内订阅,我的移动应用会将订阅购买信息发送到我的RESTful服务器,后者又与Google联系以validation订阅购买。

策略是创建一个代表您运营的服务帐户。

  1. 登录您的Google Play开发者控制台 ,然后点击您正在设置的应用。
  2. 访问设置 – > API访问权限
  3. 在“ 服务帐户”下 ,单击“ 创建服务帐户”按钮。
  4. 截至2017年1月,将显示一个对话框,其中包含有关设置服务帐户的说明。 该对话框将您带到Google API控制台; 从那里,

    A)单击“ 创建服务帐户”

    B)创建有意义的服务帐户名称。 由于我们对访问Android Publisher服务感兴趣,因此我选择了“发布者”。

    C)对于角色,只需选择一些东西 – 您可以稍后更改。

    D)选择“提供新私钥”并为.Net实施选择P12 。 不要丢失这个文件!

5)现在你完成#4,你会看到你的新服务帐户列出; 单击“授予访问权限”以启用它。

6)点击“查看权限”链接。 您应该根据您的需求和API修改权限。

要validation应用内购买,请访问Cog-> Change Permissions并启用GLOBAL“Visiblity”和“Manage Orders”权限。

好了,此时您已经在Google端配置了所有内容。 现在设置服务器到服务器的东西。 我建议创建一个.Net控制台应用程序来测试你的实现,然后在需要的地方卸载它。

1)从Nuget添加Android Publisher客户端库

 PM> Install-Package Google.Apis.AndroidPublisher.v2 

2)将P12文件添加到项目根目录

3)更改P12属性,使“构建操作”为“内容”,“复制到输出目录”为“如果更新则复制”。

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 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(); } 

祝你好运,希望这有助于某人。

资料来源:

将OAuth 2.0用于服务器到服务器应用程序

适用于Google.Apis.AndroidPublisher.v2的.Net客户端库

如果你像我一样,并希望在PHP中这样做,这里是如何做到的程序…感谢Kalina的回答我花了三天时间才弄清楚它是如何工作的:)。

开始:

  1. 转到谷歌开发者控制台https://console.developers.google.com/并创建一个Web应用程序 。 将’developers.google.com/oauthplayground’设为“重定向URI”; 您将在步骤2中使用它。创建帐户时,您将获得客户端ID和客户端密码。 确保添加了Google Play Android Developer API

  2. 访问Google oauth2游乐场https://developers.google.com/oauthplayground/ 。 这个伟大的工具是你未来几天最好的朋友。 现在转到设置:确保已设置使用您自己的OAuth凭据 。 只有这样,您才能在下面的表格中填写您的客户ID客户机密

  3. Google oauth2 playground中,转到步骤1 选择并授权API填写输入字段https://www.googleapis.com/auth/androidpublisher中的范围。 我无法在列表中findGoogle Play Android Developer API,也许他们会在稍后添加一些时间。 点击AUTORIZE APIS 。 做下面的授权事情。

  4. Google oauth2 playground中,转到步骤2 代币的Exchange授权代码 。 如果一切顺利,您将看到以/ 4开头的授权码。 如果事情没有顺利,请检查右侧的错误消息。 现在你点击’刷新访问令牌’。 复制刷新令牌……它将以/ 1开始…

  5. 现在,您始终可以获得访问令牌! 这是如何:

     $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将包含两个时间戳,即initiateTimestampMsecvalidUntilTimestampMsec ,即订阅有效的时间。 两者都是加入到1970年1月1日的毫秒数!

我不知道在2012年,但在2015年你不应该手动执行任何这些步骤。 我很难find文档,所以我发布在这里,以防它帮助任何人。

  1. 出于安全原因,您应该只从服务器查询应用内购买,否则您无法信任购买过程的两个端点。

现在在服务器端(我认为如果你绝对需要,你仍然可以使用你的应用程序中的相同代码),请将google-api-services-androidpublisher客户端库包含到您的项目中(请参阅https://developers.google.com / api-client-library / java / apis / androidpublisher / v1 )

如您所述,您需要一个带有P12文件的服务帐户(客户端库只接受P12文件)。

然后,以下代码将validation并很好地获取购买信息:

  HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); JsonFactory jsonFactory = new JacksonFactory(); List scopes = new ArrayList(); 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客户端身份validation的信息,请访问: https : //developers.google.com/identity/protocols/OAuth2ServiceAccount

我可能会误解您的问题,但我认为您没有理由使用您引用的链接来获取Android应用的应用内结算function。 这个页面更有帮助:

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); } } 

由于您有一个应用程序可以调用的Web服务,我建议您将私钥安全地存储在服务器上。 您应该尽可能多地将应用程序内容移动到服务调用中,请参阅此链接 。 我已经实现了应用内订阅,但是在此部分API出来之前。 我必须自己进行注册和安全validation,但看起来这个API使用OAuth为您完成大部分工作,尽管看起来您仍然负责存储订阅请求/validation。

在谈到将JWT与现有库签名时,它们似乎确实为您提供了到java库,Python库和PHP库的链接 – 它取决于您的Web服务或服务器组件的编写方式(我的是C#,所以我使用RSACryptoServiceProvider来validation签名购买。 他们使用JSON对象进行实际的数据传输。

如果有人对接受的post最后一步(#7)有问题,我发现?access_token=工作而不是?accessToken=

太糟糕的堆栈溢出不会让我直接向线程发表评论……