Как я сделал электронную визитку для Apple и Google Wallet и что узнал о формате .pkpass

В Apple Wallet обычно хранят банковские карты, посадочные талоны, билеты и карты лояльности. Но мне захотелось использовать его немного иначе — сделать обычную визитку с контактными данными. В столе всегда валялось куча визиток, напечатанных на работе, но я постоянно забывал их брать, а на встречах краснел и диктовал телефон.
Идея была простая: открываю Wallet, показываю QR-код, другой человек сканирует его и получает предложение сохранить мои контактные данные прямо в записной книжке телефона, с названием фирмы, должностью, телефоном, Telegram, почтой, сайтом, в общем весь набор. Без установки приложений, регистрации и переходов на сторонние сайты.
Заодно стало интересно разобраться, как вообще устроены карточки Apple и Google Wallet и можно ли генерировать их самостоятельно.
Что скрывается внутри .pkpass
Первое открытие: .pkpass — это обычный ZIP-архив с определённой структурой. Никакой особой магии внутри нет.
Если переименовать файл в .zip и распаковать, можно увидеть примерно следующее:
business-card.pkpass
├── pass.json
├── manifest.json
├── signature
├── icon.png
├── icon@2x.png
└── logo.pngОсновной файл здесь — pass.json. В нём описывается карточка: название, цвета, поля, QR-код, идентификаторы разработчика и другие параметры.
Изображения отвечают за визуальное оформление. manifest.json содержит SHA-1-хэши файлов пакета, а signature — цифровую подпись.
И вот здесь начинается самое интересное. Просто собрать ZIP с правильным JSON недостаточно. Apple Wallet не примет карточку без корректной подписи.
Почему нельзя просто собрать ZIP
Чтобы выпустить собственный .pkpass, нужен Apple Developer Account, зарегистрированный Pass Type ID и сертификат для подписи.
Схема примерно такая:
Создаём
pass.jsonи изображения.Вычисляем SHA-1-хэши файлов и собираем
manifest.json.Подписываем манифест приватным ключом, созданным вместе с CSR для сертификата Pass Type ID, который получаем в Apple Developer Account, предварительно оплатив 99 $ в год (сертификат Pass Type ID тоже живёт примерно год, его нужно перевыпускать).
Добавляем промежуточный сертификат Apple WWDR в подпись.
Упаковываем файлы в ZIP и получаем
.pkpass.
Подпись должна быть откреплённой (detached PKCS#7/CMS) в формате DER.
Есть несколько моментов, которые стоит проверить, если Wallet отказывается принимать карточку: совпадает ли passTypeIdentifier с сертификатом, правильно ли указан teamIdentifier, действителен ли сертификат и включён ли WWDR, а также та ли версия WWDR.
Для локальной проверки подписи пригодится OpenSSL:
openssl smime -verify \
-inform DER \
-in signature \
-content manifest.json \
-noverify \
-out /dev/nullПравда, эта команда с -noverify проверяет криптографическую подпись, но не подтверждает доверие ко всей цепочке сертификатов. Хэши файлов в manifest.json тоже нужно сверять отдельно.
Как передать контакт без сервера
Саму визитку я решил строить вокруг QR-кода. Причём не с URL на сайт, как это часто делают, а непосредственно с контактными данными в формате vCard.
Простейший пример:
BEGIN:VCARD
VERSION:3.0
FN:Ivan Petrov
TEL;TYPE=CELL:+79991234567
EMAIL:ivan@example.com
ORG:Example
END:VCARDЭту строку можно закодировать в QR и добавить в pass.json в поле barcodes.
Плюс такого подхода очевиден: QR содержит сами данные. Для их передачи не требуется обращаться к серверу.
Но есть нюанс. Чем больше информации мы помещаем в vCard, тем плотнее становится QR-код. ФИО, пара телефонов, почта, должность, сайт, адрес — и код уже заметно сложнее считывать с экрана.
Поэтому я бы не советовал превращать QR в полноценное резюме. Для обычной визитки достаточно имени, телефона, почты, мессенджера и, возможно, ссылки на сайт.
Ещё один важный момент: QR-код с vCard не означает, что контакт автоматически попадёт в телефонную книгу. Телефон должен распознать формат, а пользователь — подтвердить сохранение.
И поведение здесь зависит от приложения, которым сканируют код.
Кириллица в QR: откуда берутся ????
Когда получилось добавить имя на русском, стали обнаруживаться странности с отсканированными данными. Имя на русском отображалось как вопросительные знаки. Немного разобравшись, стало ясно, что в pass.json в блоке barcodes нужно добавить поле messageEncoding: "utf-8". Это одна строка. Без неё Wallet кодирует содержимое QR в ISO-8859-1, и всё, чего нет в этой кодировке, портится. То есть всё, что написано кириллицей, выглядит так: имя «Анна Ветрова» превращается в «???? ???????».
Для сравнения, в pass.json это выглядит так:
"barcodes": [{
"format": "PKBarcodeFormatQR",
"message": "BEGIN:VCARD...",
"messageEncoding": "utf-8"
}]Что делать с Android
С Apple Wallet всё относительно понятно: собираем подписанный pass, отдаём файл с MIME-типом application/vnd.apple.pkpass, пользователь добавляет карточку.
С Android ситуация другая. Google Wallet использует собственную модель карточек, API и механизм выпуска. Просто взять .pkpass и добавить его в Google Wallet штатным способом не получится.
Поэтому для универсальной визитки я бы предусмотрел несколько вариантов:
Google Wallet — отдельная реализация карточки.
QR с vCard или скачиваемый
.vcf— как запасной вариант, не требующий Wallet.
При этом везде можно использовать одинаковые контактные данные.
Но надо сказать, что Google Wallet в России официально не работает. Для установки и запуска визитки могут потребоваться танцы с бубном, которые я не проходил, так как не имею подходящего девайса.
Почему я не стал усложнять всё обновлениями
Apple Wallet позволяет обновлять уже установленные карточки. Для этого есть webServiceURL, authenticationToken, регистрация устройств и push-уведомления.
Но для обычной визитки такая инфраструктура может оказаться избыточной.
Если человек меняет телефон или должность раз в несколько лет, проще выпустить новую карточку, чем поддерживать целую систему обновления пропусков. Технически такая система выглядит сложной и затратной.
Обратная сторона решения понятна: если контакт уже сохранили в телефонную книгу, его данные останутся прежними. Даже обновление самой карточки Wallet не изменит автоматически чужие контакты.
Что в итоге
Для себя я сделал несколько выводов:
.pkpass— довольно простой формат по структуре, но с обязательной криптографической подписью.Контактные данные можно поместить прямо в QR-код, без зависимости от сервера при сканировании.
Сохранять контакт без действий пользователя нельзя.
Apple Wallet и Google Wallet требуют разных механизмов выпуска карточек.
Не каждому проекту нужна серверная инфраструктура обновлений.
В результате получается довольно удобная вещь: электронная визитка всегда под рукой, а контакт можно передать буквально за несколько секунд.
И что мне особенно понравилось — для этого не нужно писать отдельное мобильное приложение, всё работает в штатной программе телефона.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.