Вы разработали карту лояльности, но пользователи жалуются — при попытке добавить её в 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-обновлений. Стоимость рассчитывается индивидуально.







