Интеграция Google Wallet для посадочных талонов в мобильном приложении
Посадочный талон в Google Wallet — это FlightObject поверх FlightClass. Класс описывает рейс (авиакомпания, номер, маршрут), объект — конкретный пассажир и место. Главное отличие от EventTicket: Google Wallet автоматически обновляет статус рейса (задержка, изменение ворот) через интеграцию с авиационными базами данных — если правильно заполнить поля flightHeader.
FlightClass и FlightObject: структура
def create_flight_class(flight_number: str, origin: str, destination: str,
departure_time: str) -> dict:
issuer_id = "YOUR_ISSUER_ID"
class_id = f"{issuer_id}.flight_{flight_number}"
return {
"id": class_id,
"issuerName": "AirCompany",
"flightHeader": {
"carrier": {
"carrierIataCode": "SU", # IATA-код авиакомпании
"airlineLogo": {
"sourceUri": {"uri": "https://yourapp.com/logo.png"}
},
"airlineName": {
"defaultValue": {"language": "ru", "value": "Аэрофлот"}
}
},
"flightNumber": flight_number,
"operatingCarrier": {
"carrierIataCode": "SU"
}
},
"origin": {
"airportIataCode": origin, # "SVO"
"terminal": "D",
"gate": "D12"
},
"destination": {
"airportIataCode": destination # "LED"
},
"localScheduledDepartureDateTime": departure_time, # "2024-06-15T14:30:00"
"reviewStatus": "UNDER_REVIEW" # или APPROVED после прохождения верификации
}
def create_flight_object(class_id: str, passenger_name: str,
seat: str, booking_ref: str) -> dict:
object_id = f"YOUR_ISSUER_ID.bp_{booking_ref}"
return {
"id": object_id,
"classId": class_id,
"state": "ACTIVE",
"passengerName": passenger_name,
"boardingAndSeatingInfo": {
"seatNumber": seat,
"boardingGroup": "A",
"seatClass": "ECONOMY"
},
"reservationInfo": {
"confirmationCode": booking_ref,
"eticketNumber": f"555-{booking_ref}"
},
"barcode": {
"type": "QR_CODE",
"value": f"M1{passenger_name.upper().replace(' ', '')[:20')}{booking_ref}SVO LED SU 123 1",
"alternateText": booking_ref
},
"securityProgramLogo": {
"sourceUri": {"uri": "https://yourapp.com/security-badge.png"}
}
}
Поле barcode.value для авиабилетов — это BCBP (Bar Coded Boarding Pass) строка по стандарту IATA. Сканеры в аэропорту ожидают именно этот формат, а не произвольный ID.
JWT и передача в приложение
def generate_boarding_pass_jwt(flight_object: dict) -> str:
payload = {
"iss": service_account_email,
"aud": "google",
"typ": "savetowallet",
"iat": int(time.time()),
"payload": {
"flightObjects": [flight_object]
}
}
return jwt.encode(payload, private_key, algorithm="RS256")
Android: сохранение посадочного талона
fun saveBoardingPass(jwt: String) {
val request = SavePassesRequest.newBuilder().setJwt(jwt).build()
walletClient.savePassesViaIntent(request) { result ->
result.intentSender?.let { sender ->
addToWalletLauncher.launch(
IntentSenderRequest.Builder(sender).build()
)
} ?: run {
// Пасс уже добавлен — обновляем через API
showAlreadySaved()
}
}
}
Если intentSender равен null, пасс с таким objectId уже есть в Wallet — Google не предлагает добавить дубликат. Это нормальное поведение.
Автоматические уведомления об изменениях рейса
Это главная фича FlightObject по сравнению с GenericObject. Google отслеживает статус рейса по carrierIataCode + flightNumber + localScheduledDepartureDateTime. При задержке или изменении ворот пользователь получает уведомление от Google Wallet автоматически — без дополнительной логики на вашей стороне.
Для этого reviewStatus класса должен быть APPROVED, а данные рейса должны совпадать с авиационными базами. Статус UNDER_REVIEW — класс ещё не верифицирован Google, автоматические обновления не работают.
Верификация Issuer Account
Перед выходом в прод авиационный issuer должен пройти верификацию в Google Pay & Wallet Console. Для тестирования достаточно тестового аккаунта, добавленного в Тестовые устройства.
Сроки
2–3 дня. Серверная генерация JWT с BCBP-штрихкодом, интеграция кнопки, тестирование — 2 дня. Настройка автообновлений статуса рейса — дополнительно 0,5–1 день. Стоимость рассчитывается индивидуально.







