Google 錢包票證開發流程

Google Wallet API 提供一組預先定義的票證類型,已針對特定用途 (例如禮物卡、登機證、活動票券等) 進行最佳化。即使無法使用特定票證類型,也可使用一般票證類型。

本文將介紹使用 Google Wallet API 建立票證及核發票證所需的基本步驟。有很多方法可以完成下文所述的某些步驟,但整體來說,所有票證類型都是按照相同的基本開發流程建立。

如需建立票證的詳細逐步操作說明,請參閱 Google Wallet REST APIAndroid SDK 的使用指南。

用途

票證類別可定義多張票證中通用的一組屬性,與範本類似。舉例來說,如果您發行的是活動票券,票證類別會定義所有票券均相同的欄位,例如活動名稱、日期和時間。

您發布的每張票證都必須參照一個票證類別。另外,您也必須為您建立的每個票證類別指派專屬 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"
      }
    }
  }
}
    

用途

票證物件會定義要核發給特定使用者的專屬票證屬性。舉例來說,活動票券的票證物件會定義特定票券專屬的欄位,例如座位號碼或票券的 QR code。

建立票證物件後,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 Token (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 電子錢包商家控制台中提供的憑證進行簽署。簽署作業會使用您的憑證來加密 JWT,進而確保票證安全無虞,並讓 Google Wallet API 驗證透過憑證編碼的票證詳細資料是否有效,並且與您的發卡機構帳戶建立關聯。

操作方式

Google 錢包用戶端程式庫和 Android SDK 提供便利的方法簽署 JWT。此外,Google Cloud 也提供許多開放原始碼程式庫,這些程式庫可處理程式碼簽署的複雜度,且可供選擇。

如果是使用 Google Wallet REST API 核發票證的使用者,系統會使用 Google Cloud 服務帳戶金鑰簽署 JWT。對於使用 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 應用程式建立「新增至 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)
    }
  }
        

使用者儲存核發的票證後,票證會連同他們儲存的任何其他票證一起顯示在他們的 Google 錢包應用程式中。

在 JWT 中建立票證物件和票證類別

您可以透過 Google Wallet REST API 或 Android SDK 預先建立票證類別和票證物件。建立完成後,系統就會透過參照 ID 來核發票證。

或者,您也可以直接將票證類別和票證物件嵌入用於向使用者發出票證的 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": ""
        }
      }]
    }
  }