google订阅支付服务端

2,830 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

1. 通用订阅

1.1.接收google的返回json

```php
{
    "message":{
        "attributes":{
            "key":"value"
        },
        "data":"eyAidmVyc2lvbiI6IHN0cmluZywgInBhY2thZ2VOYW1lIjogc3RyaW5nLCAiZXZlbnRUaW1lTWlsbGlzIjogbG9uZywgIm9uZVRpbWVQcm9kdWN0Tm90aWZpY2F0aW9uIjogT25lVGltZVByb2R1Y3ROb3RpZmljYXRpb24sICJzdWJzY3JpcHRpb25Ob3RpZmljYXRpb24iOiBTdWJzY3JpcHRpb25Ob3RpZmljYXRpb24sICJ0ZXN0Tm90aWZpY2F0aW9uIjogVGVzdE5vdGlmaWNhdGlvbiB9",
        "messageId":"136969346945"
    },
    "subscription":"projects/myproject/subscriptions/mysubscription"
}
```

1.2. 解密data(base64)

```php
{
    "version":"1.0",
    "packageName":"com.some.thing",
    "eventTimeMillis":"1503349566168",
    "subscriptionNotification":{
        "version":"1.0",
        "notificationType":4,
        "purchaseToken":"PURCHASE_TOKEN",
        "subscriptionId":"my.sku"
    },
    "oneTimeProductNotification":{
        "version":"1.0",
        "notificationType":1,
        "purchaseToken":"PURCHASE_TOKEN",
        "sku":"my.sku"
    },
    "testNotification":{
        "version":"1.0"
    }
}
```

返回参数说明
subscriptionNotification(订阅相关)、oneTimeProductNotification(一次性购买相关)
testNotification(测试发布相关) 三个不会同时存在任意2个

> 参数名	说明
version	此通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。
packageName	与此通知相关的应用的软件包名称(例如“com.some.thing”)
eventTimeMillis	事件发生的时间戳,以从公元纪年开始计算的毫秒数表示
subscriptionNotification	与订阅相关,并且此字段包含与购买交易相关的其他信息
oneTimeProductNotification	与一次性购买相关,并且此字段包含与购买交易相关的其他信息
testNotification	与测试发布相关。这些只通过 Google Play 管理中心发送

subscriptionNotification说明
> 参数名	说明
version	此通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。
notificationType	int 订阅的 notificationType 可以参考下面的表
purchaseToken	购买订阅时向用户设备提供的令牌
subscriptionId	所购买订阅的 ID(例如“monthly001”)

notificationType说明
> SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消,在用户取消时发送。
SUBSCRIPTION_PURCHASED - 购买了新的订阅。
SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态(如果已启用)。
SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期(如果已启用)。
SUBSCRIPTION_RESTARTED - 用户已通过 Play > 帐号 > 订阅重新激活其订阅(需要选择使用订阅恢复功能)。
SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
SUBSCRIPTION_PAUSED - 订阅已暂停。
SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
SUBSCRIPTION_REVOKED - 用户在到期时间之前已撤消订阅。
SUBSCRIPTION_EXPIRED - 订阅已到期。

1.3. 根据解密后的内容去google接口做查询校验并发货(关键参数expiryTimeMillis)
根据解密后的内容去google接口做校验
[Google文档地址](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions/get?hl=zh-cn)
请求域名(Get/form):
> https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}

返回参数

```php

{
  "resource": {
    object (SubscriptionPurchase)
  }
}

{
  "kind": string,
  "startTimeMillis": string,
  "expiryTimeMillis": string,
  "autoResumeTimeMillis": string,
  "autoRenewing": boolean,
  "priceCurrencyCode": string,
  "priceAmountMicros": string,
  "introductoryPriceInfo": {
    object (IntroductoryPriceInfo)
  },
  "countryCode": string,
  "developerPayload": string,
  "paymentState": integer,
  "cancelReason": integer,
  "userCancellationTimeMillis": string,
  "cancelSurveyResult": {
    object (SubscriptionCancelSurveyResult)
  },
  "orderId": string,
  "linkedPurchaseToken": string,
  "purchaseType": integer,
  "priceChange": {
    object (SubscriptionPriceChange)
  },
  "profileName": string,
  "emailAddress": string,
  "givenName": string,
  "familyName": string,
  "profileId": string,
  "acknowledgementState": integer,
  "externalAccountId": string,
  "promotionType": integer,
  "promotionCode": string,
  "obfuscatedExternalAccountId": string,
  "obfuscatedExternalProfileId": string
}
```

1.4. 消耗该笔订单
[Google文档地址](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions/acknowledge?hl=zh-cn)
请求域名(Post/form)
>https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:acknowledge

2. 一次性订阅商品(消耗型商品缓慢支付)

说明

1.消耗型商品选择缓慢支付方式,Google服务端会走一次性订阅的回调

2.Google服务端通过input/json方式 回调给配置的地址

3.我们服务端收到google回调后 校验并发货,同时调用服务端消耗接口。

2.1.Google后台相关配置

1.创建主题。在google后台 (console.developers.google.com/apis) 选择应用-->左菜单选择Pub\Sub-->创建主题

2.为刚才新建的主题添加主账号,选择google服务器为推送消息服务商(google-play-developer-notifications@system.gserviceaccount.com) 点击刚才新建的主题-->在网页右侧有添加主账号按钮

3.在新建的主题下面添加订阅 选择新建好的主题-->点击旁边的多功能按钮(“:”)-->创建订阅-->选择传送类型为推送-->填写回调地址

4.在Google开发者后台绑定主题(Google Play Console : play.google.com/console/abo…) 打开GooglePlay管理中心-->选择您的应用-->下滑到创收-->选择创收设置-->滚动到实时开发者通知部分-->填写主题名(Topic name)(主题名即刚才新建的主题ID)

2.2.接收Google服务器回调并解析处理(base64)

1.Google服务器回调的json数据(需要选择input/json方式接收)
```php
{
    "message":{
        "data":"eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20uZGh0ei5maWdodGluZy50eiIsImV2ZW50VGltZU1pbGxpcyI6IjE2MzYwOTY3ODA3MTAiLCJvbmVUaW1lUHJvZHVjdE5vdGlmaWNhdGlvbiI6eyJ2ZXJzaW9uIjoiMS4wIiwibm90aWZpY2F0aW9uVHlwZSI6MSwicHVyY2hhc2VUb2tlbiI6ImdqZ2ptam1sYWNnYWtnZWNrZm1qaGhubi5BTy1KMU93bk9tWGc0VTg2SjFEOTFkMlNJQmFiTWRQTm9jYlhCWnpqYWpSWWxCcGJSeFg0X2tpYW9EVEpRMnJVNFMyYUtYQW5HUkp0ZTJBVjhiM1NraEF4RzcxZXdDcjVDUSIsInNrdSI6ImNvbS5kaHR6LmZpZ2h0aW5nLnR6MSJ9fQ==",
        "messageId":"2931105763628844",
        "message_id":"2931105763628844",
        "publishTime":"2021-11-05T07:19:41.009Z",
        "publish_time":"2021-11-05T07:19:41.009Z"
    },
    "subscription":"projects\/jinyoumobilegame-1429d\/subscriptions\/dhtz_ft"
}
```
2.用base64解析data
```php
{
    "version":"1.0",
    "packageName":"com.dhtz.fighting.tz",
    "eventTimeMillis":"1636098148511",
    "oneTimeProductNotification":{
        "version":"1.0",
        "notificationType":1,
        "purchaseToken":"mdclhokjpbfaiammjmjeoeoi.AO-J1OzIjbEAC5vbhPIN1R0E5PVZgFvLPrQHQlvuVxwLEgd4BC_S35KBQaBGX8DoisOh3p3a9iDSROuzuX4BLyZTXX2w4lrmfw",
        "sku":"com.dhtz.fighting.tz1"
    }
}
```

2.3 订单校验后做发货处理(发货之前可以到Google那边查询该订单情况)

Google文档地址 接口和具体传参(get/form): > androidpublisher.googleapis.com/androidpubl…

查询返回体
```php
{  
   "purchaseTimeMillis": "1636684861095",//以毫秒为单位购买产品的时间
   "purchaseState": 0,//订单的购买状态,0(已购买)1(取消)
   "consumptionState": 0,
   "developerPayload": "",//开发人员指定的字符串,其中包含有关订单的补充信息
   "orderId": "xxxxx",//与购买应用内商品关联的订单 ID
   "purchaseType": 0,//应用内商品的购买类型。仅当购买不是使用标准的应用内结算流程进行时才会设置
   "acknowledgementState": 1,//应用内产品的确认状态,0(尚未确认),1(已确认)
   "kind": "androidpublisher#productPurchase",//代表一个 productPurchase
   "obfuscatedExternalAccountId": "xxxxx",//客户端传入的
   "regionCode": "US"
}
```

2.4.调用Google消耗订单接口

Google文档地址 接口和具体传参(post/form)

> https://androidpublisher.googleapis.com/androidpublisher/v3/
applications/{packageName}/purchases/products/{productId}/tokens/{purchaseToken}:acknowledge?access_token={access_token}

响应结果为空则表示消耗成功 ,可以再次请求2.3接口查看acknowledgementState的值为1则表示消耗成功。[^1]