Процесс разработки карт для Google Кошелька
Google Wallet API предоставляет набор типов карт, оптимизированных для определенных сценариев использования, таких как подарочные карты, посадочные талоны, билеты на мероприятия и т. д. Также есть универсальные карты, которые можно использовать, если ни один из типов не подходит.
В этой статье рассказывается, как создать и выпустить карту с помощью Google Wallet API. Некоторые из описанных ниже шагов можно выполнить разными способами, но в целом все типы карт создаются по одному и тому же базовому процессу разработки.
Подробные инструкции по созданию карт вы найдете в руководствах для веб-сайтов, электронной почты и SMS и приложений Android.
1. Создайте класс билетов
Назначение
Класс карт определяет набор свойств, общих для нескольких карт, аналогично шаблону. Например, если вы выпускаете билеты на мероприятие, в классе карт будут определены поля, одинаковые для всех билетов, такие как название события, дата и время мероприятия.
Каждая выпущенная вами карта должна ссылаться на класс карт. Каждому классу карт нужно присвоить уникальный идентификатор, который будет использоваться при создании карт.
Как это делается
Класс карт и билетов определяется в формате JSON и может быть создан с помощью Google Кошелька REST API, Android SDK или Google Wallet Business Console.
Показать пример класса Passes
{ "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" } } } }
2. Создайте объект Passes API
Назначение
Объект Passes определяет свойства уникальной карты, которая будет выпущена для определенного пользователя. Например, объект карты для билета на мероприятие определяет поля, уникальные для конкретного билета, такие как номер места или QR-код для этого билета.
При создании объекта Passes API Google Wallet сохраняет новую карту и связывает ее с вашим аккаунтом эмитента. Сохраненная карта сочетает в себе уникальные свойства объекта Passes Object и свойства шаблона связанного класса Passes Class.
Каждому объекту Passes Object необходимо присвоить уникальный идентификатор, который будет использоваться для ссылки на него при выпуске карты.
Как это делается
Объект Passes определяется в формате JSON и может быть создан с помощью Google Кошелька REST API или Android SDK.
Показать пример объекта Passes Object
{ "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": "" } }
3. Закодируйте карту в веб-токене JSON (JWT)
Назначение
Чтобы выпустить карту для пользователя, класс и объект карты должны быть закодированы в веб-токене JSON (JWT). Формат JWT – это распространенный открытый стандарт для представления утверждений между двумя сторонами. При выпуске карт с помощью Google Wallet API JWT используются для отправки утверждения о том, что пользователь имеет право на доступ к определенной карте, связанной с вашим аккаунтом эмитента.
Когда JWT отправляется в Google Wallet API, закодированные данные используются для идентификации определенной карты и ее выпуска для пользователя. Если карта уже выпущена, эти данные также позволяют Google Wallet API определить, что карта является дубликатом, чтобы она не была добавлена в Google Кошелек пользователя более одного раза.
Как это делается
Токены JWT определяются в формате JSON на основе спецификации JWT. Чтобы определить JWT для выпуска карты с помощью Google Wallet API, укажите информацию о карте в свойстве payload токена JWT.
Показать пример JWT
{ "iss": "issuer@example.com", "aud": "google", "typ": "savetowallet", "iat": 1696877738, "origins": [ "www.example.com" ], "payload": { "eventTicketObjects": [ { "id": "ISSUER_ID.LOYALTY_OBJECT_SUFFIX" } ] } }
4. Подпишите JWT своими учетными данными
Назначение
Все JWT, отправленные в Google Wallet API для выпуска карты, должны быть подписаны с использованием учетных данных, которые вы ранее указали в Google Wallet Business Console. При подписании используются ваши учетные данные для шифрования JWT, чтобы ваши карты оставались в безопасности, а Google Wallet API мог подтвердить, что закодированные в нем данные карты действительны и связаны с вашим аккаунтом эмитента.
Как это делается
Клиентские библиотеки Google Кошелька и Android SDK предоставляют удобные методы для подписи JWT. Также существует множество библиотек с открытым исходным кодом, которые упрощают подписание кода.
Если вы используете Google Wallet REST API, то JWT подписывается ключом сервисного аккаунта Google Cloud. Если вы используете Google Кошелек Android SDK, то он автоматически подписывает JWT с помощью цифрового отпечатка SHA-1 сертификата подписи приложения.
Чтобы защитить учетные данные, JWT-токены должны подписываться только на вашем сервере или с помощью Google Кошелька Android SDK в вашем приложении.
Показать пример подписи кода
Java
// 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')
5. Выпустите карту с кнопкой или ссылкой "Добавить в Google Кошелек"
Назначение
После создания подписанного JWT вы можете выпустить карту для пользователя Google Кошелька. Для этого нужно добавить кнопку или ссылку "Добавить в Google Кошелек". Когда пользователь нажимает на кнопку или гиперссылку, подписанный JWT отправляется в Google Wallet API, который затем расшифровывает его с помощью сохраненных учетных данных. После аутентификации подписи JWT карта будет выпущена и пользователь сможет сохранить ее в Google Кошельке.
Как это делается
Используйте Google Кошелек Android SDK для нативных приложений Android. Для всех остальных платформ, включая приложения для iOS, обычные и мобильные сайты, электронные письма и текстовые сообщения, создайте гиперссылку в формате 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) } }
6. Показать в Кошельке
После того как пользователь сохранит выпущенную карту, она появится в его приложении "Google Кошелек" вместе с другими сохраненными картами.
Как создавать объекты и классы карт в JWT
Классы и объекты карт и билетов можно создавать заранее с помощью Google Кошелька REST API или Android SDK. После создания класса его идентификатор используется для выпуска карт.
Вы также можете создавать классы и объекты карт непосредственно перед выпуском карты, встраивая их JSON-код прямо в JWT, который используется для выпуска карты пользователю. При использовании этого метода классы и объекты карт создаются с помощью Google Wallet API, когда подписанный JWT отправляется с помощью кнопки или ссылки "Добавить в Google Кошелек".
Например, ниже показан JWT с новым классом и объектом билетов, определенных с помощью свойств payload.eventTicketClasses и payload.eventTicketObjects. Обратите внимание, что эти свойства являются массивами, поэтому они могут принимать один или несколько классов или объектов Passes. Вы также можете указать в JWT только новый объект Passes, который ссылается на существующий класс Passes по его идентификатору.
Показать пример 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": "" } }] } }