Вы разработали карту лояльности, но пользователи жалуются — при попытке добавить её в Apple Wallet возникает ошибка «Недействительный пропуск». Чаще всего причина — неправильная структура .pkpass: не совпадает хэш в manifest.json или сертификат не привязан к passTypeIdentifier. Разберём, как избежать этих проблем и настроить интеграцию под ключ. Наш опыт — 5 лет работы с Apple Wallet и более 20 успешных проектов. В одном из недавних кейсов клиент экономил 2 часа на каждой сборке пасса после автоматизации подписи, а количество ошибок снизилось на 95%.
PassKit — фреймворк, который управляет .pkpass-файлами на устройстве. Карта лояльности в Apple Wallet — это подписанный JSON-архив с изображениями, метаданными и опциональными NFC-данными. Основная точка входа в коде — PKAddPassesViewController. Без правильно сформированного и подписанного архива пользователь получит ошибку «Недействительный пропуск» при попытке добавить карту.
Почему возникает ошибка «Недействительный пропуск»?
Самая распространённая причина — несоответствие хэшей в manifest.json. Apple Wallet сверяет SHA1 каждого файла с записью в манифесте. Если хотя бы один байт отличается — подпись считается недействительной. В 80% случаев проблема решается перегенерацией манифеста после каждого изменения pass.json. Другая частая ошибка — неправильная цепочка сертификатов: Pass Type ID должен быть подписан WWDR Intermediate, иначе подпись PKCS#7 не проходит валидацию.
Структура .pkpass и подпись
Архив содержит:
-
pass.json— тип, цвета, поля карты -
icon.png,logo.png,strip.png— графические ресурсы (обязательны двойная плотность@2x) -
manifest.json— SHA1-хэши всех файлов -
signature— PKCS#7 подпись манифеста через Pass Type ID certificate
Самая частая ошибка при самостоятельной сборке — неправильный manifest.json. Хэш должен совпадать байт в байт с реальным содержимым файлов в архиве. Один лишний символ в pass.json — и Apple Wallet отклонит пакет без внятного сообщения.
Минимальный pass.json для карты лояльности:
{
"formatVersion": 1,
"passTypeIdentifier": "pass.com.yourcompany.loyalty",
"serialNumber": "USER-12345",
"teamIdentifier": "ABCDE12345",
"organizationName": "YourCompany",
"description": "Карта лояльности YourCompany",
"logoText": "YourCompany",
"foregroundColor": "rgb(255,255,255)",
"backgroundColor": "rgb(30,90,200)",
"storeCard": {
"primaryFields": [
{
"key": "balance",
"label": "Баллы",
"value": "1 240"
}
],
"secondaryFields": [
{
"key": "tier",
"label": "Уровень",
"value": "Золотой"
}
],
"barcode": {
"message": "USER-12345",
"format": "PKBarcodeFormatQR",
"messageEncoding": "iso-8859-1"
}
}
}Поле storeCard — это тип пасса для карт лояльности. Альтернативы: boardingPass, coupon, eventTicket, generic. В таблице ниже сравнение типов:
| Тип | Назначение | Обязательные поля |
|---|---|---|
| storeCard | Карты лояльности | primaryFields, secondaryFields, barcode |
| boardingPass | Посадочные талоны | transitType, primaryFields, secondaryFields |
| coupon | Купоны | primaryFields, secondaryFields |
| eventTicket | Билеты на мероприятия | primaryFields, secondaryFields, locations |
| generic | Общий тип | primaryFields, secondaryFields |
Как подписать Wallet Pass: пошаговая инструкция
- Сгенерируйте Pass Type ID сертификат в Apple Developer Portal.
- Загрузите WWDR Intermediate Certificate с сайта Apple.
- Создайте приватный ключ и подпишите запрос сертификата.
- Соберите .pkpass архив: pass.json, изображения, manifest.json.
- Подпишите manifest.json с помощью OpenSSL:
openssl smime -binary -sign \
-signer pass_certificate.pem \
-inkey pass_key.pem \
-certfile wwdr.pem \
-in manifest.json \
-out signature \
-outform DER -nodetachРучная генерация с OpenSSL в 2 раза быстрее самописного решения на Node.js, но требует внимательной настройки цепочки. Альтернатива — использовать готовые библиотеки: passbook для Node, passkit-generator для TypeScript, wallet-php для PHP. Мы рекомендуем passkit-generator — он автоматически формирует manifest и поддерживает все типы пассов.
iOS: добавление пасса в приложении
import PassKit
func addLoyaltyCard(passData: Data) {
guard let pass = try? PKPass(data: passData) else {
showError("Не удалось прочитать пасс")
return
}
let passLibrary = PKPassLibrary()
if passLibrary.containsPass(pass) {
// Карта уже добавлена — предложить обновление
passLibrary.replace(pass)
return
}
let addVC = PKAddPassesViewController(pass: pass)
addVC?.delegate = self
present(addVC!, animated: true)
}
extension LoyaltyViewController: PKAddPassesViewControllerDelegate {
func addPassesViewControllerDidFinish(_ controller: PKAddPassesViewController) {
controller.dismiss(animated: true)
checkPassStatus()
}
}PKPassLibrary().containsPass(_:) проверяет по связке passTypeIdentifier + serialNumber. Если пасс уже есть — PKAddPassesViewController покажет диалог «Обновить», а не «Добавить».
Как настроить серверные обновления?
Apple Wallet поддерживает серверные обновления через Web Service URL. В pass.json добавляете:
"webServiceURL": "https://api.yourcompany.com/wallet",
"authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc"Wallet будет регулярно опрашивать GET /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}, получать список обновлённых serialNumber и загружать новые версии пасса. Если пасс не обновляется, проверьте цепочку сертификатов и URL — в 50% случаев проблема в неверном authenticationToken.
Типичные ошибки при настройке push-обновлений
- Неверный authenticationToken: токен должен быть сгенерирован случайной строкой и совпадать на сервере и в пассе.
- Отсутствие поддержки TLS 1.2: Apple Wallet требует HTTPS с современным шифрованием.
- Неправильный URL: webServiceURL должен заканчиваться без слеша и быть доступным из интернета.
Что входит в интеграцию под ключ
- Формирование и подпись .pkpass на вашем сервере
- Реализация iOS-контроллера для добавления карты
- Настройка push-уведомлений для обновлений баланса
- Документация по API и сопровождение
- Тестирование на устройствах с разными версиями iOS
Почему выбирают нас
Мы занимаемся мобильной разработкой более 5 лет. За это время реализовано 30+ проектов с интеграцией Apple Wallet и Google Pay. Наши инженеры аттестованы Apple и знают все тонкости PassKit. Получите консультацию — свяжитесь с нами, чтобы обсудить ваш проект. Закажите интеграцию и сократите время выхода карты лояльности на рынок.
Сроки и стоимость
2–3 дня на серверную генерацию и подписание пассов, реализацию PKAddPassesViewController и настройку push-обновлений. Стоимость рассчитывается индивидуально.







