• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Golang服务端对接Google Play结算系统订阅

武飞扬头像
JackieLeeee
帮助1

Google订阅

公司产品需要需对Google订阅,查了很多资料和相关文档,最终总结出以下内容。如果本文中存在任何不准确的地方,请不吝指出,我会尽快改正。
Google相关文档:

  1. 销售订阅内容
  2. 实时开发者通知参考
  3. Google Play Android Developer API
  4. 测试您的集成

1. 配置

  1. 应用配置页,点击创收设置→商品→订阅,给对应的应用新增订阅内容基础方案
  2. 前往API和服务,点击凭据,点击创建凭据,选择服务账号,填充相关信息创建一个服务账号
  3. Pub/Sub配置页,创建Pub/Sub主题和订阅
  4. 在对应主题中,给谷歌-play-developer-notifications@system.gserviceaccount.com添加Pub/Sub Publisher权限,一定是这个账号,这个是Google官方的服务账号,别搞错了,只有给它授权了才能发送商品订阅的消息到对应主题。同时在订阅处,给之前的服务账号授权Pub/Sub Subscriber
  5. IAM处,给之前的服务账号授予Viewer的角色。
  6. 前往Play管理中心,点击 设置→API权限→服务账号,在之前创建的服务账号旁点击查看Play管理中心权限,在应用权限上配置对应应用的权限,并在财务数据→查看财务数据打勾
  7. 前往Play管理中心,点击设置→API权限→API,启用Google Play Android Developer API。前往Google Play Android Developer API配置页,点击凭据,在下方的服务账号,找到之前创建的服务账号,点击修改进入到修改页面,点击密钥,再点击添加密钥→创建新密钥,选择JSON,点击创建,保管好这份JSON文件,服务端调用API时需要使用这份文件中的配置来初始化Client。
  8. 回到应用配置页,找到对应的应用,点击创收设置,配置发送通知的主题名称,可以点击发送测试通知。如果是推送订阅,我们配置的端点地址将会收到通知;如果是拉取订阅,我们可以在Pub/Sub配置页找到对应的订阅进行消息拉取。

2. 相关枚举介绍

2.1 谷歌回调一次性购买通知类型

参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference#one-time

通知类型 枚举值 说明
ONE_TIME_PRODUCT_PURCHASED 1 用户成功购买了一次性商品。
ONE_TIME_PRODUCT_CANCELED 2 用户已取消待处理的一次性商品购买交易。
// OneTimeProductNotificationType 谷歌回调一次性购买通知类型
// 参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference#one-time
type OneTimeProductNotificationType int

const (
	OneTimeProductNotificationTypePurchased OneTimeProductNotificationType = iota   1
	OneTimeProductNotificationTypeCanceled
)

2.2 谷歌回调订阅通知类型

参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference#sub

通知类型 枚举值 说明
SUBSCRIPTION_RECOVERED 1 恢复订阅。从账号保留状态恢复订阅。
SUBSCRIPTION_RENEWED 2 续订
SUBSCRIPTION_CANCELED 3 订阅取消。指的是用户手动进行的订阅取消操作。
SUBSCRIPTION_PURCHASED 4 新订阅
SUBSCRIPTION_ON_HOLD 5 订阅已进入帐号保留状态。一般是用户的付款信息存在问题且已经任何关联的宽限期都结束时发生的。
SUBSCRIPTION_IN_GRACE_PERIOD 6 订阅已进入宽限期。宽限期指的是订阅周期结束之后的一段时间内提供的额外时间,可选是否启用。
SUBSCRIPTION_RESTARTED 7 到期之前恢复订阅
SUBSCRIPTION_PRICE_CHANGE_CONFIRMED 8 用户已成功确认订阅价格变动。表示业务方对订阅价格进行了更改,并且用户已经确认接受新价格。
SUBSCRIPTION_DEFERRED 9 续订时间延期。指的是订阅到期前,由于付款方式问题等原因导致续订付款失败。
SUBSCRIPTION_PAUSED 10 订阅已暂停。表示用户已经暂停了订阅,可选是否启用。
SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED 11 订阅暂停计划已更改。表示用户已经更改了暂停订阅的计划,依赖暂停功能启用。
SUBSCRIPTION_REVOKED 12 订阅撤销。系统出于各种原因撤消用户的订阅,包括服务的主动调接口或购买交易被退款等。
SUBSCRIPTION_EXPIRED 13 订阅过期
// SubscriptionNotificationType 谷歌回调订阅通知类型
// 参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference#sub
type SubscriptionNotificationType int

func (s SubscriptionNotificationType) ToInt() int {
	return int(s)
}

const (
SubscriptionNotificationTypeRecovered            SubscriptionNotificationType = iota   1 // 从账号保留状态恢复订阅
	SubscriptionNotificationTypeRenewed                                                      // 续订
	SubscriptionNotificationTypeCanceled                                                     // 订阅取消 指的是用户手动进行的订阅取消操作
	SubscriptionNotificationTypePurchased                                                    // 新订阅
	SubscriptionNotificationTypeAccountHold                                                  // 订阅已进入帐号保留状态,一般是用户的付款信息存在问题且已经任何关联的宽限期都结束时发生的。
	SubscriptionNotificationTypeGracePeriod                                                  // 订阅已进入宽限期。宽限期指的是订阅周期结束之后的一段时间内提供的额外时间。(可选是否启用)
	SubscriptionNotificationTypeRestarted                                                    // 处理到期之前恢复订阅
	SubscriptionNotificationTypePriceChangeConfirmed                                         // 用户已成功确认订阅价格变动,表示业务方对订阅价格进行了更改,并且用户已经确认接受新价格。
	SubscriptionNotificationTypeDeferred                                                     // 续订时间延期 指的是订阅到期前,由于付款方式问题等原因导致续订付款失败
	SubscriptionNotificationTypePaused                                                       // 订阅已暂停,表示用户已经暂停了订阅。(可选是否启用)
	SubscriptionNotificationTypePauseScheduleChanged                                         // 订阅暂停计划已更改,表示用户已经更改了暂停订阅的计划。(依赖暂停功能启用)
	SubscriptionNotificationTypeRevoked                                                      // 订阅撤销 系统出于各种原因撤消用户的订阅,包括服务的主动调接口或购买交易被退款等
	SubscriptionNotificationTypeExpired                                                      // 订阅过期。
)
学新通

2.3 订阅确认状态

参考文档:https://developers.谷歌.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2?hl=zh-cn#AcknowledgementState

通知类型 枚举值 说明
ACKNOWLEDGEMENT_STATE_UNSPECIFIED ACKNOWLEDGEMENT_STATE_UNSPECIFIED 未指定的确认状态
ACKNOWLEDGEMENT_STATE_PENDING ACKNOWLEDGEMENT_STATE_PENDING 订阅尚未确认
ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED 订阅已确认
// AcknowledgementState 订阅的确认状态
// 参考文档:https://developers.谷歌.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2?hl=zh-cn#AcknowledgementState
type AcknowledgementState string

func (g AcknowledgementState) String() string {
	return string(g)
}

const (
	AcknowledgementStateUnspecified  AcknowledgementState = "ACKNOWLEDGEMENT_STATE_UNSPECIFIED"  // 未指定的确认状态
	AcknowledgementStatePending      AcknowledgementState = "ACKNOWLEDGEMENT_STATE_PENDING"      // 订阅尚未确认
	AcknowledgementStateAcknowledged AcknowledgementState = "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED" // 订阅已确认
)

2.4 订阅状态

参考文档:https://developers.谷歌.cn/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2?hl=zh-cn#SubscriptionState

通知类型 枚举值 说明
SUBSCRIPTION_STATE_UNSPECIFIED SUBSCRIPTION_STATE_UNSPECIFIED 未指定订阅状态。
SUBSCRIPTION_STATE_PENDING SUBSCRIPTION_STATE_PENDING 订阅已创建,但在注册期间正在等待付款。在此状态下,所有商品都正在等待付款。
SUBSCRIPTION_STATE_ACTIVE SUBSCRIPTION_STATE_ACTIVE 订阅处于有效状态。- (1) 如果订阅是自动续订方案,则至少有一个项目已自动续订且未过期。- (2) 如果订阅是预付费方案,至少有一项不会过期。
SUBSCRIPTION_STATE_PAUSED SUBSCRIPTION_STATE_PAUSED 订阅已暂停。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都会处于暂停状态。
SUBSCRIPTION_STATE_IN_GRACE_PERIOD SUBSCRIPTION_STATE_IN_GRACE_PERIOD 订阅处于宽限期。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都处于宽限期。
SUBSCRIPTION_STATE_ON_HOLD SUBSCRIPTION_STATE_ON_HOLD 订阅处于暂停状态(已暂停)。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都会处于保全状态。
SUBSCRIPTION_STATE_CANCELED SUBSCRIPTION_STATE_CANCELED 订阅已取消,但尚未到期。仅当订阅是自动续订方案时,这个状态才可用。所有内容的 autoRenewEnabled 都设为 false。
SUBSCRIPTION_STATE_EXPIRED SUBSCRIPTION_STATE_EXPIRED 订阅已过期。所有项的过期时间均为过去时间。
// GoogleSubscriptionState 谷歌订阅状态
// 参考文档:https://developers.谷歌.cn/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2?hl=zh-cn#SubscriptionState
type GoogleSubscriptionState string

func (g GoogleSubscriptionState) String() string {
	return string(g)
}

const (
	GoogleSubscriptionStateUnspecified   GoogleSubscriptionState = "SUBSCRIPTION_STATE_UNSPECIFIED"     // 未指定订阅状态。
	GoogleSubscriptionStatePending       GoogleSubscriptionState = "SUBSCRIPTION_STATE_PENDING"         // 订阅已创建,但在注册期间正在等待付款。在此状态下,所有商品都正在等待付款。
	GoogleSubscriptionStateActive        GoogleSubscriptionState = "SUBSCRIPTION_STATE_ACTIVE"          // 订阅处于有效状态。- (1) 如果订阅是自动续订方案,则至少有一个项目已自动续订且未过期。- (2) 如果订阅是预付费方案,至少有一项不会过期。
	GoogleSubscriptionStatePaused        GoogleSubscriptionState = "SUBSCRIPTION_STATE_PAUSED"          // 订阅已暂停。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都会处于暂停状态。
	GoogleSubscriptionStateInGracePeriod GoogleSubscriptionState = "SUBSCRIPTION_STATE_IN_GRACE_PERIOD" // 订阅处于宽限期。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都处于宽限期。
	GoogleSubscriptionStateOnHold        GoogleSubscriptionState = "SUBSCRIPTION_STATE_ON_HOLD"         // 订阅处于暂停状态(已暂停)。仅当订阅是自动续订方案时,这个状态才可用。在此状态下,所有内容都会处于保全状态。
	GoogleSubscriptionStateCanceled      GoogleSubscriptionState = "SUBSCRIPTION_STATE_CANCELED"        // 订阅已取消,但尚未到期。仅当订阅是自动续订方案时,这个状态才可用。所有内容的 autoRenewEnabled 都设为 false。
	GoogleSubscriptionStateExpired       GoogleSubscriptionState = "SUBSCRIPTION_STATE_EXPIRED"         // 订阅已过期。所有项的过期时间均为过去时间。
)
学新通

3. 相关库及其使用

3.1 获取官方库

go get 谷歌.golang.org/api/androidpublisher/v3

3.2 初始化service

ctx := context.WithValue(context.Background(), oauth2.HTTPClient, cli)
conf, err := 谷歌.JWTConfigFromJSON(jsonKey, androidpublisher.AndroidpublisherScope)
if err != nil {
    return
}

service, err = androidpublisher.NewService(ctx, option.WithHTTPClient(conf.Client(ctx)))
if err != nil {
    return
}

3.3 查询订阅信息v1

参考文档https://developers.谷歌.cn/android-publisher/api-ref/rest/v3/purchases.subscriptions/get?hl=zh-cn

subscriptionInfoV1, err = androidpublisher.NewPurchasesSubscriptionsService(handler.androidPublisherService).Get(packageName, subscriptionId, token).Context(handler.ctx).Do()
if err != nil {
    return
}

3.4 查询订阅信息v2

参考文档https://developers.谷歌.cn/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2/get?hl=zh-cn

subscriptionInfoV2, err = androidpublisher.NewPurchasesSubscriptionsv2Service(handler.androidPublisherService).Get(packageName, token).Context(handler.ctx).Do()
if err != nil {
    return
}

3.5 确认订阅

参考文档https://developers.谷歌.cn/android-publisher/api-ref/rest/v3/purchases.subscriptions/acknowledge?hl=zh-cn

err = handler.androidPublisherService.Purchases.Subscriptions.Acknowledge(packageName,subscriptionId,purchaseToken,&androidpublisher.SubscriptionPurchasesAcknowledgeRequest{},).Do()
if err != nil {
    return
}

3.6 校验回调身份

参考文档https://cloud.谷歌.com/pubsub/docs/push?hl=zh-cn#validate_tokens

authHeader := r.Header.Get("Authorization")
if authHeader == "" || len(strings.Split(authHeader, " ")) != 2 {
    err = errors.New("missing Authorization header")
    return
}
token := strings.Split(authHeader, " ")[1]
v, err := idtoken.NewValidator(handler.ctx, option.WithHTTPClient(&http.Client{
	Timeout: time.Second * time.Duration(10),
}))
if err != nil {
    return
}
payload, err := v.Validate(handler.ctx, token, "my_endpoint")
if err != nil {
    return
}
if payload.Issuer != "accounts.谷歌.com" && payload.Issuer != "https://accounts.谷歌.com" {
    err = errors.New("wrong issuer")
    return
}
if payload.Claims["email"] != "ClientEmail" || payload.Claims["email_verified"] != true {
    err = errors.New("unexpected email identity")
    return
}
学新通

3.7 回调信息结构

参考文档1https://developer.android.com/谷歌/play/billing/rtdn-reference?hl=zh-cn#encoding

参考文档2https://developer.android.com/谷歌/play/billing/rtdn-reference#json_specification

// GoogleNotification 谷歌回调信息结构体
// 参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference?hl=zh-cn#encoding
type GoogleNotification struct {
    Message      GoogleNotificationMessage `json:"message"`
    Subscription string                    `json:"subscription"`
}

type GoogleNotificationMessage struct {
    Data        string    `json:"data"`
    MessageID   string    `json:"messageId"`
    PublishTime time.Time `json:"publishTime"`
}

// DeveloperNotification 谷歌回调信息荷载
// 参考文档:https://developer.android.com/谷歌/play/billing/rtdn-reference#json_specification
type DeveloperNotification struct {
    Version                    string                      `json:"version"`
    PackageName                string                      `json:"packageName"`
    EventTimeMillis            string                      `json:"eventTimeMillis"`
    SubscriptionNotification   *SubscriptionNotification   `json:"subscriptionNotification,omitempty"`
    OneTimeProductNotification *OneTimeProductNotification `json:"oneTimeProductNotification,omitempty"`
    TestNotification           *TestNotification           `json:"testNotification,omitempty"`
}

// SubscriptionNotification 谷歌回调订阅通知信息结构体
type SubscriptionNotification struct {
    Version          string                            `json:"version"`
    NotificationType enum.SubscriptionNotificationType `json:"notificationType,omitempty"`
	  PurchaseToken    string                            `json:"purchaseToken,omitempty"`
	  SubscriptionID   string                            `json:"subscriptionId,omitempty"`
}

// OneTimeProductNotification 谷歌回调一次性购买通知信息结构体
type OneTimeProductNotification struct {
    Version          string                              `json:"version"`
    NotificationType enum.OneTimeProductNotificationType `json:"notificationType,omitempty"`
    PurchaseToken    string                              `json:"purchaseToken,omitempty"`
    SKU              string                              `json:"sku,omitempty"`
}

// TestNotification 通过Google Play开发者控制台发送的通知信息结构体
type TestNotification struct {
    Version string `json:"version"`
}
学新通

4. 如何测试

  1. 测试的谷歌账号必须绑定过银行卡或者信用卡,否则无法使用

  2. 将对应的谷歌账号设置为许可测试人员,官方文档:使用应用许可来测试应用内购结算功能

  3. 测试订阅在续订速度上比实际订阅快,最多可续订六次。相关文档:测试订阅专用功能

    基于时间的订阅功能

    功能 测试期
    购买交易确认 5 分钟
    免费试用 3 分钟
    初次体验价周期 与订阅测试周期相同
    宽限期(3 天和 7 天) 5 分钟
    帐号保留功能 10 分钟
    暂停(1 个月) 5 分钟
    暂停(2 个月) 10 分钟
    暂停(3 个月) 15 分钟

    续订期

    生产订阅期 测试订阅续订
    1 周 5 分钟
    1 个月 5 分钟
    3 个月 10 分钟
    6 个月 15 分钟
    1 年 30 分钟

5. 注意事项

  1. 订阅暂停功能如不需要可以在应用配置页,找到对应的应用,点击创收设置,在上方订阅设置处将其关闭。
  2. 应用配置页,点击创收设置→商品→订阅,可进行宽限期的设置,如不需要可直接设置成无宽限期。
  3. 在重新订阅时,是区分到期之前恢复到期之后重新订阅的,到期之后重新订阅会要求用户打开应用,而处理此类购买交易的方式与处理其他应用外购买相同,也就是说,客户端需要监听并通知到后端发生了重新订阅这个事件。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfaihi
系列文章
更多 icon
同类精品
更多 icon
继续加载