Процесс разработки Google Wallet Pass

API Google Кошелька предоставляет заранее определенный набор типов пропусков, оптимизированных для конкретных случаев использования, таких как подарочные карты, посадочные талоны, билеты на мероприятия и многое другое. Существует также общий тип пропуска, предназначенный для случаев, когда определенный тип пропуска недоступен.

Цель этой статьи — ознакомить вас с основными шагами, необходимыми для создания и выдачи пропуска с помощью API Google Кошелька. Существует несколько способов выполнить некоторые этапы, подробно описанные ниже, но на высоком уровне все типы проходов создаются в соответствии с одним и тем же базовым потоком разработки.

Подробное описание создания пропуска см. в руководствах для веб-приложений, приложений электронной почты, SMS или Android .

Для чего это нужно

Класс проходов определяет набор свойств, которые являются общими для нескольких проходов, аналогично шаблону. Например, если вы выписывали билеты на мероприятие, класс Passes будет определять поля, одинаковые для всех билетов, такие как название мероприятия, дата и время.

Каждый выдаваемый вами пропуск должен ссылаться на класс Passes. Вы также должны назначить уникальный идентификатор каждому создаваемому вами классу пропусков, который будет использоваться для ссылки на него при создании проходов.

Как это сделано

Класс Passes определяется в формате JSON и может быть создан с помощью REST API Google Кошелька, Android SDK или в бизнес-консоли Google Wallet.

Показать пример Проходит класс

{
  "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"
      }
    }
  }
}
    

Для чего это нужно

Объект Passes определяет свойства уникального пропуска, который будет выдан конкретному пользователю. Например, объект Passes для билета на мероприятие будет определять поля, уникальные для конкретного билета, такие как номер места или QR-код для этого билета.

При создании объекта Passes API Google Wallet сохраняет новый пропуск и связывает его с вашей учетной записью эмитента. Этот сохраненный проход представляет собой комбинацию уникальных свойств объекта Passes и свойств шаблона связанного класса Passes.

Вы также должны присвоить каждому объекту Passes уникальный идентификатор, который будет использоваться для ссылки на него при выдаче пропуска.

Как это сделано

Объект Passes имеет определенный формат JSON и может быть создан с помощью REST API Google Кошелька или 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": ""
  }
}
    

Для чего это нужно

Чтобы выдать пропуск пользователю, класс Passes и объект Passes должны быть закодированы в веб-токене JSON (JWT). Формат JWT — это общий и открытый стандарт для представления претензий между двумя сторонами. В случае выдачи пропусков с помощью API Google Кошелька JWT используются для отправки заявления о том, что пользователь имеет право на доступ к определенному пропуску, связанному с вашей учетной записью эмитента.

Когда JWT отправляется в API Google Кошелька, закодированные данные используются для идентификации конкретного прохода и выдачи его пользователю. Если пропуск уже выдан, эти данные также позволяют API Google Кошелька определить, что пропуск является дубликатом, чтобы он не добавлялся в Google Кошелек пользователя более одного раза.

Как это сделано

JWT определяются в формате JSON на основе спецификации JWT . Чтобы определить JWT для выдачи пропуска с помощью API Google Кошелька, вы предоставляете информацию о пропуске, который хотите выдать, в свойстве 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"
      }
    ]
  }
}
    

Для чего это нужно

Все JWT, отправляемые в API Google Кошелька для выдачи пропуска, должны быть подписаны учетными данными, которые вы ранее предоставили в бизнес-консоли Google Кошелька. При подписании используются ваши учетные данные для шифрования JWT, чтобы ваши пропуски оставались в безопасности, а также чтобы API Google Кошелька мог подтвердить, что закодированные в нем данные пропуска действительны и связаны с вашей учетной записью эмитента.

Как это сделано

Клиентские библиотеки Google Кошелька и Android SDK предоставляют удобные методы для подписи ваших JWT. Существует также множество доступных библиотек с открытым исходным кодом, которые решают сложные задачи подписи кода, из которых вы можете выбирать.

Для тех, кто использует REST API Google Кошелька для выдачи пропусков, JWT подписывается ключом учетной записи облачной службы Google. Для тех, кто использует Google Wallet Android SDK, SDK автоматически подписывает JWT с помощью отпечатка SHA-1 вашего сертификата подписи приложения.

Чтобы защитить ваши учетные данные, JWT следует подписывать только на вашем сервере или с помощью Google Wallet Android SDK в вашем приложении.

Показать пример подписи кода

Джава

  // 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' });
        

Питон

  # 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 отправляется в API Google Кошелька, который затем расшифровывает его, используя сохраненные учетные данные. После аутентификации подписи JWT пользователю будет выдан пропуск для сохранения в его Google Кошельке.

Как это сделано

Чтобы создать кнопку «Добавить в Google Кошелек» для приложения Android, используйте Google Wallet Android SDK, который предоставляет методы для создания кнопки. Для всех других платформ, включая Интернет, электронную почту и текстовые сообщения, создайте гиперссылку в формате https://pay.google.com/gp/v/save/<signed_jwt> . По возможности лучше всего доставить эту ссылку пользователю в виде кнопки «Добавить в Google Кошелек».

Дополнительную информацию об использовании кнопки «Добавить в Google Кошелек» см. в рекомендациях по использованию бренда API Google Кошелька.

Показать пример кода

  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 Кошелька вместе со всеми другими сохраненными им пропусками.

Создание объектов Passes и классов Passes в JWT

Классы Passes и объекты Passes можно создать заранее с помощью REST API Google Кошелька или Android SDK. После создания они затем используются для выдачи пропусков, ссылаясь на их идентификатор.

В качестве альтернативы вы также можете создавать классы Passes и объекты Passes «точно в срок», встраивая их JSON непосредственно в JWT, который используется для выдачи пропуска пользователю. В этом методе классы Passes и объекты Passes создаются API Google Кошелька, когда подписанный JWT отправляется с помощью кнопки или ссылки «Добавить в Google Кошелек».

Например, ниже показан JWT с новым классом Passes и объектом Passes, определенным с использованием свойств payload.eventTicketClasses и payload.eventTicketObjects . Обратите внимание, что эти свойства представляют собой массивы, поэтому они могут принимать один или несколько классов Passes или объектов 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": ""
        }
      }]
    }
  }