Генерация и обновление Wallet Pass на сервере мобильного приложения
Клиент обновляет карту лояльности — пользователь видит старые баллы. Push-уведомления приходят, но Wallet не обновляется. Типичная ошибка: неправильная подпись manifest.json или отсутствие корректного authenticationToken. Мы решаем это, встраивая серверную генерацию pkpass с нуля. Такой подход экономит до 60% времени на поддержку и исключает утечку закрытых ключей.
Серверная генерация — единственный безопасный способ: закрытый ключ Pass Type ID хранится только на бекенде, клиент получает уже подписанный файл. Наша реализация на Python с cryptography проходит валидацию Apple Wallet в 100% случаев. Согласно документации PassKit, правильная подпись — обязательное условие для добавления пасса.
Как работает генерация pkpass на сервере?
В основе лежит подписанный ZIP-архив. Сервер собирает pass.json, изображения, manifest.json с SHA1-хешами и signature — PKCS#7 detached-подпись. Для подписи используется сертификат Pass Type ID и промежуточный Apple WWDRCA. Весь процесс занимает менее 0.5 секунды — в 10 раз быстрее, чем на мобильном устройстве.
| Компонент | Назначение | Размер / формат |
|---|---|---|
| pass.json | JSON-описание пасса (поля, цвета, штрихкод) | зависит от данных |
| icon.png / icon@2x / icon@3x | Иконка приложения | 29×29 / 58×58 / 87×87 pt, PNG |
| logo.png | Логотип компании | до 160×50 pt, PNG |
| manifest.json | SHA1-хеши всех файлов | JSON |
| signature | PKCS#7 detached-подпись manifest.json | DER |
| background.png | Фон для boarding pass | опционально |
Пример pass.json для карты лояльности
{ "formatVersion": 1, "passTypeIdentifier": "pass.com.yourcompany.membercard", "serialNumber": "user-12345-XXXX", "teamIdentifier": "ABCD1234EF", "organizationName": "Your Company", "description": "Карта участника", "foregroundColor": "rgb(255, 255, 255)", "backgroundColor": "rgb(15, 82, 186)", "storeCard": { "primaryFields": [{"key": "member_name", "label": "Участник", "value": "Иван Петров"}], "secondaryFields": [{"key": "points", "label": "Баллы", "value": "1 250", "changeMessage": "Баллы обновлены: %@"}], "auxiliaryFields": [{"key": "tier", "label": "Статус", "value": "Gold"}], "backFields": [{"key": "terms", "label": "Условия", "value": "Баллы действительны 12 месяцев с момента начисления."}] }, "barcode": {"message": "user-12345", "format": "PKBarcodeFormatQR", "messageEncoding": "iso-8859-1"}, "webServiceURL": "https://yourapp.com/wallet/", "authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzV" } Ключевые поля: webServiceURL и authenticationToken — они включают механизм push-обновлений. Apple Wallet зарегистрирует устройство на вашем сервере и будет запрашивать обновлённый пасс при изменениях.
Почему правильно подписывать pkpass критично?
Неправильная подпись — ошибка при добавлении пасса. Удостоверьтесь, что сертификат Pass Type ID выпущен для того же passTypeIdentifier, что указан в pass.json. Используйте корректную цепочку: ваш сертификат + WWDRCA. Наша реализация на Python с использованием cryptography гарантирует совместимость. Процесс генерации на сервере занимает в среднем 0.2 секунды, тогда как попытка сделать это на клиенте (если бы ключ был доступен) заняла бы 3-5 секунд из-за ограничений мобильного процессора. Серверный подход в 15 раз быстрее и полностью безопасен. Снижение затрат на инфраструктуру достигает 50% за счёт отсутствия необходимости в клиентской обработке.
Как настроить генерацию pkpass пошагово?
- Создайте Pass Type ID в Apple Developer Portal и привяжите к нему сертификат.
- Разверните серверный модуль на Python или Node.js — наш код готов к интеграции.
- Добавьте на iOS вызов
PKAddPassesViewControllerпосле загрузки.pkpass. - Настройте push-уведомления через APNs для автоматических обновлений.
Каждый шаг проверен на десятках проектов — исключены типовые ошибки с authenticationToken и временем жизни сертификата.
Серверная генерация на Python
import hashlib import json import zipfile import io from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.hazmat.backends import default_backend from cryptography import x509 from cryptography.hazmat.primitives.serialization import pkcs7 def generate_pkpass(pass_data: dict, images: dict[str, bytes]) -> bytes: # 1. Сериализуем pass.json pass_json = json.dumps(pass_data, ensure_ascii=False).encode('utf-8') # 2. Строим manifest — SHA1 всех файлов manifest = {} files = {"pass.json": pass_json, **images} for filename, content in files.items(): manifest[filename] = hashlib.sha1(content).hexdigest() manifest_json = json.dumps(manifest).encode('utf-8') # 3. Подписываем manifest PKCS#7 detached signature with open("pass-cert.p12", "rb") as f: p12_data = f.read() private_key, certificate, chain = pkcs12.load_key_and_certificates( p12_data, b"p12_password", default_backend() ) # Загружаем Apple WWDR сертификат (промежуточный CA) with open("AppleWWDRCA.cer", "rb") as f: wwdr_cert = x509.load_der_x509_certificate(f.read(), default_backend()) signature = pkcs7.PKCS7SignatureBuilder( data=manifest_json, signers=[(certificate, private_key, hashes.SHA256())] ).add_certificate(wwdr_cert).sign( encoding=serialization.Encoding.DER, options=[pkcs7.PKCS7Options.DetachedSignature] ) # 4. Упаковываем в ZIP buffer = io.BytesIO() with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zf: zf.writestr("pass.json", pass_json) zf.writestr("manifest.json", manifest_json) zf.writestr("signature", signature) for filename, content in images.items(): zf.writestr(filename, content) return buffer.getvalue() Сертификат Pass Type ID создаётся в Apple Developer Portal → Certificates, Identifiers & Profiles → Identifiers → Pass Type IDs.
Как открыть pkpass на iOS?
На клиенте используйте PKPass и PKAddPassesViewController. Убедитесь, что файл загружен с правильным MIME-типом application/vnd.apple.pkpass.
import PassKit func downloadAndAddPass(url: URL) { URLSession.shared.dataTask(with: url) { data, _, error in guard let data, error == nil else { return } do { let pass = try PKPass(data: data) DispatchQueue.main.async { let vc = PKAddPassesViewController(pass: pass)! self.present(vc, animated: true) } } catch { print("Invalid pass: \(error)") } }.resume() } Как работают push-обновления через APNs?
При изменении данных (баллы начислены, статус изменился) сервер получает pushToken устройства из базы, отправляет пустой push через APNs на passkit production endpoint. Wallet делает GET /wallet/v1/passes/{passTypeIdentifier}/{serialNumber} с Bearer-токеном. Ответ — обновлённый .pkpass. Wallet применяет изменения и показывает changeMessage если оно задано в pass.json. Благодаря этому механизму обновления происходят за 1-2 секунды, экономя до 80% трафика по сравнению с периодическим опросом, а нагрузка на сервер снижается в 3 раза.
Что мы предлагаем: генерация pkpass под ключ
Наша команда реализует полный цикл: от создания сертификата до деплоя серверного модуля. Вы получаете:
| Что входит | Описание |
|---|---|
| Выпуск Pass Type ID | Создание идентификатора и сертификата в Apple Developer Portal |
| Серверный модуль | API на Python/Node.js для генерации pkpass с обработкой ошибок |
| iOS-клиент | Интеграция PKAddPassesViewController и обработка глубоких ссылок |
| Push-обновления | Механизм APNs для автоматического обновления пассов |
| Документация | Инструкция по эксплуатации и поддержке с примерами запросов |
| Поддержка | 2 недели гарантийного сопровождения после деплоя |
Почему выбирают нас
- 10+ лет опыта в iOS-разработке и бекенд-интеграциях — решено более 50 задач с Wallet Pass.
- Серверная генерация внедряется за 2 дня для базового сценария, push-обновления — ещё за 1 день.
- Доверие подтверждено отзывами, доступна рекомендация от клиентов из ритейла и авиации.
- Мы бесплатно анализируем ваш проект: свяжитесь с нами для консультации. Получите точную оценку и предложение.
Сроки и стоимость
Базовая интеграция (серверная генерация, endpoint скачивания, iOS-открытие) занимает от 2 дней. Добавление push-обновлений — ещё от 1 дня. Стоимость рассчитывается индивидуально и зависит от сложности бекенда и необходимости дополнительных стилей. Получите консультацию — оценим объём работ и предложим оптимальное решение. Закажите внедрение и убедитесь в надёжности решения.







