Ukrainian (українська мова) translation by Andy Yur (you can also view the original English article)



Вступ
Покупки в додатках - відмінна можливість для розробників, які хочуть отримувати більше прибутку і пропонують додатковий контент і функції через свої додатки. Наприклад, для ігор ви можете купити камені або монети, а для фото-додатків розблокувати нові ефекти або інструменти. Все це робиться за допомогою кредитної картки або іншим способом, не виходячи з програми.
У цьому уроці я опишу всі кроки зі створення Consumable і Non-Consumable IAP в iTunes Connect і покажу код, який вам потрібен для покупки обох продуктів. Я зробив sample Xcode project with a label and two buttons, завантажте його і слідуйте по вказівкам, щоб зрозуміти, як він працює.
Створення Sandbox Tester в iTunes Connect
Я припускаю, що ви вже створили додаток iOS в розділі My Apps в iTunes Connect. Тепер зробимо Sandbox Tester для перевірки IAP на вашому реальному пристрої (НЕ Simulator - він не підтримує In-App покупки).
Увійдіть в Users and Roles, далі на вкладку Sandbox Tester, натисніть (+) поруч з Tester.



Заповніть форму, щоб додати новий sandbox tester. Після збереження поверніться до My App та натисніть значок свого застосування, щоб ввести його дані і створити продукти IAP.
Створення продуктів IAP в iTunes Connect
Consumable Products
У вкладці Features натисніть (+) поруч з In-App Purchases. Можна створювати тільки один продукт за раз, тому почнемо з Consumable.



Consumable IAP, як випливає з назви, є продуктом, який можна купити багато разів. Ми будемо використовувати його для збору додаткових «монет» в нашому демонстраційному додатку.
Натисніть Create, щоб ініціалізувати елемент IAP. На наступному екрані ви налаштуєте всю інформацію про свій продукт:
- Reference Name: це ім'я буде використовуватися в звітах iTunes Connect і в Sales and Trends. Воно може бути будь-яким, але не довше 64 символів, в App Store воно відображатиметься.
- Product ID: унікальний алфавітно-цифровий ідентифікатор для розпізнавання вашого продукту. Розробники часто використовують для нього синтаксис web-reverse. У нашому прикладі це com.iaptutorial.coins. Пізніше ми вставимо цей ID в рядок нашого коду.
- Price: виберіть цінової розряд з меню, що випадає. Пам'ятайте: щоб продати ваш продукт через додаток в App Store, ви повинні подати заявку на отримання Paid Application Agreement в Agreements, Tax & Banking.
- Localizations: для цього уроку ми вибрали тільки англійську мову, але ви можете додати, натиснувши кнопку (+). Введіть Display Name і Description. Обидва вони будуть видні в App Store.
- Screenshot: завантажте скріншот для огляду. Він не відобразиться в App Store, і повинен бути допустимого для платформи додатків розміру, тому, якщо ваше додаток Universal, можете завантажити скріншот iPad.
- Review Notes: будь-яка додаткова інформація про ваш IAP, яка може бути корисна для рецензента.



Закінчивши, натисніть Save і отримаєте попередження:
Ваша перша покупка In-App повинна бути представлена в новій версії програми. Виберіть його з розділу In-App Purchases і натисніть Submit.
Non-Consumable Products
Тепер натисніть кнопку In-App Purchases в лівому списку, прямо над кнопкою Game Center і додайте новий продукт IAP. На цей раз виберіть опцію Non-Consumable:



Натисніть Create і повторіть кроки, описані вище. Оскільки цей продукт Non-Consumable і користувачі зможуть купити його тільки раз, Apple вимагає підтвердження можливості оплати. Це на випадок, якщо ви спершу видалите цю програму встановіть його повторно або зайдете з іншого пристрою з тим же Apple ID і вам потрібно буде повернути свої покупки, не заплативши за них двічі. Тому пізніше ми додамо функцію Restore Purchase в нашому коді.
ID продукту, який ми створили - com.iaptutorial.premium з ціновим рівнем USD $ 2.99. Ми назвали його Unlock Premium Version.
Коли ви заповните поля, збережіть свій продукт і поверніться на сторінку In-App Purchases. У вас буде список з двох продуктів, з їх Name, Type, ID і Status, Ready to Submit.



Поверніться на сторінку свого додатка, натиснувши на кнопки App Store і Prepare for Submission. Прокрутіть вниз до розділу In-App Purchases прямо під General App Information, натисніть кнопку (+), щоб додати свої продукти IAP.



Виберіть їх і натисніть Done.



Нарешті, натисніть Save в правому верхньому куті екрану, і ви зможете налаштувати продукти In-App Purchase на iTunes Connect.
Увійдіть в Тестер Sandbox на пристрої iOS
Перш ніж перейти до коду, зробіть ще крок. Натисніть Settings > iTunes & App Store на пристрої iOS. Якщо ви вже увійшли в систему зі своїм Apple ID, натисніть на нього і виберіть Sign Out. Потім увійдіть в систему з обліковими даними для sandbox tester, які ви створили. Після входу в систему може з'явитися попередження:
Просто натисніть Cancel. Ваше пристрій знову попросить sandbox login, намагаючись зробити покупку і дізнається вашу тестову обліковий запис, щоб ви не платили ні копійки по кредитній карті за будь-яку покупку, яку робите.
Вийдіть з Settings, підключіть пристрій до комп'ютера Mac через USB-кабель і, нарешті, почніть кодування!
Код
Якщо ви відкриєте наш демонстраційний проект, то побачите, що весь необхідний код для In-App Purchase написаний:
Якщо ви хочете протестувати додаток, то повинні змінити Bundle Identifier на свій id. В іншому випадку Xcode не дозволить вам запускати додаток на реальному пристрої і додаток не впізнає два ваших IAP-продукту.
Увійдіть в ViewController.swift і перевірте код. Перш за все, ми додали інструкцію import для StoreKit
і делегатів, які нам потрібні для відстеження транзакцій і запитів продукту.
import StoreKit class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
Потім ми оголосили кілька корисних переглядів.
/* Views */ @IBOutlet weak var coinsLabel: UILabel! @IBOutlet weak var premiumLabel: UILabel! @IBOutlet weak var consumableLabel: UILabel! @IBOutlet weak var nonConsumableLabel: UILabel!
CoinsLabel
і premiumLabel
будуть використовуватися для показу результатів покупок обох продуктів. ConsumableLabel
і nonConsumableLabel
покажуть опис і ціну кожного продукту IAP, які ми раніше створили в iTunes Connect.
Тепер додамо деякі змінні:
/* Variables */ let COINS_PRODUCT_ID = "com.iaptutorial.coins" let PREMIUM_PRODUCT_ID = "com.iaptutorial.premium" var productID = "" var productsRequest = SKProductsRequest() var iapProducts = [SKProduct]() var nonConsumablePurchaseMade = UserDefaults.standard.bool(forKey: "nonConsumablePurchaseMade") var coins = UserDefaults.standard.integer(forKey: "coins")
Перші два рядки - це нагадування про ID продуктів. Важливо, щоб ці рядки точно відповідали тим, які були зареєстровані в розділі iTunes Connect In-App Purchase.
-
productID
- це рядок, яку ми будемо використовувати для визначення продукту для покупки. -
productsRequest
- це екземплярSKProductsRequest
, необхідний для пошуку продуктів IAP з вашого застосування в iTC. -
iapProducts
просто набірSKProducts
. Зверніть увагу, що префікс SK означає StoreKit, структуру iOS для обробки покупок.
Останні два рядки завантажують дві змінні типу Boolean
і Integer
, необхідні для відстеження покупок монет і преміальної версії, consumable і non-consumable продуктів.
Наступний код в viewDidLoad()
виконує кілька дій відразу після запуску програми:
// Check your In-App Purchases print("NON CONSUMABLE PURCHASE MADE: \(nonConsumablePurchaseMade)") print("COINS: \(coins)") // Set text coinsLabel.text = "COINS: \(coins)" if nonConsumablePurchaseMade { premiumLabel.text = "Premium version PURCHASED!" } else { premiumLabel.text = "Premium version LOCKED!"} // Fetch IAP Products available fetchAvailableProducts()
Спочатку ми просто реєструємо кожну покупку в консолі Xcode. Потім ми показуємо загальна кількість монет, які ми купили за допомогою coinsLabel
. Оскільки ми запускаємо демонстраційне додаток вперше, воно відображає COINS: 0.
if
ставиться до тексту premiumLabel
в залежності від того, чи був придбаний non-consumable продукт. Для початку він буде показувати Premium version LOCKED! поки ми не зробили преміальну покупку.
Останній рядок коду викликає метод, його ми побачимо пізніше, він витягує продукти, які ми зберігали в iTC.
Тепер давайте подивимося, що роблять дві кнопки покупки, які ми встановили в нашому demo app:
// MARK: - BUY 10 COINS BUTTON @IBAction func buy10coinsButt(_ sender: Any) { purchaseMyProduct(product: iapProducts[0]) } // MARK: - UNLOCK PREMIUM BUTTON @IBAction func unlockPremiumButt(_ sender: Any) { purchaseMyProduct(product: iapProducts[1]) }
Обидва методи викличуть функцію, яка перевірить, чи може пристрій здійснювати покупки, а якщо це можливо, додаток викличе методи StoreKit для їх обробки.
Як згадувалося раніше, нам потрібна третя кнопка для відновлення нашої non-consumable покупки. Ось її код:
// MARK: - RESTORE NON-CONSUMABLE PURCHASE BUTTON @IBAction func restorePurchaseButt(_ sender: Any) { SKPaymentQueue.default().add(self) SKPaymentQueue.default().restoreCompletedTransactions() } func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { nonConsumablePurchaseMade = true UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade") UIAlertView(title: "IAP Tutorial", message: "You've successfully restored your purchase!", delegate: nil, cancelButtonTitle: "OK").show() }
Функція IBAction
підключається до кнопки Restore Purchase в Storyboard і приєднується до системи Apple's In-App Purchase, щоб відновити купівлю, якщо вона вже була зроблена.
paymentQueueRestoreCompletedTransactionsFinished()
- це метод з фреймворка StoreKit, який підтвердить змінну nonConsumablePurchaseMade
після того, як покупка буде успішно відновлено.
Ми закінчили з кнопками, тому давайте подивимося, що робить функція fetchAvailableProducts()
:
// MARK: - FETCH AVAILABLE IAP PRODUCTS func fetchAvailableProducts() { // Put here your IAP Products ID's let productIdentifiers = NSSet(objects: COINS_PRODUCT_ID, PREMIUM_PRODUCT_ID ) productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>) productsRequest.delegate = self productsRequest.start() }
Спочатку ми створюємо екземпляр NSSet
, який в основному являє собою масив рядків. Ми збережемо два ID продукту, які ми раніше оголосили.
Потім ми запускаємо SKProductsRequest
на основі цих ID для відображення інформації про продукти (описі і ціною) IAP, які будуть оброблятися цим методом:
// MARK: - REQUEST IAP PRODUCTS func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) { if (response.products.count > 0) { iapProducts = response.products // 1st IAP Product (Consumable) ------------------------------------ let firstProduct = response.products[0] as SKProduct // Get its price from iTunes Connect let numberFormatter = NumberFormatter() numberFormatter.formatterBehavior = .behavior10_4 numberFormatter.numberStyle = .currency numberFormatter.locale = firstProduct.priceLocale let price1Str = numberFormatter.string(from: firstProduct.price) // Show its description consumableLabel.text = firstProduct.localizedDescription + "\nfor just \(price1Str!)" // ------------------------------------------------ // 2nd IAP Product (Non-Consumable) ------------------------------ let secondProd = response.products[1] as SKProduct // Get its price from iTunes Connect numberFormatter.locale = secondProd.priceLocale let price2Str = numberFormatter.string(from: secondProd.price) // Show its description nonConsumableLabel.text = secondProd.localizedDescription + "\nfor just \(price2Str!)" // ------------------------------------ } }
У наведеній вище функції спочатку перевіримо, чи є продукти, зареєстровані в iTunes Connect і відповідно налаштуємо наш масив iapProducts
. Потім ми можемо ініціювати два SKProducts і роздрукувати їх опис і ціну на етикетках.
Перш ніж перейти до ядра коду In-App Purchase, додамо ще пару функцій:
// MARK: - MAKE PURCHASE OF A PRODUCT func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() } func purchaseMyProduct(product: SKProduct) { if self.canMakePurchases() { let payment = SKPayment(product: product) SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(payment) print("PRODUCT TO PURCHASE: \(product.productIdentifier)") productID = product.productIdentifier // IAP Purchases dsabled on the Device } else { UIAlertView(title: "IAP Tutorial", message: "Purchases are disabled in your device!", delegate: nil, cancelButtonTitle: "OK").show() } }
Перша перевіряє, чи може наш пристрій здійснювати покупки. Другу функцію ми викликаємо з двох кнопок. Запускаючи чергу платежів і змінюючи нашу змінну productID
в обраний productIdentifier
.
Тепер ми нарешті прийшли до останнього методу делегування, він обробляє результати платежів:
// MARK:- IAP PAYMENT QUEUE func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction:AnyObject in transactions { if let trans = transaction as? SKPaymentTransaction { switch trans.transactionState { case .purchased: SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction) // The Consumable product (10 coins) has been purchased -> gain 10 extra coins! if productID == COINS_PRODUCT_ID { // Add 10 coins and save their total amount coins += 10 UserDefaults.standard.set(coins, forKey: "coins") coinsLabel.text = "COINS: \(coins)" UIAlertView(title: "IAP Tutorial", message: "You've successfully bought 10 extra coins!", delegate: nil, cancelButtonTitle: "OK").show() // The Non-Consumable product (Premium) has been purchased! } else if productID == PREMIUM_PRODUCT_ID { // Save your purchase locally (needed only for Non-Consumable IAP) nonConsumablePurchaseMade = true UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade") premiumLabel.text = "Premium version PURCHASED!" UIAlertView(title: "IAP Tutorial", message: "You've successfully unlocked the Premium version!", delegate: nil, cancelButtonTitle: "OK").show() } break case .failed: SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction) break case .restored: SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction) break default: break }}} }
Ця функція має повідомлення switch
і перевіряє кожне стан платежу. Перший case
викликається, якщо покупка була успішно виконана і завершує транзакцію.
Усередині цього блоку ми перевіримо вибір ID продукту і виконаємо необхідні дії для оновлення програми, тому, якщо ми купимо 10 додаткових монет, ми додамо 10 до змінної coins
, збережемо її значення за допомогою UserDefaults
, відобразимо нову кількість монет і заявимо про це.
Зверніть увагу, що ви можете робити цю покупку без обмежень, оскільки це consumable IAP.
Точно так же, якщо ми купили продукт non-consumable, додаток встановлює змінну nonConsumablePurchaseMade
в true
, зберігає її, змінює текст premiumLabel
і запускає попередження про те, що покупка пройшла успішно.
Інші два cases
обробляють результати платежів за відмову і відновлення. Додаток запустить оповіщення, якщо ваша транзакція завершиться невдачею або якщо ви відновили non-consumable покупку.
Ось так! Тепер увійдіть в систему зі своїми обліковими даними Sandbox Tester і запустіть перевірку додатки. Спочатку з'явиться попередження:
Виберіть Use Existing Apple ID і знову введіть дані Sandbox Tester для входу в систему. Це тому, що додаток розпізнає реального користувача з налаштувань iTunes і App Store, а не з Sandbox.
Після входу в систему, ви зможете здійснювати покупки обох продуктів.






Шаблони CodeCanyon
Якщо ви працюєте з iOS і хочете глибше пізнати мову Swift і розробку додатків, дивіться my iOS app templates on CodeCanyon.
Є сотні інших iOS app templates on the Envato Market, готових до роботи і прискоренню вашого застосування. Покопайтеся в них! Можливо, цим ви заощадите години роботи в своєму наступному додатку.
Висновок
У цьому уроці ми розглянули всі кроки зі створення продуктів In-App Purchase в iTunes Connect і написання коду для вашого застосування. Сподіваюся, ви зможете використовувати ці знання в своєму наступному iOS app!
Спасибі за читання, і до зустрічі! Ознайомтеся з іншими нашими курсами та посібниками по розробці iOS app за допомогою Swift.