37

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

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

  1. 在 Google API 控制台中创建一个服务帐户。
  2. 保存给我的私钥(在哪里?肯定不在我的代码中/在设备上,如此示例代码所示)
  3. 使用适用于 Java 的 Google API 客户端库创建并使用私钥签署 JWT(如何?文档给了我这个,但那不是 Java 代码......我该怎么处理它?)
  4. 构造访问令牌请求,并获取对 API 的访问权限
  5. 应用程序现在可以向 API 发送GET请求,以查明用户是否有订阅
  6. 当访问令牌过期时,返回步骤 3。

另外,我有一个 Web 服务,虽然我对 Web 服务或 Web 服务编程一无所知......我只知道足够了解它可能需要在这里使用。

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

4

7 回答 7

44

事实证明,我的步骤不正确。我花了几个星期才弄清楚这一点,而且似乎没有在其他任何地方记录下来。别客气:

  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]。您可以将结果值保存在程序中;除非明确撤销,否则它永远不会过期。(此步骤由@BrianWhite 插入——见评论)确保您使用的是 POST。(由 Gintas 插入)

  5. https://accounts.google.com/o/oauth2/token在您的代码中,使用 BasicNameValuePairs "grant_type","refresh_token", "client_id",[YOUR CLIENT ID], "client_secret",[YOUR CLIENT SECRET],发送一个 HttpPost 请求"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]". 例如看这里

于 2012-09-25T20:40:19.657 回答
24

.NET 用户:我希望这个答案可以为某人省去很多悲伤。

正如@Christophe Fondacci 在 2015 年指出的那样,几年前公认的解决方案效果很好。

现在是2017 2020 年,这个过程变得更加容易和快捷

我的用例是验证应用内订阅,我的移动应用将订阅购买信息发送到我的 RESTful 服务器,该服务器反过来联系 Google 以验证订阅购买。

该策略是创建一个代表您操作的服务帐户。

  1. 登录到您的Google Play 开发控制台并单击您正在设置的应用程序。

  2. 访问设置-> API 访问

  3. Service Accounts下,点击Create Service Account按钮。

  4. 截至 2017 年 1 月,将出现一个对话框,其中包含有关设置服务帐户的说明。该对话框会将您带到 Google API 控制台;从那里,

    A) 单击创建服务帐户

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

C) 对于角色,只需选择一些内容 - 您可以稍后更改。

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

  1. 现在您已完成 #4,您将看到列出的新服务帐户;单击“授予访问权限”以启用它。

  2. 点击“查看权限”链接。您应该根据您的需要和 API 修改权限。

要验证应用内购买,请访问 Cog->Change Permissions 并启用全球“可见性”和“管理订单”权限。

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

  1. 从 Nuget [1]添加 Android Publisher 客户端库
    PM> Install-Package Google.Apis.AndroidPublisher.v3
  1. 将 P12 文件添加到项目根目录

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

  3. 实现这样的东西来测试你的访问和微调[1]

    using System.Threading.Tasks;
    using System.Security.Cryptography.X509Certificates;
    using Google.Apis.Services;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.AndroidPublisher.v3;
    ...
    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();
    }

祝你好运,希望这对某人有所帮助。

资料来源:

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

适用于 Google.Apis.AndroidPublisher.v3 的 .Net 客户端库[1]


更新于 2020 年 4 月 11 日 - Google.Apis.AndroidPublisher.v2 EOL'd,使用 Google.Apis.AndroidPublisher.v3。
于 2017-01-04T00:21:28.750 回答
10

如果您像我一样,并且想在PHP中执行此操作,那么这里是如何执行此操作的过程...感谢 Kalina 的回答,我只花了三天时间就弄清楚了它是如何工作的:)。

开始:

  1. 转到谷歌开发者控制台https://console.developers.google.com/并创建一个网络应用程序。将“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中填写范围。我在列表中找不到 Google Play Android Developer API,也许他们稍后会添加。点击AUTORIZE APIS。做下面的授权事情。

  4. Google oauth2 游乐场中,转到第 2 步交换令牌授权码。如果一切顺利,您将看到以 /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);
    

现在你有一个访问令牌万岁...... JSON 将如下所示:

"access_token" : "{the access token}",  "token_type" : "Bearer",  "expires_in" : 3600

最后,您可以向谷歌询问一些事情了!这是如何做到的:

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

于 2014-02-10T13:03:57.543 回答
6

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

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

现在在服务器端(如果您绝对需要,我认为您仍然可以在您的应用程序中使用相同的代码),将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

于 2015-11-13T00:10:53.347 回答
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);
    }
}
于 2012-09-14T18:49:20.943 回答
2

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

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

于 2017-07-26T03:41:11.523 回答
1

As you have a web service which your app can call, I would recommend storing your private key securely on your server. You should look to moving as much of the in-app stuff to service calls, as possible, see this link. I've implemented in-app subscription, but it was before this part of the API was out. I had to do my own registration and security verification but it looks like this API does most of that for you, using OAuth, although it looks like you are still responsible for storing the subscription request/verification.

Where it talks about signing your JWT's with an existing library, they do appear to provide you with links to a java library, a Python library and a PHP library - it depends what your web service or server component is written in (mine is C#, so I'm using RSACryptoServiceProvider) to verify signed purchases. They're using JSON objects for the actual transfer of data.

于 2012-09-23T14:19:45.810 回答