Інтеграція 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": "uk", "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
Перед виходом в прод авіаційний видавець повинен пройти верифікацію на Google Pay & Wallet Console. Для тестування достатньо тестового акаунта, доданого в Test Devices.
Тривалість
2–3 дні. Серверна генерація JWT з BCBP-штрих-кодом, інтеграція кнопки, тестування — 2 дні. Налаштування автооновлень статусу рейсу — додатково 0,5–1 день. Вартість розраховується індивідуально.







