Google 钱包卡券开发流程
Google Wallet API 提供了一组预定义的卡券类型,这些卡券类型针对特定用例(例如礼品卡、登机牌、活动门票等)进行了优化。此外,还有一种通用卡券类型,适用于无法使用特定卡券类型的用例。
本文旨在帮助您熟悉使用 Google Wallet API 创建和签发卡券所需的基本步骤。您可以通过多种方式完成下文详述的某些步骤,但大体上讲,所有卡券类型都是按照相同的基本开发流程创建的。
如需查看卡券创建的详细演示,请参阅适用于网页、电子邮件和短信或 Android 应用的指南。
![](https://developers.google.cn/static/wallet/images/ticket-class.png?authuser=9&%3Bhl=da&hl=da)
1. 创建卡券类
用途
卡券类可定义一组在多个卡券中通用的属性,类似于模板。例如,如果您要签发活动的门票,Passs 类将定义所有门票相同的字段,例如活动名称、日期和时间。
您发出的每个卡券都必须引用一个卡券类。您还必须为创建的每个卡券类分配一个唯一 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" } } } }
![](https://developers.google.cn/static/wallet/images/ticket-object.png?authuser=9&%3Bhl=da&hl=da)
2. 创建卡券对象
用途
卡券对象定义将发放给特定用户的唯一卡券的属性。例如,活动门票的卡券对象会定义特定门票独有的字段,例如该门票的座位号或二维码。
创建卡券对象后,Google Wallet API 会存储新的卡券,并将其与您的发卡机构账号相关联。这个存储的卡券由卡券对象的唯一属性和相关卡券类的模板属性构成。
您还必须为每个卡券对象分配一个唯一 ID,用于在发布卡券时用于引用此 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": "" } }
![](https://developers.google.cn/static/wallet/images/ticket-jwt.png?authuser=9&%3Bhl=da&hl=da)
3. 将卡券编码到 JSON 网络令牌 (JWT) 中
用途
为了向用户签发卡券,Passs 类和卡券对象必须在 JSON Web 令牌 (JWT) 中进行编码。JWT 格式是一种通用的开放式标准,用于表示两方之间的声明。如果使用 Google Wallet API 签发卡券,JWT 将用于发送声明,声明用户有权访问与您的发卡机构账号相关联的特定卡券。
将 JWT 发送到 Google Wallet API 时,编码数据将用于标识特定的卡券并将其颁发给用户。如果卡券已发放,这些数据还允许 Google Wallet API 识别该卡券是重复卡券,这样它就不会多次添加到用户的 Google 钱包中。
具体做法
JWT 是根据 JWT 规范用 JSON 格式定义的。要定义一个 JWT 以便使用 Google Wallet API 签发卡券,您需要在 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" } ] } }
![](https://developers.google.cn/static/wallet/images/ticket-jwt-signed.png?authuser=9&%3Bhl=da&hl=da)
4. 使用您的凭据为 JWT 签名
用途
所有发送至 Google Wallet API 以颁发卡券的 JWT 都必须使用您之前在 Google Wallet Business Console 中提供的凭据进行签名。签名功能使用您的凭据对 JWT 进行加密,以便确保您的卡券安全无虞,并允许 Google Wallet API 进行身份验证,确保在其中编码的卡券详细信息有效且与您的发卡机构账号相关联。
具体做法
Google 钱包客户端库和 Android SDK 提供了便捷的方法来签署您的 JWT。还有许多开源库可供您选择处理复杂代码签名的事务。
对于使用 Google Wallet REST API 颁发卡券的用户,JWT 将使用 Google Cloud 服务账号密钥进行签名。对于使用 Google Wallet Android SDK 的用户,SDK 会自动使用应用签名证书的 SHA-1 指纹来为 JWT 签名。
为了保护您的凭据,应仅在您的服务器上或使用 Google Wallet Android SDK 在应用中对 JWT 进行签名。
显示示例代码签名
Java
// Create the JWT as a HashMap object HashMapclaims = 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')
![](https://developers.google.cn/static/wallet/images/ticket-add-to-wallet.png?authuser=9&%3Bhl=da&hl=da)
5. 使用“添加到 Google 钱包”按钮或链接发放卡券
用途
创建已签名的 JWT 后,您就可以向 Google 钱包用户签发卡券了!为此,系统会向用户显示“添加到 Google 钱包”按钮,按钮或链接。当用户点击该按钮或超链接时,已签名的 JWT 会发送到 Google Wallet API,然后由 Google Wallet API 使用您保存的凭据对其进行解密。JWT 签名通过身份验证后,系统就会将卡券发放给用户,以保存到用户的 Google 钱包中。
具体做法
要创建“添加到 Google 钱包”按钮,请使用 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) } }
![](https://developers.google.cn/static/wallet/images/ticket-enduser-view.png?authuser=9&%3Bhl=da&hl=da)
6. 在 Google 钱包中查看
用户保存签发的卡券后,该卡券将与保存的任何其他卡券一起显示在用户的 Google 钱包应用中。
在 JWT 中创建卡券对象和卡券类
您可以使用 Google Wallet REST API 或 Android SDK 提前创建卡券类和卡券对象。创建完毕后,系统会利用这些卡券 ID 来发布卡券。
或者,您也可以“即时”创建卡券类和卡券对象。在此方法中,Google Wallet API 会在使用“添加到 Google 钱包”发送已签名的 JWT 时创建卡券类和卡券对象按钮或链接。
例如,以下代码展示了使用 payload.eventTicketClasses
和 payload.eventTicketObjects
属性定义的新卡券类和卡券对象的 JWT。请注意,这些属性是数组,因此可以接受一个或多个卡券类或卡券对象。您也可以在 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": "" } }] } }