Необходимо реализовать подписку внутри iOS продукта за доступ к фитче. Поскольку auto-renewable подписку использовать скорее всего не получится (строгое ограничение на тип контента подписки), то решено использовать второй тип non-renewing. Но вот проблема - как и где сохранять информацию о сроке подписки, а также как синхронизовать между устройствами активные подписки?
Локально сохранять срок и сравнивать его с системным - это обходится банальной перестановкой системного времени и не вариант.
Apple не предоставляют механизм для восстановления подписок non-renewing, а также для проверки статуса(истечения даты) подписки.
Обязательно ли нужно делать форму регистрации/авторизации пользователя или можно как-то обойтись записью в iCloud? Можно ли использовать e-mail в случае авторизации и регистрации? Какую информацию лучше хранить в iCloud и передавать на свой сервер?
В общем, интересует как это всё можно сделать и не получить reject от apple при рассмотрении приложения. Сильно возиться с аккаунтами не хотелось бы, но с сервера можно сдеать простенький API, только вот что именно... На stackoverflow много обращений по схожим вопросам, но я пока так и не нашёл единого мнения на этот счёт, иногда apple допускает какие-то решения, у других эти же решения заворачивает, в общем полная неразбериха.
Буду очень благодарен, если кто-то поделится практической информацией как это всё можно реализовать, схема, может на примере своих приложений.
P.S.: На статьи по работе с in app на Хабре натыкался, но деталей и логику как работает сервер + клиент с такими подписками не нашёл.
Не завернет. Но лучше делать с серверной частью, во первых саму покупку можно защитить от ломалок, во вторых срок подписки контролировать. При подписке генерируйте UUID, отправляйте его на сервер вместе с покупкой и сохраняйте его в iCloud KVS, потом по этому UUID будете проверять подписку через сервер.
Делал такие подписки:
1 свой сервер
2 сохранение производится отсылкой рецепта покупки + mac устройства
3 восстановление по запросу к АПИ с отправкой мака
4 регистрация не обязательна(требование Apple), но нужно предупреждать юзера что нужно регаться если захочет восстановить на другом устройстве
@Rockerman на данный момент нет такого ID в SDK, к которому можно привязаться намертво. identifierForVendor изменится после переустановки приложения, и будет разным на разных девайсах. Поэтому он не подойдет. Выход только генерация UUID или другой рандомной последовательности с низкой вероятностью коллизии и запись его в iCloud либо Keychain если шаринг не нужен
@s0L@Rockerman у меня несколько приложений используют этот принцип, недавно их обновлял, все прошли проверку. Так что с mac'ом все ок. Либо можно делать md5 хеш из ip+имя девайса - использовать как уникальный идентификатор, и закинуть его в keychain. Mac самое надежное, если человек полностью ресет сделает, то все равно сможет восстановить подписку.
Восстановление возможно только если пользователь зарегистрируется или достаточно mac адрес отправить?
Если пользователь сначала купил подписку, а потом захочет привязать покупку к аккаунту, то у него соответственно нет уже шансов?
Я читал, iCloud может быть выключен. Надо тогда предупреждение как мимимум сделать, чтобы включить iCloud для шаринга подписок. Получается нужно хранить последний UUID (или md5 от receipt) покупки в iCloud, а при запросе с сервера статуса подписки проверять по этому UUID (есть ли он в базе). При этом, нужно локально сохрянять reciept до тех пор, пока не выполнится запрос проверки покупки на сервере. Мало ли, может интернет пропасть, программа зависнуть и потеряется транзакция покупки. Я правильно всё понимаю? Много тонкостей может всплыть
UUID нет смысла хранить несколько, можно использовать его как ID пользователя в одном экземпляре. Сохранять локально receipt тоже нет смысла, если не выполнился запрос на сервер для проверки, то просто не нужно делать finishTransaction, иначе получается вы спишите деньги, а плюшки не отдадите. Потом транзакция снова придет автоматически и ее можно будет обычным образом обработать повторно. По поводу выключенного iCloud, да можно и предупредить, что не будет доступно на других девайсах, но с точки зрения кода само хранилище KVS работает независимо от того включен он или нет, его можно использовать всегда.
И да, будте готовы к тому, что у вас может быть несколько подписок у одного пользователя. Например есть подписка на двух девайсах, а потом включился iCloud и они зашарились. Такие ситуации нужно обрабатывать согласно нужной логике
Ещё такой момент. Получается, что запрашивать статус подписки со своего сервера придётся каждый раз при использовании функции приложения, на которую подписался пользователь? И без интернет соединения разрешать это не получится. Не сверять ведь полученную ранее дату подписки с локальным временем в системе. Это ведь обходиться банальной перестановкой времени?
@Rockerman можно проверять при запуске приложения, а потом сверять со временем в процессе работы и реагировать на смену системного времени. Если нет сети, проверять как только она появится. Также можно записывать куда-нибудь в userDefaults последнее системное время на момент запроса с сервера, чтобы реагировать не перевелось ли оно назад при следующем запуске без сети.
Возникла трудность при проверке receipt для mac os x.
Беру я его так:
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
if([[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]]){
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
}, но преобразовать к словарю, подобно как для iOS нем могу.
Такое ощущение, что у него совсем другой формат.
Кто-нибудь делал проверку покупки для mac?