Google 월렛 패스 개발 절차

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

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

패스를 만드는 방법을 자세히 알아보려면 Google Wallet REST API 또는 Android SDK 사용 가이드를 참조하세요.

용도

패스 클래스는 템플릿과 마찬가지로 여러 패스에 공통적으로 적용되는 속성 집합을 정의합니다. 예를 들어 이벤트의 티켓을 발급하는 경우 패스 클래스는 이벤트 이름, 날짜, 시간과 같이 모든 티켓에서 동일한 필드를 정의합니다.

발급하는 모든 패스는 패스 클래스를 참조해야 합니다. 또한 생성한 모든 패스 클래스에 고유 ID를 할당해야 합니다. 패스 클래스는 패스를 만들 때 이 ID를 참조하는 데 사용됩니다.

작동 방식

Passes 클래스는 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를 사용해야 합니다.

코드 서명 예시 표시

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로 전송되고, Google Wallet API에서 저장된 사용자 인증 정보를 사용하여 복호화합니다. JWT 서명이 인증되면 Google 월렛에 저장할 패스가 사용자에게 발급됩니다.

작동 방식

Android 앱용 '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를 보여줍니다. 이러한 속성은 배열이므로 하나 이상의 패스 클래스 또는 패스 객체를 허용할 수 있습니다. 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": ""
        }
      }]
    }
  }