Google 钱包卡券开发流程

Google Wallet API 提供了一组预定义的卡券类型,这些卡券类型针对特定用例(例如礼品卡、登机牌、活动门票等)进行了优化。此外,还有一种通用卡券类型,适用于无法使用特定卡券类型的用例。

本文旨在帮助您熟悉使用 Google Wallet API 创建和签发卡券所需的基本步骤。您可以通过多种方式完成下文详述的某些步骤,但大体上讲,所有卡券类型都是按照相同的基本开发流程创建的。

如需查看卡券创建的详细演示,请参阅适用于网页、电子邮件和短信Android 应用的指南。

用途

卡券类定义了一组在多个卡券中通用的属性,类似于模板。例如,如果您要签发活动门票,卡券类会定义在所有门票中相同的字段,如活动名称、日期和时间。

您发出的每个卡券都必须引用一个卡券类。您还必须为自己创建的每个卡券类分配一个唯一 ID,用于在创建卡券时引用此 ID。

具体做法

卡券类以 JSON 格式定义,可通过 Google Wallet REST API、Android SDK 或 Google 钱包商家控制台创建。

显示卡券类示例

{
  "id": "ISSUER_ID.EVENT_CLASS_ID",
  "issuerName": "[TEST ONLY] Heraldic Event",
  "localizedIssuerName": {
    "defaultValue": {
      "language": "en-US",
      "value": "[TEST ONLY] Heraldic Event"
    }
  },
  "logo": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "LOGO_IMAGE_DESCRIPTION"
      }
    }
  },
  "eventName": {
    "defaultValue": {
      "language": "en-US",
      "value": "Google Live"
    }
  },
  "venue": {
    "name": {
      "defaultValue": {
        "language": "en-US",
        "value": "Shoreline Amphitheater"
      }
    },
    "address": {
      "defaultValue": {
        "language": "en-US",
        "value": "ADDRESS_OF_THE_VENUE"
      }
    }
  },
  "dateTime": {
    "start": "2023-04-12T11:30"
  },
  "reviewStatus": "UNDER_REVIEW",
  "hexBackgroundColor": "#264750",
  "heroImage": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "HERO_IMAGE_DESCRIPTION"
      }
    }
  }
}
    

用途

卡券对象用于定义将签发给特定用户的唯一卡券的属性。例如,活动门票的卡券对象定义了特定门票独有的字段,如该门票的座位号或二维码。

卡券对象创建后,Google Wallet API 会存储一个新卡券,并将其与您的发卡机构帐号关联。此存储的卡券是卡券对象的唯一属性和关联的卡券类的模板属性的组合。

您还必须为每个卡券对象分配一个唯一 ID,用于在发放卡券时引用该对象。

具体做法

卡券对象采用 JSON 格式定义,可通过 Google Wallet REST API 或 Android SDK 创建。

显示卡券对象示例

{
  "id": "ISSUER_ID.OBJECT_ID",
  "classId": "ISSUER_ID.EVENT_CLASS_ID",
  "state": "ACTIVE",
  "seatInfo": {
    "seat": {
      "defaultValue": {
        "language": "en-us",
        "value": "5"
      }
    },
    "row": {
      "defaultValue": {
        "language": "en-us",
        "value": "G"
      }
    },
    "section": {
      "defaultValue": {
        "language": "en-us",
        "value": "40"
      }
    },
    "gate": {
      "defaultValue": {
        "language": "en-us",
        "value": "3A"
      }
    }
  },
  "barcode": {
    "type": "QR_CODE",
    "value": "BARCODE_VALUE",
    "alternateText": ""
  }
}
    

用途

如需向用户颁发卡券,卡券类和卡券对象必须编码为 JSON Web 令牌 (JWT)。JWT 格式是表示两方之间声明的通用开放标准。如果是使用 Google Wallet API 签发凭证,则 JWT 用于发送一项声明,以表明用户有权访问与签发者帐号关联的特定凭证。

将 JWT 发送到 Google Wallet API 时,编码数据将用于标识特定卡券并将其发放给用户。如果卡券已经发放,Google Wallet API 还可通过这些数据识别卡券是否重复,以免将其多次添加到用户的 Google 钱包。

具体做法

JWT 是根据 JWT 规范,以 JSON 格式定义。如需定义用于通过 Google Wallet API 签发卡券的 JWT,请在 JWT 的 payload 属性中提供与您要签发的卡券相关的信息。

显示示例 JWT

{
  "iss": "issuer@example.com",
  "aud": "google",
  "typ": "savetowallet",
  "iat": 1696877738,
  "origins": [
    "www.example.com"
  ],
  "payload": {
    "eventTicketObjects": [
      {
        "id": "ISSUER_ID.LOYALTY_OBJECT_SUFFIX"
      }
    ]
  }
}
    

用途

所有发送到 Google Wallet API 以颁发卡券的 JWT 都必须使用您之前在 Google Wallet Business Console 中提供的凭据签名。签名功能会使用您的凭据来加密 JWT,以确保您的卡券保持安全,并允许 Google Wallet API 进行身份验证,确认编码到的卡券详细信息有效且与您的发卡机构帐号相关联。

具体做法

Google 电子钱包客户端库和 Android SDK 提供了对 JWT 进行签名的便捷方法。还有许多开源库可供您选择处理代码签名的复杂性。

对于使用 Google Wallet REST API 发放卡券的用户,JWT 会使用 Google Cloud 服务帐号密钥进行签名。对于使用 Google 钱包 Android SDK 的用户,该 SDK 会自动使用应用签名证书的 SHA-1 指纹处理 JWT 签名。

为了保护您的凭据,请仅在您的服务器上为 JWT 签名,或在您的应用中使用 Google 钱包 Android SDK。

显示示例代码签名

Java

  // Create the JWT as a HashMap object
  HashMap claims = new HashMap();
  claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
  claims.put("aud", "google");
  claims.put("origins", Arrays.asList("www.example.com"));
  claims.put("typ", "savetowallet");

  // Create the Google Wallet payload and add to the JWT
  HashMap payload = new HashMap();
  payload.put("eventTicketObjects", Arrays.asList(newObject));
  claims.put("payload", payload);

  // Google Cloud service account credentials are used to sign the JWT
  Algorithm algorithm =
      Algorithm.RSA256(
          null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
  String token = JWT.create().withPayload(claims).sign(algorithm);
        

Node.JS

  // Create the JWT claims
  let claims = {
    iss: this.credentials.client_email,
    aud: 'google',
    origins: ['www.example.com'],
    typ: 'savetowallet',
    payload: {
      eventTicketObjects: [newObject]
    },
  };

  // The service account credentials are used to sign the JWT
  let token = jwt.sign(claims, this.credentials.private_key, { algorithm: 'RS256' });
        

Python

  # Create the JWT claims
  claims = {
      'iss': self.credentials.service_account_email,
      'aud': 'google',
      'origins': ['www.example.com'],
      'typ': 'savetowallet',
      'payload': {
          # The listed classes and objects will be created
          'eventTicketObjects': [new_object]
      }
  }

  # The service account credentials are used to sign the JWT
  signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
  token = jwt.encode(signer, claims).decode('utf-8')
        

用途

创建签名的 JWT 后,您就可以向 Google 钱包用户颁发卡券了!为此,请向用户显示“添加到 Google 钱包”按钮或链接。当用户点击该按钮或超链接时,系统会将已签名的 JWT 发送到 Google Wallet API,后者随后会使用您保存的凭据对其进行解密。JWT 签名通过身份验证后,系统会向用户发送该卡券,以将其保存在用户的 Google 钱包中。

具体做法

要为 Android 应用创建“Add to Google Wallet”按钮,请使用 Google Wallet Android SDK,其中提供了生成该按钮的方法。对于所有其他平台,包括网络、电子邮件和短信,请创建格式为 https://pay.google.com/gp/v/save/<signed_jwt> 的超链接。如果可能,最好通过“添加到 Google 钱包”按钮将此链接提供给用户。

如需详细了解如何使用“添加到 Google 钱包”按钮,请参阅 Google Wallet API 品牌推广指南

显示示例代码

  https://pay.google.com/gp/v/save/<signed_jwt>
        

Android SDK

  private lateinit var walletClient: PayClient
  private val addToGoogleWalletRequestCode = 1000
  private lateinit var addToGoogleWalletButton: View

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    walletClient = Pay.getClient(this)
    addToGoogleWalletButton.setOnClickListener {
      walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)
    }
  }
        

用户保存已发放的卡券后,此卡券将与其保存的任何其他卡券一起显示在他们的 Google 钱包应用中。

在 JWT 中创建卡券对象和卡券类

卡券类和卡券对象可以使用 Google Wallet REST API 或 Android SDK 提前创建。创建后,系统会使用这些卡券通过引用其 ID 来发放卡券。

或者,您也可以“及时”创建卡券类和卡券对象,方法是将其 JSON 直接嵌入到用于向用户颁发卡券的 JWT 中。在此方法中,当使用“添加到 Google 钱包”按钮或链接发送已签名的 JWT 时,Google Wallet API 会创建卡券类和卡券对象。

例如,下面显示的 JWT 具有使用 payload.eventTicketClassespayload.eventTicketObjects 属性定义的新卡券类和卡券对象。请注意,这些属性是数组,因此它们可以接受一个或多个卡券类或卡券对象。您还可以在 JWT 中指定通过 ID 引用现有卡券类的新卡券对象。

显示示例 JWT

  {
    "iss": "issuer@example.com",
    "aud": "google",
    "typ": "savetowallet",
    "iat": 1696877738,
    "origins": [
      "www.example.com"
    ],
    "payload": {
      "eventTicketClasses": [{
        "id": "ISSUER_ID.EVENT_CLASS_ID",
        "issuerName": "[TEST ONLY] Heraldic Event",
        "localizedIssuerName": {
          "defaultValue": {
            "language": "en-US",
            "value": "[TEST ONLY] Heraldic Event"
          }
        },
        "logo": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "LOGO_IMAGE_DESCRIPTION"
            }
          }
        },
        "eventName": {
          "defaultValue": {
            "language": "en-US",
            "value": "Google Live"
          }
        },
        "venue": {
          "name": {
            "defaultValue": {
              "language": "en-US",
              "value": "Shoreline Amphitheater"
            }
          },
          "address": {
            "defaultValue": {
              "language": "en-US",
              "value": "ADDRESS_OF_THE_VENUE"
            }
          }
        },
        "dateTime": {
          "start": "2023-04-12T11:30"
        },
        "reviewStatus": "UNDER_REVIEW",
        "hexBackgroundColor": "#264750",
        "heroImage": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "HERO_IMAGE_DESCRIPTION"
            }
          }
        }
      }],
      "eventTicketObjects": [{
        "id": "ISSUER_ID.OBJECT_ID",
        "classId": "ISSUER_ID.EVENT_CLASS_ID",
        "state": "ACTIVE",
        "seatInfo": {
          "seat": {
            "defaultValue": {
              "language": "en-us",
              "value": "5"
            }
          },
          "row": {
            "defaultValue": {
              "language": "en-us",
              "value": "G"
            }
          },
          "section": {
            "defaultValue": {
              "language": "en-us",
              "value": "40"
            }
          },
          "gate": {
            "defaultValue": {
              "language": "en-us",
              "value": "3A"
            }
          }
        },
        "barcode": {
          "type": "QR_CODE",
          "value": "BARCODE_VALUE",
          "alternateText": ""
        }
      }]
    }
  }