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







