Google ウォレットのパスの開発フロー

Google Wallet API には、ギフトカード、搭乗券、イベント チケットなど、特定のユースケース向けに最適化された事前定義されたパスタイプが用意されています。特定のパスタイプが使用できないユースケース向けの汎用パスタイプもあります。

この記事では、Google Wallet API を使用してパスを作成および発行するために必要な基本的な手順について説明します。以下で説明する手順の一部を実現する方法は複数ありますが、大まかに言うと、すべてのパスタイプは同じ基本的な開発フローに沿って作成されます。

パス作成の詳細なチュートリアルについては、Google ウォレット REST API または Android SDK の使用ガイドをご覧ください。

用途

パスクラスは、テンプレートと同様に、複数のパスに共通する一連のプロパティを定義します。たとえば、イベントのチケットを発行する場合、パスクラスはすべてのチケットで同じフィールド(イベント名、日付、時間など)を定義します。

発行するすべてのパスでパスクラスを参照する必要があります。また、作成するすべてのパスクラスに一意の ID を割り当てる必要があります。この ID は、パスの作成時に ID を参照するために使用されます。

仕組み

パスクラスは JSON 形式で定義され、Google Wallet REST API、Android SDK、または Google ウォレット Business Console で作成できます。

パスクラスの例を表示

{
  "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 コードなど、特定のチケットに固有のフィールドを定義します。

パス オブジェクトが作成されると、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": ""
  }
}
    

用途

ユーザーにパスを発行するには、パスクラスとパス オブジェクトを 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 ウォレット 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 アプリ用の [Google ウォレットに追加] ボタンを作成するには、Google ウォレット Android SDK を使用します。この 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 に JSON を直接埋め込んで、パスクラスとパス オブジェクトを「ジャストイン タイム」で作成することもできます。この方法では、[Google ウォレットに追加] ボタンまたはリンクを使用して署名済みの JWT が送信されると、Google Wallet API によってパスクラスとパス オブジェクトが作成されます。

たとえば、次の JWT では、payload.eventTicketClasses プロパティと payload.eventTicketObjects プロパティを使用して新しいパスクラスとパス オブジェクトが定義されています。これらのプロパティは配列であるため、1 つ以上のパスクラスまたはパス オブジェクトを受け入れることができます。既存のパスクラスを ID で参照する新しいパス オブジェクトを JWT で指定することもできます。

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": ""
        }
      }]
    }
  }