Google 월렛 패스 개발 절차

Google Wallet API는 기프트 카드, 탑승권, 이벤트 티켓 등 특정 사용 사례에 최적화된 사전 정의된 패스 유형 집합을 제공합니다. 특정 패스 유형을 사용할 수 없는 사용 사례를 위한 일반 패스 유형도 있습니다.

이 도움말에서는 Google Wallet API를 사용하여 패스를 만들고 발급하는 데 필요한 기본 단계를 설명합니다. 아래에 설명된 단계를 실행하는 방법에는 여러 가지가 있지만 대략적으로 모든 패스 유형은 동일한 기본 개발 흐름에 따라 생성됩니다.

패스 생성에 관한 자세한 안내는 웹, 이메일, SMS 또는 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"
      }
    }
  }
}
    

용도

패스 객체는 특정 사용자에게 발급되는 고유한 패스의 속성을 정의합니다. 예를 들어 이벤트 티켓의 패스 객체는 특정 티켓의 고유한 필드(예: 해당 티켓의 좌석 번호 또는 QR 코드)를 정의합니다.

패스 객체가 생성되면 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 웹 토큰 (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 Wallet REST API를 사용하여 패스를 발급하는 경우 JWT는 Google Cloud 서비스 계정 키로 서명됩니다. Google 월렛 Android SDK를 사용하는 경우, SDK가 앱 서명 인증서의 SHA-1 지문을 사용한 JWT 서명을 자동으로 처리합니다.

사용자 인증 정보를 보호하기 위해 JWT는 서버에서만 서명되거나 앱에서 Google 월렛 Android SDK를 사용해야 합니다.

코드 서명 예시 표시

자바

  // 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", Arrays.asList("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("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 월렛에 저장됩니다.

작동 방식

'Google 월렛에 추가' 생성 방법 버튼을 사용하려면 버튼 생성 메서드를 제공하는 Google 월렛 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에 직접 JSON을 삽입합니다. 이 방식에서는 서명된 JWT가 'Google 월렛에 추가'를 통해 전송될 때 Google Wallet API에 의해 패스 클래스 및 패스 객체가 생성됩니다. 버튼을 클릭하거나 링크를 클릭합니다.

예를 들어 다음은 payload.eventTicketClassespayload.eventTicketObjects 속성을 사용하여 정의된 새 패스 클래스 및 패스 객체가 포함된 JWT를 보여줍니다. 이러한 속성은 배열이므로 하나 이상의 패스 클래스 또는 패스 객체를 허용할 수 있습니다. 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": ""
        }
      }]
    }
  }