開始使用 Web API

請先確認您已完成所有必要條件,再開始使用 Web API。如要繼續使用 Web API,您必須具備服務帳戶和服務帳戶金鑰,且需要授予服務帳戶呼叫 Google Wallet API 的權限

前往 GitHub 下載程式碼範例,執行以下步驟中參照的程式碼片段。

驗證及授權

傳送至 Google Wallet API 的要求必須通過驗證,以便 Wallet API 識別應用程式發出要求。方法是使用服務帳戶金鑰取得存取權杖。

首先,執行必要的程式庫匯入作業,並為服務帳戶 JSON 定義部分變數,以及將儲存的核發者、類別、不重複使用者和物件 ID。

Java

如要開始透過 Java 進行整合,請參閱我們完整的 GitHub 程式碼範例

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.*;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.walletobjects.Walletobjects;
import com.google.api.services.walletobjects.model.*;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import java.io.*;
import java.security.interfaces.RSAPrivateKey;
import java.util.*;

/** Demo class for creating and managing Generic passes in Google Wallet. */
public class DemoGeneric {
  /**
   * Path to service account key file from Google Cloud Console. Environment variable:
   * GOOGLE_APPLICATION_CREDENTIALS.
   */
  public static String keyFilePath;

  /** Service account credentials for Google Wallet APIs. */
  public static GoogleCredentials credentials;

  /** Google Wallet service client. */
  public static Walletobjects service;

  public DemoGeneric() throws Exception {
    keyFilePath =
        System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");

    auth();
  }

PHP

如要開始在 PHP 中整合,請參閱完整的 GitHub 程式碼範例

use Firebase\JWT\JWT;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Client as Google_Client;

/** Demo class for creating and managing Generic passes in Google Wallet. */
class DemoGeneric
{
  /**
   * Path to service account key file from Google Cloud Console. Environment
   * variable: GOOGLE_APPLICATION_CREDENTIALS.
   */
  public string $keyFilePath;

  /**
   * Service account credentials for Google Wallet APIs.
   */
  public ServiceAccountCredentials $credentials;

  /**
   * Google Wallet service client.
   */
  public Google_Service_Walletobjects $service;

  public function __construct()
  {
    $this->keyFilePath = getenv('GOOGLE_APPLICATION_CREDENTIALS') ?: '/path/to/key.json';

    $this->auth();
  }

Python

如要開始整合 Python,請參閱我們完整的 GitHub 程式碼範例

import json
import os
import uuid

from google.auth.transport.requests import AuthorizedSession
from google.oauth2.service_account import Credentials
from google.auth import jwt, crypt


class DemoGeneric:
    """Demo class for creating and managing Generic passes in Google Wallet.

    Attributes:
        key_file_path: Path to service account key file from Google Cloud
            Console. Environment variable: GOOGLE_APPLICATION_CREDENTIALS.
        base_url: Base URL for Google Wallet API requests.
    """

    def __init__(self):
        self.key_file_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS',
                                            '/path/to/key.json')
        self.base_url = 'https://walletobjects.googleapis.com/walletobjects/v1'
        self.batch_url = 'https://walletobjects.googleapis.com/batch'
        self.class_url = f'{self.base_url}/genericClass'
        self.object_url = f'{self.base_url}/genericObject'

        # Set up authenticated client
        self.auth()

C#

如要開始在 C# 中整合,請參閱完整的 GitHub 程式碼範例

using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Walletobjects.v1;
using Google.Apis.Walletobjects.v1.Data;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;


/// <summary>
/// Demo class for creating and managing Generic passes in Google Wallet.
/// </summary>
class DemoGeneric
{
  /// <summary>
  /// Path to service account key file from Google Cloud Console. Environment
  /// variable: GOOGLE_APPLICATION_CREDENTIALS.
  /// </summary>
  public static string keyFilePath;

  /// <summary>
  /// Service account credentials for Google Wallet APIs
  /// </summary>
  public static ServiceAccountCredential credentials;

  /// <summary>
  /// Google Wallet service client
  /// </summary>
  public static WalletobjectsService service;

  public DemoGeneric()
  {
    keyFilePath = Environment.GetEnvironmentVariable(
        "GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json";

    Auth();
  }

Node.js

如要開始在節點中進行整合,請參閱完整的 GitHub 程式碼範例

const { GoogleAuth } = require('google-auth-library');
const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');

/**
 * Demo class for creating and managing Generic passes in Google Wallet.
 */
class DemoGeneric {
  constructor() {
    /**
     * Path to service account key file from Google Cloud Console. Environment
     * variable: GOOGLE_APPLICATION_CREDENTIALS.
     */
    this.keyFilePath = process.env.GOOGLE_APPLICATION_CREDENTIALS || '/path/to/key.json';

    this.baseUrl = 'https://walletobjects.googleapis.com/walletobjects/v1';
    this.batchUrl = 'https://walletobjects.googleapis.com/batch';
    this.classUrl = `${this.baseUrl}/genericClass`;
    this.objectUrl = `${this.baseUrl}/genericObject`;

    this.auth();
  }

查看

如要開始在 Go 中整合,請前往 GitHub 參閱完整程式碼範例 GitHub 上的程式碼範例

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/golang-jwt/jwt"
	"github.com/google/uuid"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	oauthJwt "golang.org/x/oauth2/jwt"
	"io"
	"net/http"
	"os"
	"strings"
)


const (
	batchUrl  = "https://walletobjects.googleapis.com/batch"
	classUrl  = "https://walletobjects.googleapis.com/walletobjects/v1/genericClass"
	objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/genericObject"
)

接下來,請使用其中一個架構程式庫擷取必要的憑證,以呼叫 Google Wallet API。

Java

如要開始透過 Java 進行整合,請參閱我們完整的 GitHub 程式碼範例

/**
 * Create authenticated HTTP client using a service account file.
 *
 */
public void auth() throws Exception {
  String scope = "https://www.googleapis.com/auth/wallet_object.issuer";

  credentials =
      GoogleCredentials.fromStream(new FileInputStream(keyFilePath))
          .createScoped(List.of(scope));
  credentials.refresh();

  HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

  // Initialize Google Wallet API service
  service =
      new Walletobjects.Builder(
              httpTransport,
              GsonFactory.getDefaultInstance(),
              new HttpCredentialsAdapter(credentials))
          .setApplicationName("APPLICATION_NAME")
          .build();
}

PHP

如要開始在 PHP 中整合,請參閱完整的 GitHub 程式碼範例

/**
 * Create authenticated HTTP client using a service account file.
 */
public function auth()
{
  $scope = 'https://www.googleapis.com/auth/wallet_object.issuer';

  $this->credentials = new ServiceAccountCredentials(
    $scope,
    $this->keyFilePath
  );

  // Initialize Google Wallet API service
  $this->client = new Google_Client();
  $this->client->setApplicationName('APPLICATION_NAME');
  $this->client->setScopes($scope);
  $this->client->setAuthConfig($this->keyFilePath);

  $this->service = new Google_Service_Walletobjects($this->client);
}

Python

如要開始整合 Python,請參閱我們完整的 GitHub 程式碼範例

def auth(self):
    """Create authenticated HTTP client using a service account file."""
    self.credentials = Credentials.from_service_account_file(
        self.key_file_path,
        scopes=['https://www.googleapis.com/auth/wallet_object.issuer'])

    self.http_client = AuthorizedSession(self.credentials)

C#

如要開始在 C# 中整合,請參閱完整的 GitHub 程式碼範例

/// <summary>
/// Create authenticated service client using a service account file.
/// </summary>
public void Auth()
{
  credentials = (ServiceAccountCredential)GoogleCredential
      .FromFile(keyFilePath)
      .CreateScoped(new List<string>
      {
        "https://www.googleapis.com/auth/wallet_object.issuer"
      })
      .UnderlyingCredential;

  service = new WalletobjectsService(
      new BaseClientService.Initializer()
      {
        HttpClientInitializer = credentials
      });
}

Node.js

如要開始在節點中進行整合,請參閱完整的 GitHub 程式碼範例

/**
 * Create authenticated HTTP client using a service account file.
 */
auth() {
  this.credentials = require(this.keyFilePath);

  this.httpClient = new GoogleAuth({
    credentials: this.credentials,
    scopes: 'https://www.googleapis.com/auth/wallet_object.issuer'
  });
}

查看

如要開始在 Go 中整合,請前往 GitHub 參閱完整程式碼範例 GitHub 上的程式碼範例

// Create authenticated HTTP client using a service account file.
func (d *demoGeneric) auth() {
	b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
	credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
	d.credentials = credentials
	d.httpClient = d.credentials.Client(oauth2.NoContext)
}

建立票證物件

票證物件是票證類別的執行個體。如要建立票證物件,您必須提供下列屬性:

  • classId:票證類別的 id
  • id:客戶的專屬 ID

如要進一步瞭解這些屬性在一般票證中的表示方式,請參閱範本指南

建立票證物件的程式碼範例:

Java

如要開始透過 Java 進行整合,請參閱我們完整的 GitHub 程式碼範例

/**
 * Create an object.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 * @param objectSuffix Developer-defined unique ID for this pass object.
 * @return The pass object ID: "{issuerId}.{objectSuffix}"
 */
public String createObject(String issuerId, String classSuffix, String objectSuffix)
    throws IOException {
  // Check if the object exists
  try {
    service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();

    System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix);
    return String.format("%s.%s", issuerId, objectSuffix);
  } catch (GoogleJsonResponseException ex) {
    if (ex.getStatusCode() != 404) {
      // Something else went wrong...
      ex.printStackTrace();
      return String.format("%s.%s", issuerId, objectSuffix);
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  GenericObject newObject =
      new GenericObject()
          .setId(String.format("%s.%s", issuerId, objectSuffix))
          .setClassId(String.format("%s.%s", issuerId, classSuffix))
          .setState("ACTIVE")
          .setHeroImage(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Hero image description"))))
          .setTextModulesData(
                  List.of(
                          new TextModuleData()
                                  .setHeader("Text module header")
                                  .setBody("Text module body")
                                  .setId("TEXT_MODULE_ID")))
          .setLinksModuleData(
              new LinksModuleData()
                  .setUris(
                      Arrays.asList(
                          new Uri()
                              .setUri("http://maps.google.com/")
                              .setDescription("Link module URI description")
                              .setId("LINK_MODULE_URI_ID"),
                          new Uri()
                              .setUri("tel:6505555555")
                              .setDescription("Link module tel description")
                              .setId("LINK_MODULE_TEL_ID"))))
          .setImageModulesData(
                  List.of(
                          new ImageModuleData()
                                  .setMainImage(
                                          new Image()
                                                  .setSourceUri(
                                                          new ImageUri()
                                                                  .setUri(
                                                                          "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                                                  .setContentDescription(
                                                          new LocalizedString()
                                                                  .setDefaultValue(
                                                                          new TranslatedString()
                                                                                  .setLanguage("en-US")
                                                                                  .setValue("Image module description"))))
                                  .setId("IMAGE_MODULE_ID")))
          .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
          .setCardTitle(
              new LocalizedString()
                  .setDefaultValue(
                      new TranslatedString().setLanguage("en-US").setValue("Generic card title")))
          .setHeader(
              new LocalizedString()
                  .setDefaultValue(
                      new TranslatedString().setLanguage("en-US").setValue("Generic header")))
          .setHexBackgroundColor("#4285f4")
          .setLogo(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Generic card logo"))));

  GenericObject response = service.genericobject().insert(newObject).execute();

  System.out.println("Object insert response");
  System.out.println(response.toPrettyString());

  return response.getId();
}

PHP

如要開始在 PHP 中整合,請參閱完整的 GitHub 程式碼範例

/**
 * Create an object.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for this pass class.
 * @param string $objectSuffix Developer-defined unique ID for this pass object.
 *
 * @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
 */
public function createObject(string $issuerId, string $classSuffix, string $objectSuffix)
{
  // Check if the object exists
  try {
    $this->service->genericobject->get("{$issuerId}.{$objectSuffix}");

    print("Object {$issuerId}.{$objectSuffix} already exists!");
    return "{$issuerId}.{$objectSuffix}";
  } catch (Google\Service\Exception $ex) {
    if (empty($ex->getErrors()) || $ex->getErrors()[0]['reason'] != 'resourceNotFound') {
      // Something else went wrong...
      print_r($ex);
      return "{$issuerId}.{$objectSuffix}";
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  $newObject = new Google_Service_Walletobjects_GenericObject([
    'id' => "{$issuerId}.{$objectSuffix}",
    'classId' => "{$issuerId}.{$classSuffix}",
    'state' => 'ACTIVE',
    'heroImage' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Hero image description'
        ])
      ])
    ]),
    'textModulesData' => [
      new Google_Service_Walletobjects_TextModuleData([
        'header' => 'Text module header',
        'body' => 'Text module body',
        'id' => 'TEXT_MODULE_ID'
      ])
    ],
    'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
      'uris' => [
        new Google_Service_Walletobjects_Uri([
          'uri' => 'http://maps.google.com/',
          'description' => 'Link module URI description',
          'id' => 'LINK_MODULE_URI_ID'
        ]),
        new Google_Service_Walletobjects_Uri([
          'uri' => 'tel:6505555555',
          'description' => 'Link module tel description',
          'id' => 'LINK_MODULE_TEL_ID'
        ])
      ]
    ]),
    'imageModulesData' => [
      new Google_Service_Walletobjects_ImageModuleData([
        'mainImage' => new Google_Service_Walletobjects_Image([
          'sourceUri' => new Google_Service_Walletobjects_ImageUri([
            'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          ]),
          'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
            'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
              'language' => 'en-US',
              'value' => 'Image module description'
            ])
          ])
        ]),
        'id' => 'IMAGE_MODULE_ID'
      ])
    ],
    'barcode' => new Google_Service_Walletobjects_Barcode([
      'type' => 'QR_CODE',
      'value' => 'QR code value'
    ]),
    'cardTitle' => new Google_Service_Walletobjects_LocalizedString([
      'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
        'language' => 'en-US',
        'value' => 'Generic card title'
      ])
    ]),
    'header' => new Google_Service_Walletobjects_LocalizedString([
      'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
        'language' => 'en-US',
        'value' => 'Generic header'
      ])
    ]),
    'hexBackgroundColor' => '#4285f4',
    'logo' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Generic card logo'
        ])
      ])
    ])
  ]);

  $response = $this->service->genericobject->insert($newObject);

  print "Object insert response\n";
  print_r($response);

  return $response->id;
}

Python

如要開始整合 Python,請參閱我們完整的 GitHub 程式碼範例

def create_object(self, issuer_id: str, class_suffix: str,
                  object_suffix: str) -> str:
    """Create an object.

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for the pass class.
        object_suffix (str): Developer-defined unique ID for the pass object.

    Returns:
        The pass object ID: f"{issuer_id}.{object_suffix}"
    """

    # Check if the object exists
    response = self.http_client.get(
        url=f'{self.object_url}/{issuer_id}.{object_suffix}')

    if response.status_code == 200:
        print(f'Object {issuer_id}.{object_suffix} already exists!')
        print(response.text)
        return f'{issuer_id}.{object_suffix}'
    elif response.status_code != 404:
        # Something else went wrong...
        print(response.text)
        return f'{issuer_id}.{object_suffix}'

    # See link below for more information on required properties
    # https://developers.google.com/wallet/generic/rest/v1/genericobject
    new_object = {
        'id': f'{issuer_id}.{object_suffix}',
        'classId': f'{issuer_id}.{class_suffix}',
        'state': 'ACTIVE',
        'heroImage': {
            'sourceUri': {
                'uri':
                    'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Hero image description'
                }
            }
        },
        'textModulesData': [{
            'header': 'Text module header',
            'body': 'Text module body',
            'id': 'TEXT_MODULE_ID'
        }],
        'linksModuleData': {
            'uris': [{
                'uri': 'http://maps.google.com/',
                'description': 'Link module URI description',
                'id': 'LINK_MODULE_URI_ID'
            }, {
                'uri': 'tel:6505555555',
                'description': 'Link module tel description',
                'id': 'LINK_MODULE_TEL_ID'
            }]
        },
        'imageModulesData': [{
            'mainImage': {
                'sourceUri': {
                    'uri':
                        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Image module description'
                    }
                }
            },
            'id': 'IMAGE_MODULE_ID'
        }],
        'barcode': {
            'type': 'QR_CODE',
            'value': 'QR code'
        },
        'cardTitle': {
            'defaultValue': {
                'language': 'en-US',
                'value': 'Generic card title'
            }
        },
        'header': {
            'defaultValue': {
                'language': 'en-US',
                'value': 'Generic header'
            }
        },
        'hexBackgroundColor': '#4285f4',
        'logo': {
            'sourceUri': {
                'uri':
                    'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Generic card logo'
                }
            }
        }
    }

    # Create the object
    response = self.http_client.post(url=self.object_url, json=new_object)

    print('Object insert response')
    print(response.text)

    return response.json().get('id')

C#

如要開始在 C# 中整合,請參閱完整的 GitHub 程式碼範例

/// <summary>
/// Create an object.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
/// <param name="objectSuffix">Developer-defined unique ID for this pass object.</param>
/// <returns>The pass object ID: "{issuerId}.{objectSuffix}"</returns>
public string CreateObject(string issuerId, string classSuffix, string objectSuffix)
{
  // Check if the object exists
  Stream responseStream = service.Genericobject
      .Get($"{issuerId}.{objectSuffix}")
      .ExecuteAsStream();

  StreamReader responseReader = new StreamReader(responseStream);
  JObject jsonResponse = JObject.Parse(responseReader.ReadToEnd());

  if (!jsonResponse.ContainsKey("error"))
  {
    Console.WriteLine($"Object {issuerId}.{objectSuffix} already exists!");
    return $"{issuerId}.{objectSuffix}";
  }
  else if (jsonResponse["error"].Value<int>("code") != 404)
  {
    // Something else went wrong...
    Console.WriteLine(jsonResponse.ToString());
    return $"{issuerId}.{objectSuffix}";
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  GenericObject newObject = new GenericObject
  {
    Id = $"{issuerId}.{objectSuffix}",
    ClassId = $"{issuerId}.{classSuffix}",
    State = "ACTIVE",
    HeroImage = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Hero image description"
        }
      }
    },
    TextModulesData = new List<TextModuleData>
    {
      new TextModuleData
      {
        Header = "Text module header",
        Body = "Text module body",
        Id = "TEXT_MODULE_ID"
      }
    },
    LinksModuleData = new LinksModuleData
    {
      Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
      {
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "http://maps.google.com/",
          Description = "Link module URI description",
          Id = "LINK_MODULE_URI_ID"
        },
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "tel:6505555555",
          Description = "Link module tel description",
          Id = "LINK_MODULE_TEL_ID"
        }
      }
    },
    ImageModulesData = new List<ImageModuleData>
    {
      new ImageModuleData
      {
        MainImage = new Image
        {
          SourceUri = new ImageUri
          {
            Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
          },
          ContentDescription = new LocalizedString
          {
            DefaultValue = new TranslatedString
            {
              Language = "en-US",
              Value = "Image module description"
            }
          }
        },
        Id = "IMAGE_MODULE_ID"
      }
    },
    Barcode = new Barcode
    {
      Type = "QR_CODE",
      Value = "QR code"
    },
    CardTitle = new LocalizedString
    {
      DefaultValue = new TranslatedString
      {
        Language = "en-US",
        Value = "Generic card title"
      }
    },
    Header = new LocalizedString
    {
      DefaultValue = new TranslatedString
      {
        Language = "en-US",
        Value = "Generic header"
      }
    },
    HexBackgroundColor = "#4285f4",
    Logo = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Generic card logo"
        }
      },
    }
  };

  responseStream = service.Genericobject
      .Insert(newObject)
      .ExecuteAsStream();
  responseReader = new StreamReader(responseStream);
  jsonResponse = JObject.Parse(responseReader.ReadToEnd());

  Console.WriteLine("Object insert response");
  Console.WriteLine(jsonResponse.ToString());

  return $"{issuerId}.{objectSuffix}";
}

Node.js

如要開始在節點中進行整合,請參閱完整的 GitHub 程式碼範例

/**
 * Create an object.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for the pass class.
 * @param {string} objectSuffix Developer-defined unique ID for the pass object.
 *
 * @returns {string} The pass object ID: `${issuerId}.${objectSuffix}`
 */
async createObject(issuerId, classSuffix, objectSuffix) {
  let response;

  // Check if the object exists
  try {
    response = await this.httpClient.request({
      url: `${this.objectUrl}/${issuerId}.${objectSuffix}`,
      method: 'GET'
    });

    console.log(`Object ${issuerId}.${objectSuffix} already exists!`);

    return `${issuerId}.${objectSuffix}`;
  } catch (err) {
    if (err.response && err.response.status !== 404) {
      // Something else went wrong...
      console.log(err);
      return `${issuerId}.${objectSuffix}`;
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  let newObject = {
    'id': `${issuerId}.${objectSuffix}`,
    'classId': `${issuerId}.${classSuffix}`,
    'state': 'ACTIVE',
    'heroImage': {
      'sourceUri': {
        'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Hero image description'
        }
      }
    },
    'textModulesData': [
      {
        'header': 'Text module header',
        'body': 'Text module body',
        'id': 'TEXT_MODULE_ID'
      }
    ],
    'linksModuleData': {
      'uris': [
        {
          'uri': 'http://maps.google.com/',
          'description': 'Link module URI description',
          'id': 'LINK_MODULE_URI_ID'
        },
        {
          'uri': 'tel:6505555555',
          'description': 'Link module tel description',
          'id': 'LINK_MODULE_TEL_ID'
        }
      ]
    },
    'imageModulesData': [
      {
        'mainImage': {
          'sourceUri': {
            'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          },
          'contentDescription': {
            'defaultValue': {
              'language': 'en-US',
              'value': 'Image module description'
            }
          }
        },
        'id': 'IMAGE_MODULE_ID'
      }
    ],
    'barcode': {
      'type': 'QR_CODE',
      'value': 'QR code'
    },
    'cardTitle': {
      'defaultValue': {
        'language': 'en-US',
        'value': 'Generic card title'
      }
    },
    'header': {
      'defaultValue': {
        'language': 'en-US',
        'value': 'Generic header'
      }
    },
    'hexBackgroundColor': '#4285f4',
    'logo': {
      'sourceUri': {
        'uri': 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Generic card logo'
        }
      }
    }
  };

  response = await this.httpClient.request({
    url: this.objectUrl,
    method: 'POST',
    data: newObject
  });

  console.log('Object insert response');
  console.log(response);

  return `${issuerId}.${objectSuffix}`;
}

查看

如要開始在 Go 中整合,請前往 GitHub 參閱完整程式碼範例 GitHub 上的程式碼範例

// Create an object.
func (d *demoGeneric) createObject(issuerId, classSuffix, objectSuffix string) {
	newObject := fmt.Sprintf(`
	{
		"classId": "%s.%s",
		"cardTitle": {
			"defaultValue": {
				"value": "Generic card title",
				"language": "en-US"
			}
		},
		"heroImage": {
			"contentDescription": {
				"defaultValue": {
					"value": "Hero image description",
					"language": "en-US"
				}
			},
			"sourceUri": {
				"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
			}
		},
		"barcode": {
			"type": "QR_CODE",
			"value": "QR code"
		},
		"header": {
			"defaultValue": {
				"value": "Generic header",
				"language": "en-US"
			}
		},
		"state": "ACTIVE",
		"linksModuleData": {
			"uris": [
				{
					"id": "LINK_MODULE_URI_ID",
					"uri": "http://maps.google.com/",
					"description": "Link module URI description"
				},
				{
					"id": "LINK_MODULE_TEL_ID",
					"uri": "tel:6505555555",
					"description": "Link module tel description"
				}
			]
		},
		"imageModulesData": [
			{
				"id": "IMAGE_MODULE_ID",
				"mainImage": {
					"contentDescription": {
						"defaultValue": {
							"value": "Image module description",
							"language": "en-US"
						}
					},
					"sourceUri": {
						"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
					}
				}
			}
		],
		"textModulesData": [
			{
				"body": "Text module body",
				"header": "Text module header",
				"id": "TEXT_MODULE_ID"
			}
		],
		"logo": {
			"contentDescription": {
				"defaultValue": {
					"value": "Generic card logo",
					"language": "en-US"
				}
			},
			"sourceUri": {
				"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
			}
		},
		"hexBackgroundColor": "#4285f4",
		"id": "%s.%s"
	}
	`, issuerId, classSuffix, issuerId, objectSuffix)

	res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))

	if err != nil {
		fmt.Println(err)
	} else {
		b, _ := io.ReadAll(res.Body)
		fmt.Printf("Object insert response:\n%s\n", b)
	}
}

完成後,客戶的票證物件就會在伺服器上建立,但在這個階段,票證物件尚未連結至 Google 使用者或其裝置。如要將票證與 Google 錢包建立關聯,使用者必須先將票證儲存至 Google 錢包

正在新增至 Google 錢包

新增票證至 Google 錢包後,票證物件會連結至 Google 使用者,且只能在已登入 Google 身分的環境中啟動。將使用者導向至「新增至 Google 錢包」網址即可。

「新增至 Google 錢包」網址是以動態方式產生的網址,當中包含您在上一個步驟中建立的票證物件 ID 相關資訊。這項資訊編碼為 JSON Web Token (JWT)

JSON Web Token (JWT)

JWT 含有您 (發卡機構) 針對使用者即將儲存的票證物件提出的聲明。JWT 必須使用透過建立服務帳戶步驟所取得的服務帳戶金鑰中的 private_key 簽署,而 Google 會驗證 JWT 簽名,藉此驗證這些憑證附加資訊。

JWT 憑證附加資訊應有下列結構:

{
  "aud": "google",
  "origins": ["https://example.com"],
  "iss": "my-service-account@my-project-id.iam.gserviceaccount.com",
  "typ": "savetowallet",
  "payload": {
    "genericObjects": [
      {
        "id": "PASSES_OBJECT_ID_1234567890"
      }
    ]
  }
}

建構 JWT claims (步驟 1),然後使用服務帳戶金鑰的 private_key 簽署憑證附加資訊,並取得 token (步驟 2):

Java

如要開始透過 Java 進行整合,請參閱我們完整的 GitHub 程式碼範例

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
 * pass class and object defined in the JWT are created. This allows you to create multiple pass
 * classes and objects in one API call when the user saves the pass to their wallet.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 * @param objectSuffix Developer-defined unique ID for the pass object.
 * @return An "Add to Google Wallet" link.
 */
public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericclass
  GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix));

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  GenericObject newObject =
      new GenericObject()
          .setId(String.format("%s.%s", issuerId, objectSuffix))
          .setClassId(String.format("%s.%s", issuerId, classSuffix))
          .setState("ACTIVE")
          .setHeroImage(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Hero image description"))))
          .setTextModulesData(
                  List.of(
                          new TextModuleData()
                                  .setHeader("Text module header")
                                  .setBody("Text module body")
                                  .setId("TEXT_MODULE_ID")))
          .setLinksModuleData(
              new LinksModuleData()
                  .setUris(
                      Arrays.asList(
                          new Uri()
                              .setUri("http://maps.google.com/")
                              .setDescription("Link module URI description")
                              .setId("LINK_MODULE_URI_ID"),
                          new Uri()
                              .setUri("tel:6505555555")
                              .setDescription("Link module tel description")
                              .setId("LINK_MODULE_TEL_ID"))))
          .setImageModulesData(
                  List.of(
                          new ImageModuleData()
                                  .setMainImage(
                                          new Image()
                                                  .setSourceUri(
                                                          new ImageUri()
                                                                  .setUri(
                                                                          "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                                                  .setContentDescription(
                                                          new LocalizedString()
                                                                  .setDefaultValue(
                                                                          new TranslatedString()
                                                                                  .setLanguage("en-US")
                                                                                  .setValue("Image module description"))))
                                  .setId("IMAGE_MODULE_ID")))
          .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
          .setCardTitle(
              new LocalizedString()
                  .setDefaultValue(
                      new TranslatedString().setLanguage("en-US").setValue("Generic card title")))
          .setHeader(
              new LocalizedString()
                  .setDefaultValue(
                      new TranslatedString().setLanguage("en-US").setValue("Generic header")))
          .setHexBackgroundColor("#4285f4")
          .setLogo(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Generic card logo"))));

  // Create the JWT as a HashMap object
  HashMap<String, Object> claims = new HashMap<String, Object>();
  claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
  claims.put("aud", "google");
  claims.put("origins", List.of("www.example.com"));
  claims.put("typ", "savetowallet");

  // Create the Google Wallet payload and add to the JWT
  HashMap<String, Object> payload = new HashMap<String, Object>();
  payload.put("genericClasses", List.of(newClass));
  payload.put("genericObjects", List.of(newObject));
  claims.put("payload", payload);

  // The 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);

  System.out.println("Add to Google Wallet link");
  System.out.printf("https://pay.google.com/gp/v/save/%s%n", token);

  return String.format("https://pay.google.com/gp/v/save/%s", token);
}

PHP

如要開始在 PHP 中整合,請參閱完整的 GitHub 程式碼範例

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * When the user opens the "Add to Google Wallet" URL and saves the pass to
 * their wallet, the pass class and object defined in the JWT are
 * created. This allows you to create multiple pass classes and objects in
 * one API call when the user saves the pass to their wallet.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for the pass class.
 * @param string $objectSuffix Developer-defined unique ID for the pass object.
 *
 * @return string An "Add to Google Wallet" link.
 */
public function createJwtNewObjects(string $issuerId, string $classSuffix, string $objectSuffix)
{
  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericclass
  $newClass = new Google_Service_Walletobjects_GenericClass([
    'id' => "{$issuerId}.{$classSuffix}",
  ]);

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  $newObject = new Google_Service_Walletobjects_GenericObject([
    'id' => "{$issuerId}.{$objectSuffix}",
    'classId' => "{$issuerId}.{$classSuffix}",
    'state' => 'ACTIVE',
    'heroImage' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Hero image description'
        ])
      ])
    ]),
    'textModulesData' => [
      new Google_Service_Walletobjects_TextModuleData([
        'header' => 'Text module header',
        'body' => 'Text module body',
        'id' => 'TEXT_MODULE_ID'
      ])
    ],
    'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
      'uris' => [
        new Google_Service_Walletobjects_Uri([
          'uri' => 'http://maps.google.com/',
          'description' => 'Link module URI description',
          'id' => 'LINK_MODULE_URI_ID'
        ]),
        new Google_Service_Walletobjects_Uri([
          'uri' => 'tel:6505555555',
          'description' => 'Link module tel description',
          'id' => 'LINK_MODULE_TEL_ID'
        ])
      ]
    ]),
    'imageModulesData' => [
      new Google_Service_Walletobjects_ImageModuleData([
        'mainImage' => new Google_Service_Walletobjects_Image([
          'sourceUri' => new Google_Service_Walletobjects_ImageUri([
            'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          ]),
          'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
            'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
              'language' => 'en-US',
              'value' => 'Image module description'
            ])
          ])
        ]),
        'id' => 'IMAGE_MODULE_ID'
      ])
    ],
    'barcode' => new Google_Service_Walletobjects_Barcode([
      'type' => 'QR_CODE',
      'value' => 'QR code value'
    ]),
    'cardTitle' => new Google_Service_Walletobjects_LocalizedString([
      'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
        'language' => 'en-US',
        'value' => 'Generic card title'
      ])
    ]),
    'header' => new Google_Service_Walletobjects_LocalizedString([
      'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
        'language' => 'en-US',
        'value' => 'Generic header'
      ])
    ]),
    'hexBackgroundColor' => '#4285f4',
    'logo' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Generic card logo'
        ])
      ])
    ])
  ]);

  // The service account credentials are used to sign the JWT
  $serviceAccount = json_decode(file_get_contents($this->keyFilePath), true);

  // Create the JWT as an array of key/value pairs
  $claims = [
    'iss' => $serviceAccount['client_email'],
    'aud' => 'google',
    'origins' => ['www.example.com'],
    'typ' => 'savetowallet',
    'payload' => [
      'genericClasses' => [
        $newClass
      ],
      'genericObjects' => [
        $newObject
      ]
    ]
  ];

  $token = JWT::encode(
    $claims,
    $serviceAccount['private_key'],
    'RS256'
  );

  print "Add to Google Wallet link\n";
  print "https://pay.google.com/gp/v/save/{$token}";

  return "https://pay.google.com/gp/v/save/{$token}";
}

Python

如要開始整合 Python,請參閱我們完整的 GitHub 程式碼範例

def create_jwt_new_objects(self, issuer_id: str, class_suffix: str,
                           object_suffix: str) -> str:
    """Generate a signed JWT that creates a new pass class and object.

    When the user opens the "Add to Google Wallet" URL and saves the pass to
    their wallet, the pass class and object defined in the JWT are
    created. This allows you to create multiple pass classes and objects in
    one API call when the user saves the pass to their wallet.

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for the pass class.
        object_suffix (str): Developer-defined unique ID for the pass object.

    Returns:
        An "Add to Google Wallet" link.
    """

    # See link below for more information on required properties
    # https://developers.google.com/wallet/generic/rest/v1/genericclass
    new_class = {'id': f'{issuer_id}.{class_suffix}'}

    # See link below for more information on required properties
    # https://developers.google.com/wallet/generic/rest/v1/genericobject
    new_object = {
        'id': f'{issuer_id}.{object_suffix}',
        'classId': f'{issuer_id}.{class_suffix}',
        'state': 'ACTIVE',
        'heroImage': {
            'sourceUri': {
                'uri':
                    'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Hero image description'
                }
            }
        },
        'textModulesData': [{
            'header': 'Text module header',
            'body': 'Text module body',
            'id': 'TEXT_MODULE_ID'
        }],
        'linksModuleData': {
            'uris': [{
                'uri': 'http://maps.google.com/',
                'description': 'Link module URI description',
                'id': 'LINK_MODULE_URI_ID'
            }, {
                'uri': 'tel:6505555555',
                'description': 'Link module tel description',
                'id': 'LINK_MODULE_TEL_ID'
            }]
        },
        'imageModulesData': [{
            'mainImage': {
                'sourceUri': {
                    'uri':
                        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Image module description'
                    }
                }
            },
            'id': 'IMAGE_MODULE_ID'
        }],
        'barcode': {
            'type': 'QR_CODE',
            'value': 'QR code'
        },
        'cardTitle': {
            'defaultValue': {
                'language': 'en-US',
                'value': 'Generic card title'
            }
        },
        'header': {
            'defaultValue': {
                'language': 'en-US',
                'value': 'Generic header'
            }
        },
        'hexBackgroundColor': '#4285f4',
        'logo': {
            'sourceUri': {
                'uri':
                    'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Generic card logo'
                }
            }
        }
    }

    # 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
            'genericClasses': [new_class],
            'genericObjects': [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')

    print('Add to Google Wallet link')
    print(f'https://pay.google.com/gp/v/save/{token}')

    return f'https://pay.google.com/gp/v/save/{token}'

C#

如要開始在 C# 中整合,請參閱完整的 GitHub 程式碼範例

/// <summary>
/// Generate a signed JWT that creates a new pass class and object.
/// <para />
/// When the user opens the "Add to Google Wallet" URL and saves the pass to
/// their wallet, the pass class and object defined in the JWT are created.
/// This allows you to create multiple pass classes and objects in one API
/// call when the user saves the pass to their wallet.
/// <para />
/// The Google Wallet C# library uses Newtonsoft.Json.JsonPropertyAttribute
/// to specify the property names when converting objects to JSON. The
/// Newtonsoft.Json.JsonConvert.SerializeObject method will automatically
/// serialize the object with the right property names.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
/// <param name="objectSuffix">Developer-defined unique ID for the pass object.</param>
/// <returns>An "Add to Google Wallet" link.</returns>
public string CreateJWTNewObjects(string issuerId, string classSuffix, string objectSuffix)
{
  // Ignore null values when serializing to/from JSON
  JsonSerializerSettings excludeNulls = new JsonSerializerSettings()
  {
    NullValueHandling = NullValueHandling.Ignore
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericclass
  GenericClass newClass = new GenericClass
  {
    Id = $"{issuerId}.{classSuffix}"
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  GenericObject newObject = new GenericObject
  {
    Id = $"{issuerId}.{objectSuffix}",
    ClassId = $"{issuerId}.{classSuffix}",
    State = "ACTIVE",
    HeroImage = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Hero image description"
        }
      }
    },
    TextModulesData = new List<TextModuleData>
      {
        new TextModuleData
        {
          Header = "Text module header",
          Body = "Text module body",
          Id = "TEXT_MODULE_ID"
        }
      },
    LinksModuleData = new LinksModuleData
    {
      Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
        {
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "http://maps.google.com/",
            Description = "Link module URI description",
            Id = "LINK_MODULE_URI_ID"
          },
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "tel:6505555555",
            Description = "Link module tel description",
            Id = "LINK_MODULE_TEL_ID"
          }
        }
    },
    ImageModulesData = new List<ImageModuleData>
      {
        new ImageModuleData
        {
          MainImage = new Image
          {
            SourceUri = new ImageUri
            {
              Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
            },
            ContentDescription = new LocalizedString
            {
              DefaultValue = new TranslatedString
              {
                Language = "en-US",
                Value = "Image module description"
              }
            }
          },
          Id = "IMAGE_MODULE_ID"
        }
      },
    Barcode = new Barcode
    {
      Type = "QR_CODE",
      Value = "QR code"
    },
    CardTitle = new LocalizedString
    {
      DefaultValue = new TranslatedString
      {
        Language = "en-US",
        Value = "Generic card title"
      }
    },
    Header = new LocalizedString
    {
      DefaultValue = new TranslatedString
      {
        Language = "en-US",
        Value = "Generic header"
      }
    },
    HexBackgroundColor = "#4285f4",
    Logo = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Generic card logo"
        }
      },
    }
  };

  // Create JSON representations of the class and object
  JObject serializedClass = JObject.Parse(
      JsonConvert.SerializeObject(newClass, excludeNulls));
  JObject serializedObject = JObject.Parse(
      JsonConvert.SerializeObject(newObject, excludeNulls));

  // Create the JWT as a JSON object
  JObject jwtPayload = JObject.Parse(JsonConvert.SerializeObject(new
  {
    iss = credentials.Id,
    aud = "google",
    origins = new List<string>
    {
      "www.example.com"
    },
    typ = "savetowallet",
    payload = JObject.Parse(JsonConvert.SerializeObject(new
    {
      // The listed classes and objects will be created
      // when the user saves the pass to their wallet
      genericClasses = new List<JObject>
      {
        serializedClass
      },
      genericObjects = new List<JObject>
      {
        serializedObject
      }
    }))
  }));

  // Deserialize into a JwtPayload
  JwtPayload claims = JwtPayload.Deserialize(jwtPayload.ToString());

  // The service account credentials are used to sign the JWT
  RsaSecurityKey key = new RsaSecurityKey(credentials.Key);
  SigningCredentials signingCredentials = new SigningCredentials(
      key, SecurityAlgorithms.RsaSha256);
  JwtSecurityToken jwt = new JwtSecurityToken(
      new JwtHeader(signingCredentials), claims);
  string token = new JwtSecurityTokenHandler().WriteToken(jwt);

  Console.WriteLine("Add to Google Wallet link");
  Console.WriteLine($"https://pay.google.com/gp/v/save/{token}");

  return $"https://pay.google.com/gp/v/save/{token}";
}

Node.js

如要開始在節點中進行整合,請參閱完整的 GitHub 程式碼範例

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * When the user opens the "Add to Google Wallet" URL and saves the pass to
 * their wallet, the pass class and object defined in the JWT are
 * created. This allows you to create multiple pass classes and objects in
 * one API call when the user saves the pass to their wallet.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for the pass class.
 * @param {string} objectSuffix Developer-defined unique ID for the pass object.
 *
 * @returns {string} An "Add to Google Wallet" link.
 */
createJwtNewObjects(issuerId, classSuffix, objectSuffix) {
  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericclass
  let newClass = {
    'id': `${issuerId}.${classSuffix}`
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/generic/rest/v1/genericobject
  let newObject = {
    'id': `${issuerId}.${objectSuffix}`,
    'classId': `${issuerId}.${classSuffix}`,
    'state': 'ACTIVE',
    'heroImage': {
      'sourceUri': {
        'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Hero image description'
        }
      }
    },
    'textModulesData': [
      {
        'header': 'Text module header',
        'body': 'Text module body',
        'id': 'TEXT_MODULE_ID'
      }
    ],
    'linksModuleData': {
      'uris': [
        {
          'uri': 'http://maps.google.com/',
          'description': 'Link module URI description',
          'id': 'LINK_MODULE_URI_ID'
        },
        {
          'uri': 'tel:6505555555',
          'description': 'Link module tel description',
          'id': 'LINK_MODULE_TEL_ID'
        }
      ]
    },
    'imageModulesData': [
      {
        'mainImage': {
          'sourceUri': {
            'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          },
          'contentDescription': {
            'defaultValue': {
              'language': 'en-US',
              'value': 'Image module description'
            }
          }
        },
        'id': 'IMAGE_MODULE_ID'
      }
    ],
    'barcode': {
      'type': 'QR_CODE',
      'value': 'QR code'
    },
    'cardTitle': {
      'defaultValue': {
        'language': 'en-US',
        'value': 'Generic card title'
      }
    },
    'header': {
      'defaultValue': {
        'language': 'en-US',
        'value': 'Generic header'
      }
    },
    'hexBackgroundColor': '#4285f4',
    'logo': {
      'sourceUri': {
        'uri': 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Generic card logo'
        }
      }
    }
  };

  // Create the JWT claims
  let claims = {
    iss: this.credentials.client_email,
    aud: 'google',
    origins: ['www.example.com'],
    typ: 'savetowallet',
    payload: {
      // The listed classes and objects will be created
      genericClasses: [newClass],
      genericObjects: [newObject]
    },
  };

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

  console.log('Add to Google Wallet link');
  console.log(`https://pay.google.com/gp/v/save/${token}`);

  return `https://pay.google.com/gp/v/save/${token}`;
}

查看

如要開始在 Go 中整合,請前往 GitHub 參閱完整程式碼範例 GitHub 上的程式碼範例

// Generate a signed JWT that creates a new pass class and object.
//
// When the user opens the "Add to Google Wallet" URL and saves the pass to
// their wallet, the pass class and object defined in the JWT are
// created. This allows you to create multiple pass classes and objects in
// one API call when the user saves the pass to their wallet.
func (d *demoGeneric) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
	newClass := fmt.Sprintf(`
	{
		"id": "%s.%s"
	}
	`, issuerId, classSuffix)

	newObject := fmt.Sprintf(`
	{
		"classId": "%s.%s",
		"cardTitle": {
			"defaultValue": {
				"value": "Generic card title",
				"language": "en-US"
			}
		},
		"heroImage": {
			"contentDescription": {
				"defaultValue": {
					"value": "Hero image description",
					"language": "en-US"
				}
			},
			"sourceUri": {
				"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
			}
		},
		"barcode": {
			"type": "QR_CODE",
			"value": "QR code"
		},
		"header": {
			"defaultValue": {
				"value": "Generic header",
				"language": "en-US"
			}
		},
		"state": "ACTIVE",
		"linksModuleData": {
			"uris": [
				{
					"id": "LINK_MODULE_URI_ID",
					"uri": "http://maps.google.com/",
					"description": "Link module URI description"
				},
				{
					"id": "LINK_MODULE_TEL_ID",
					"uri": "tel:6505555555",
					"description": "Link module tel description"
				}
			]
		},
		"imageModulesData": [
			{
				"id": "IMAGE_MODULE_ID",
				"mainImage": {
					"contentDescription": {
						"defaultValue": {
							"value": "Image module description",
							"language": "en-US"
						}
					},
					"sourceUri": {
						"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
					}
				}
			}
		],
		"textModulesData": [
			{
				"body": "Text module body",
				"header": "Text module header",
				"id": "TEXT_MODULE_ID"
			}
		],
		"logo": {
			"contentDescription": {
				"defaultValue": {
					"value": "Generic card logo",
					"language": "en-US"
				}
			},
			"sourceUri": {
				"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
			}
		},
		"hexBackgroundColor": "#4285f4",
		"id": "%s.%s"
	}
	`, issuerId, classSuffix, issuerId, objectSuffix)

	var payload map[string]interface{}
	json.Unmarshal([]byte(fmt.Sprintf(`
	{
		"genericClasses": [%s],
		"genericObjects": [%s]
	}
	`, newClass, newObject)), &payload)

	claims := jwt.MapClaims{
		"iss":     d.credentials.Email,
		"aud":     "google",
		"origins": []string{"www.example.com"},
		"typ":     "savetowallet",
		"payload": payload,
	}

	// The service account credentials are used to sign the JWT
	key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey)
	token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key)

	fmt.Println("Add to Google Wallet link")
	fmt.Println("https://pay.google.com/gp/v/save/" + token)
}

取得已簽署的 JWT 後,您可以利用這項資訊建構新增至 Google 錢包連結

「新增至 Google 錢包」連結採用的格式如下:

https://pay.google.com/gp/v/save/{token}

這個連結可嵌入您的網頁,或以超連結的形式透過電子郵件傳送。 也可以透過其他管道 (例如即時通訊和簡訊) 傳送給客戶。

經過編碼的 JWT 的長度上限為 1800 個字元。如果您的 JWT 低於此限制,則可在已簽署的 JWT 中加入整個物件。您的 JWT 不應超過此限制。如果長度超過 1800 個半形字元,儲存功能可能會因為網路瀏覽器遭到截斷。

新增至 Google 錢包按鈕

為求最佳效果,請在網頁、電子郵件或 Android 應用程式中使用 Google 錢包按鈕素材資源

Google 錢包按鈕的呈現方式如下:

  • JavaScript 網頁按鈕可用於網站。
  • 含有按鈕的 JWT 連結可用於電子郵件、簡訊、應用程式與網站。

[僅用於測試] 通過

如果仍處於展示模式,您建立的所有票證都會在票證的標題中加上額外文字「[TEST ONLY]」。以便區分展示卡與即時通行證。待我們的團隊核准正式版後,當使用者在連結的裝置上重新開啟錢包應用程式時,這些展示模式票證就不會再有說明文字。

後續步驟