Добавляем встроенные покупки в приложение
Здраствуйте дорогие читатели. В этой статье я расскажу вам, как я добавлял встроенные покупки в свое приложение на iOS, разработанное с использованием фреймворка SwiftUI.
Я не профессиональный разработчик приложений, никогда этому не учился. Разработка - это скорее мое хобби. Решения, использованные мной в коде, возможно, кому то покажутся далекими от идеала. Но только таким образом я смог реализовать задуманное.
Нижеприведенный пример код использует встроенные покупки типа Consumable, но прочитав, как это сделал я, вы сможете реализовать любые другие типы покупок. Примеры кода работают в реальном приложении. В конце статьи приведены ссылки на демонстрационный проект и на реальное приложение, доступное в AppStore.
Здесь я не буду рассказывать как создавать покупки в AppStore Connect. Будем использовать готовые, которые я создал ранее. Выглядят они так:
Итак - поехали!
Первым делом создаем проект:
- в Xcode 11 выбираем: Создать новый проект-> Single View App и в свойствах проекта выбираем фреймворк SwiftUI;
- в XCode 12 выбираем: Создать новый проект -> App и в свойствах проекта выбираем: Interface: SwiftUI; Life Cycle: UIKit App Delegate.
Создается проект, в котором у нас должно быть несколько файлов, с двумя из которых мы будем работать:
- AppDelegate.swift;
- ContentView.swift;
и создадим несколько новых.
Поскольку в реальных приложениях крайне редко бывают (по крайней мере я никогда не видел) встроенных покупок на главном экране, мы подготовим заготовку пользовательского интерфейса. Выглядеть он будет следующим образом:
- в файле ContentView создаем TabView с двумя экранами, один их которых мы оставим под главный экран приложения, а второй отдадим под краткое описание нашего приложения, где и будет расположена кнопка перехода на экран с покупками (в нашем случае "Donation").
- на экране "Donation" мы расположим наши встроенные покупки с их названиями и ценами.
Что бы TabView у нас нормально работал, создадим два View:
- MainView, в котором оставим простое текстовое View;
- AboutView, в котором пока напишем только текст.
MainView:
AboutView:
А вот и наш ContentView с двумя экранами в TabView():
Далее нам надо включить встроенные покупки с свойствах проекта. Делается это следующим образом:
1. Переходим в свойства проекта: BeerCrafterDemo -> TARGETS BeerCrafterDemo -> Signing & Capabilities и нажимаем кнопку + Capability:
2. Во всплывшем окне ищем и выбираем In-App Purchase.
3. В итоге в нашем списке Signing & Capabilities должны появиться встроенные покупки:
Теперь приступаем к созданию менеджера покупок.
Первым делом наше приложение должно каким-нибудь образом знать список идентификаторов покупок. Здесь пространства для манёвра мало. Можно список продуктов получать с удаленного сервера или вшить в приложение. Я воспользуюсь вторым вариантом.
Создадим новый Swift-файл и назовем его IAPManager.swift. Сразу после импортированного фреймворка Foundation импортируем StoreKit и создадим enum типа String, назвав его IAPProducts. Здесь мы запишем все наши идентификаторы продуктов, точно так же, как они записаны в AppStore Connect:
Далее мы создаем класс IAPManager и несколько функций:
- функцию, добавляющую наблюдателя за транзакциями после проверки возможности совершать платежи,
- и функцию, удаляющую наблюдателя за транзакциями.
Следующим шагом нам надо сделать так, что бы наша функция setupPurchases исполнялась при запуске приложения, а функция removePurchases исполнялась при завершении приложения. Делается это следующим образом:
- переходим в файл AppDelegate.swift;
- в функции application запускаем нашего наблюдателя;
- добавляем функцию applicationWillTerminate для удаления нашего наблюдателя при завершении приложения.
Следующим шагом мы должны получить список продуктов. В классе IAPManager создадим функцию getProduct, которой передадим наши идентификаторы и отправим запрос на их получение, при этом не забыв подписаться под протокол SKProductRequestDelegate и создать переменную для хранения списка продуктов:
На этом этапе вы можете собрать проект и проверить его на реальном устройстве. В панели отладчика должны появится сообщения о возможности совершения покупок и список продуктов.
Далее мы должны получить локализованные цены на наши продукты. Для этого мы напишем короткое расширение для SKProduct:
Следующим шагом мы доработаем наш наблюдатель за транзакциями, что бы мы могли отслеживать их состояния. Для этого мы должны в расширение IAPManager: SKPaymentTransactionObserver дописать несколько функций отслеживания состояния транзакций:
На финальном этапе создания нашего менеджера мы научим его совершать сделки и восстанавливать покупки. Последней функцией мы пользоваться в нашем приложении не будем. Она понадобиться, если вы примените покупки других типов, например авто-возобновляемые подписки. В основной класс IAPManager запишем несколько строк:
На этом этапе я столкнулся с проблемой, решить которую удалось только способом, о котором напишу далее. Мой IAPManager никак не хотел подружится и передать список покупок и цены во View, созданную при помощи фреймворка SwiftUI.
В основном классе IAPManager я создал два пустых массива типа String:
и переписал функцию productRequest:
Теперь создадим экран покупок и сделаем переход в него из экрана AboutView:
Первым делом нам нужно уведомить пользователя, если по какой то причине список покупок оказался недоступен. Для этого создадим переменную productCount, присвоим ей значение количества продуктов:
var productCount = IAPManager.shared.products.count;
и создадим условие, если их количество равно нулю, вывести сообщение о недоступности продуктов:
Последним этапом допишем две кнопки, которые будут содержать информацию о названии продукта и его цене. Кнопка будет показана только если продукт доступен:
Обратите внимание, что для получения названий продуктов и цен из IAPManager мы ввели две переменные:
var productsLocalizedTitle = IAPManager.shared.purchases
var productsLocalizedPrice = IAPManager.shared.purchasesPrise
Вот собственно и всё. Теперь можно собрать проект и проверить наши покупки на реальном устройстве при помощи тестировщика.
Экран покупок:
Нажимаем кнопку покупки:
Совершаем покупку:
У этого способа реализации есть два недостатка, которые я увидел:
1. Если пользователь очень быстро перейдет в экран покупок, то приложение может не успеть загрузить часть или все продукты, тогда будет показано сообщение о отсутствии продуктов;
2. Список покупок загружается только при старте приложения, и не обновляется в случае изменения.
Мой способ, который я вам рассказал, выполнен достаточно грубо, и у опытных разработчиков может вызвать смех или слёзы. Ну а начинающим вполне может показать путь, который они смогут в дальнейшем усовершенствовать.
Благодарю за прочтение. Ставьте лайки и оставляйте комментарии.
Ссылка на проект в GitHub.
Ссылка на реальное приложение в AppStore: BeerCrafter.