Інтеграція Apple Wallet для квитків на заходи в мобільних додатках
Квиток на концерт або конференцію — це архів типу eventTicket .pkpass. На відміну від boardingPass, немає transitType, структура полів інша, і особливу увагу необхідно звернути на поле strip.png — воно формує "заголовок" з зображенням заходу. Без strip.png правильного розміру (624×246 @1x або 1248×492 @2x) карточка виглядає голо та безлико.
pass.json для eventTicket
{
"formatVersion": 1,
"passTypeIdentifier": "pass.com.yourtickets.event",
"serialNumber": "EVT-CONCERT-2024-USER42",
"teamIdentifier": "ABCDE12345",
"organizationName": "YourTickets",
"description": "Квиток на концерт Івана Іванова",
"foregroundColor": "rgb(255,255,255)",
"backgroundColor": "rgb(20,20,20)",
"labelColor": "rgb(180,180,180)",
"eventTicket": {
"primaryFields": [
{ "key": "event", "value": "Концерт Івана Іванова", "label": "Захід" }
],
"secondaryFields": [
{ "key": "venue", "value": "Олімпійський", "label": "Місце проведення" },
{ "key": "date", "value": "2024-09-21T20:00+03:00", "label": "Дата",
"dateStyle": "PKDateStyleMedium", "timeStyle": "PKDateStyleShort" }
],
"auxiliaryFields": [
{ "key": "seat", "value": "Сектор A, ряд 5, місце 12", "label": "Місце" },
{ "key": "category", "value": "VIP", "label": "Категорія" }
],
"backFields": [
{ "key": "order", "label": "Номер замовлення", "value": "ORD-987654" },
{ "key": "rules", "label": "Правила входу", "value": "Вход не ранше ніж за 30 хвилин до початку" }
],
"barcode": {
"message": "EVT-CONCERT-2024-USER42",
"format": "PKBarcodeFormatQR",
"messageEncoding": "iso-8859-1",
"altText": "EVT-CONCERT-2024-USER42"
}
},
"relevantDate": "2024-09-21T19:30+03:00",
"expirationDate": "2024-09-21T23:59+03:00",
"locations": [
{
"latitude": 55.7806,
"longitude": 37.5617,
"relevantText": "Ви рядом з місцем проведення заходу"
}
]
}
expirationDate — після цієї дати Wallet автоматично переміщає пас в архів та пропонує його видалити.
Валідація QR при сканування
Вміст barcode message — це те, що сканер на вході читає. Логіка валідації повністю на сервері: сканер надсилає рядок на POST /tickets/validate, сервер перевіряє статус квитка в базі даних та повертає valid/already_scanned/invalid.
Важливо: сам файл .pkpass не містить інформації про те, чи був квиток використаний. Дані про сканування зберігаються лише на сервері.
Захист від скриншотів
QR-коди у Wallet неможливо захистити від скриншотів за допомогою функцій iOS. Для заходів з високим ризиком перепродажу використовуйте обертовий штрих-код — поле barcode.message у pass.json оновлюється кожні 30–60 секунд через APN push. Навіть якщо користувач зробить скриншот, він стане недійсним протягом хвилини.
Реалізація: сервер зберігає seed для кожного квитка, генерує TOTP-подібний код, надсилає push до Wallet → пристрій запитує новий .pkpass → старий QR застаріває.
Групові квитки
Якщо одне замовлення містить кілька місць — кожен квиток є окремим .pkpass з власним serialNumber. Не можна групувати кілька пасів в один архів. Для групової відправки в додатку використовуйте PKAddPassesViewController(passes:):
let passes = ticketDataArray.compactMap { try? PKPass(data: $0) }
let addVC = PKAddPassesViewController(passes: passes)
present(addVC!, animated: true)
Контролер відображає всі квитки списком — користувачі додають їх одним дотиком.
Тривалість
2–3 дні: генерація пасів eventTicket на сервері, реалізація серверного API валідації QR, реалізація обертового штрих-кода при необхідності. Вартість розраховується індивідуально.







