Реалізація Family Sharing підписки в iOS-додатку
Сімейний доступ до підписок — функція, яку App Store підтримує, але на практиці її реалізація часто викликає проблеми. Один член сім’ї купує підписку, інші до 6 осіб отримують доступ автоматично. Однак якщо додаток неправильно обробляє revoke при виході користувача з сім’ї, доступ залишається — це втрата виручки (до 30% в деяких проектах). Ми, як розробники з досвідом понад 5 років і десятками реалізованих in-app покупок, вирішуємо це завдання під ключ. У цій статті розберемо коректне налаштування Family Sharing через StoreKit 2, тестування та типові помилки.
Як працює перевірка Family Sharing через StoreKit 2?
У StoreKit 2 кожна транзакція містить поле ownershipType: .purchased (купив сам) або .familyShared (отримав через сім’ю). Додаток зобов’язаний перевіряти обидва варіанти при старті та постійно слухати оновлення. Ось базова перевірка за допомогою Transaction.currentEntitlements:
for await verificationResult in Transaction.currentEntitlements { switch verificationResult { case .verified(let transaction): if transaction.productID == "com.app.premium" { switch transaction.ownershipType { case .purchased: grantAccess(source: .directPurchase) case .familyShared: grantAccess(source: .familySharing) @unknown default: break } } case .unverified: // не довіряємо транзакції — логуємо, не даємо доступ break } } Щоб підписка взагалі підтримувала Family Sharing, її потрібно ввімкнути в App Store Connect. У налаштуваннях In-App Purchase знайдіть продукт і активуйте перемикач «Family Sharing» → «On for all members». Це робиться один раз і не відміняється для вже куплених підписок.
Чому виникає розсинхронізація доступу після виходу з сім’ї?
Основна помилка — кешування статусу підписки без перевірки актуальності. Коли користувач покидає Family Group, транзакція .familyShared отримує revocationDate. Transaction.currentEntitlements перестає її повертати, але якщо додаток зберігає premium-статус у UserDefaults або Keychain, доступ залишиться. Наша практика показує: до 30% кейсів сімейного доступу містять цю проблему. Раніше реалізація з StoreKit 1 вимагала серверної валідації, що збільшувало вартість у 2 рази.
Правильне рішення — слухати Transaction.updates постійно, а не тільки при вході в додаток:
func listenForTransactionUpdates() { Task { for await verificationResult in Transaction.updates { if case .verified(let transaction) = verificationResult { if transaction.revocationDate != nil { revokeAccess() } else { await transaction.finish() grantAccess() } } } } } Цей код запускається при старті додатка і працює весь час життя процесу. Без нього навіть перевірка currentEntitlements при кожному відкритті може пропустити revoke, якщо додаток не перезапущено.
Що важливо при тестуванні Family Sharing?
Тестування в Xcode Sandbox не обійтись без кількох тестових Apple ID, об’єднаних у сім’ю. В App Store Connect → Users and Access → Sandbox Testers створіть мінімум двох користувачів, потім там же налаштуйте Family Sharing у Sandbox. Без цього кроку ви не зможете симулювати .familyShared транзакції. Ми гарантуємо повне покриття — перевіряємо сценарії покупки основним користувачем, отримання доступу членами сім’ї, вихід із сім’ї та повторний вхід.
Для наочності зведемо сценарії в таблицю:
| Сценарій | Дія | Очікуваний результат |
|---|---|---|
| Основний користувач купує підписку | Покупка через StoreKit 2 | Транзакція з ownershipType == .purchased |
| Член сім’ї отримує доступ | Автоматично через Family Sharing | Транзакція з ownershipType == .familyShared |
| Член сім’ї виходить із групи | Вихід через налаштування Apple ID | revocationDate встановлюється, доступ відкликається |
| Повторний вхід у сім’ю | Повернення в групу | Нова familyShared транзакція (якщо підписка ще активна) |
StoreKit 1 vs StoreKit 2: що обрати?
Старий API (SKPaymentTransaction) не надає ownershipType. Для перевірки family-shared транзакції в StoreKit 1 потрібна серверна валідація receipt — парсити поле in_app[].is_in_family_sharing. Це ускладнює архітектуру і збільшує час розробки. Порівняння підходів:
| Аспект | StoreKit 1 | StoreKit 2 |
|---|---|---|
| Перевірка ownershipType | Receipt validation на сервері | Поле ownershipType у транзакції |
| Складність | Висока (серверна частина обов’язкова) | Низька (на клієнті, без сервера) |
| Реакція на revoke | Потрібен окремий listener + серверна синхронізація | Вбудований Transaction.updates |
| Підтримка Swift Concurrency | Ні (тільки @escaping) | Так (async/await) |
Міграція на StoreKit 2 знижує час реалізації в 2–3 рази і зменшує кількість багів. Для нових проектів ми однозначно рекомендуємо його. Детальніше про StoreKit 2 — в офіційній документації Apple.
Що входить у нашу роботу
- Налаштування Family Sharing для продуктів в App Store Connect
- Реалізація перевірки
ownershipTypeчерез StoreKit 2 - Обробка revoke при виході з Family Group
- Постійний listener
Transaction.updatesпротягом життя додатка - Тестування з Sandbox-сім’єю (до 6 членів, кілька сценаріїв)
- Документація для серверної частини (якщо потрібна валідація на бекенді)
- Гарантія коректної роботи протягом 30 днів після здачі
Строки та вартість
Орієнтовний строк: 3–5 днів, включаючи налаштування App Store Connect і тестування на Sandbox акаунтах. Вартість розраховується індивідуально — зв’яжіться з нами для оцінки вашого проекту. Отримайте консультацію безкоштовно: ми проаналізуємо поточну реалізацію і запропонуємо оптимальне рішення. Замовте аудит вашого коду для перевірки обробки Family Sharing — це займе годину, а зекономить тижні доопрацювань.







