Статьи

Встроенные покупки в iOS с помощью Swift 3

Конечный продукт
Что вы будете создавать

Покупка в приложении — отличная функция для всех разработчиков, которые хотят получать больше прибыли и предлагать дополнительный контент и функции через свои приложения. Например, для игр вы можете купить драгоценные камни или монеты, а для приложений для фотографий вы можете разблокировать новые эффекты или инструменты. И вы можете сделать все это, используя кредитную карту или другой способ оплаты, не выходя из приложения.

В этом учебном пособии я расскажу обо всех необходимых шагах по созданию продукта IAP для расходных и не расходуемых материалов в iTunes Connect и покажу код, необходимый для покупки обоих предметов. Я сделал пример проекта Xcode с меткой и двумя кнопками , поэтому скачайте его и следуйте инструкциям этого урока, чтобы понять, как он работает.

Я предполагаю, что вы уже создали приложение для iOS в разделе « Мои приложения » в iTunes Connect. Первое, что вы должны сделать, это создать тестер песочницы для тестирования IAP на вашем реальном устройстве (без симулятора — он не поддерживает покупки в приложении).

Введите Users and Roles , перейдите на вкладку Sandbox Tester и нажмите знак ( + ) рядом с Tester .

Пользователи и роли в iTunes Connect

Заполните форму, чтобы добавить новый тестер песочницы. После того, как вы сохранили свою информацию, вернитесь в раздел « Мое приложение » и нажмите на значок вашего приложения, чтобы ввести его данные и создать продукты IAP.

Перейдите на вкладку « Функции », а затем знак ( + ) рядом с покупками в приложении . Вы можете создавать по одному продукту за раз, поэтому давайте начнем с расходуемого .

Выберите Расходные материалы в приложении

Расходные материалы IAP, как следует из их названия, — это продукт, который можно купить несколько раз. Мы будем использовать его для сбора дополнительных «монет» в нашем демонстрационном приложении.

Нажмите кнопку « Создать», чтобы инициализировать элемент IAP. На следующем экране вы можете настроить всю информацию о вашем продукте:

  • Ссылочное имя : это имя будет использоваться в iTunes Connect и в отчетах о продажах и тенденциях . Он не будет отображаться в App Store, и вы можете ввести любое имя, которое хотите, но оно не может быть длиннее 64 символов.
  • Идентификатор продукта : уникальный буквенно-цифровой идентификатор, который приложение получает для распознавания вашего продукта. Обычно разработчики используют обратный веб-синтаксис для идентификаторов продуктов. В этом примере мы выбрали com.iaptutorial.coins . Позже мы вставим этот идентификатор в виде строки в наш код.
  • Цена : выберите ценовой уровень в раскрывающемся меню. Помните, что для того, чтобы продать свой продукт для покупки в App Store в App Store, вы должны подать заявку на платное соглашение в разделе Соглашения, налоги и банковское дело .
  • Локализации : для этого урока мы выбрали только английский, но вы можете добавить больше языков, нажав на кнопку ( + ). Затем введите отображаемое имя и описание . Оба они будут видны в App Store.
  • Снимок экрана : Загрузить скриншот для просмотра. Он не будет отображаться в App Store и должен иметь допустимый размер для платформы вашего приложения, поэтому, если ваше приложение Universal, вы можете загрузить скриншот iPad.
  • Примечания к обзору : любая дополнительная информация о вашем IAP, которая может быть полезна для рецензента.
Создать новый продукт IAP

Когда вы закончите, нажмите Сохранить, и вы получите это предупреждение:

Ваша первая покупка в приложении должна быть представлена ​​с новой версией приложения. Выберите его в разделе покупок в приложении и нажмите «Отправить».

Теперь нажмите кнопку «Покупки в приложении» в списке слева, справа над кнопкой Game Center , и добавьте новый продукт IAP. На этот раз выберите опцию Non-Consumable :

Создать непотребляемый продукт

Нажмите « Создать» и повторите шаги, упомянутые выше. Поскольку это будет непотребляемый продукт, пользователи смогут приобрести его только один раз, а Apple требуется возможность восстановить такие покупки. Это происходит в случае, если вы удаляете приложение и переустанавливаете его снова или загружаете с другого устройства с тем же Apple ID, и вам необходимо вернуть свои покупки, не заплатив за них дважды. Поэтому позже мы добавим функцию восстановления покупки в наш код.

Идентификатор продукта, который мы создали сейчас, — com.iaptutorial.premium , уровень цен — 2,99 долларов США. Мы назвали это Unlock Premium Version.

Когда вы закончите заполнять все поля, сохраните ваш продукт и вернитесь на страницу покупок в приложении. Теперь у вас должен быть список двух ваших продуктов с именами , типом , идентификатором и статусом, установленными как готовые к отправке .

Список покупок в приложении

Вернитесь на страницу своего приложения, нажав в App Store и кнопки « Подготовиться к отправке» . Прокрутите вниз до раздела « Покупки внутри приложения », прямо под « Общей информацией приложения», и нажмите кнопку (+) , чтобы добавить свои продукты IAP.

Добавить покупки в приложении на страницу информации о ваших приложениях

Выберите все из них и нажмите Готово .

Выберите ваши продукты IAP

Наконец, нажмите « Сохранить» в правом верхнем углу экрана, и вы закончите настройку продуктов для покупок в приложении в iTunes Connect.

Прежде чем перейти к коду, осталось сделать еще одну вещь. Выберите « Настройки» > « iTunes & App Store» на устройстве iOS. Если вы уже вошли в систему со своим оригинальным Apple ID, нажмите на него и выберите « Выйти» . Затем просто войдите с учетными данными для тестера песочницы, который вы создали. После входа вы можете получить следующее предупреждение:

Оповещение от устройства

Просто проигнорируйте его сообщение и нажмите Отмена . Ваше устройство снова запросит ваши учетные данные для входа в песочницу при попытке совершить покупку и распознает вашу тестовую учетную запись, чтобы с вашей кредитной карты не было снято ни копейки за любую покупку, которую вы совершаете.

Выйдите из настроек , подключите ваше устройство к компьютеру Mac через USB-кабель и, наконец, начнем кодировать!

Если вы скачали наш демонстрационный проект, вы увидите, что весь необходимый код для покупки в приложении был написан, поэтому, запустив его, вы получите что-то вроде этого:

Демо IAP приложение

Если вы хотите протестировать приложение, вы должны изменить идентификатор пакета на свой собственный идентификатор. В противном случае Xcode не позволит вам запустить приложение на реальном устройстве, и приложение не распознает два созданных вами продукта IAP.

Идентификатор Chage Bundle во вкладке General в XCode

Введите ViewController.swift и проверьте код. Прежде всего, мы добавили оператор импорта для StoreKit и делегатов, которые нам нужны, чтобы отслеживать платежные транзакции и запросы продуктов.

1
2
3
4
5
6
import StoreKit
 
class ViewController: UIViewController,
SKProductsRequestDelegate,
SKPaymentTransactionObserver
{

Тогда мы объявили несколько просмотров, которые будут полезны.

1
2
3
4
5
6
/* Views */
   @IBOutlet weak var coinsLabel: UILabel!
   @IBOutlet weak var premiumLabel: UILabel!
   @IBOutlet weak var consumableLabel: UILabel!
   @IBOutlet weak var nonConsumableLabel: UILabel!
   

coinsLabel и premiumLabel будут использоваться для отображения результатов покупок для обоих продуктов. nonConsumableLabel и nonConsumableLabel покажут описание и цену каждого продукта IAP, который мы ранее создали в iTunes Connect.

Теперь пришло время добавить некоторые переменные:

01
02
03
04
05
06
07
08
09
10
/* 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»)
   

Первые две строки должны вспомнить наши идентификаторы продуктов. Важно, чтобы эти строки в точности совпадали со строками, зарегистрированными в разделе «Покупки через iTunes».

  • productID — это строка, которую мы будем использовать позже, чтобы определить, какой продукт мы выберем для покупки.
  • productsRequest — это экземпляр SKProductsRequest , необходимый для поиска продуктов IAP из вашего приложения на iTC.
  • iapProducts — это простой набор SKProducts . Обратите внимание, что префикс SK означает StoreKit, iOS-фреймворк, который мы будем использовать для обработки покупок.

Последние две строки загружают две переменные типа Boolean и Integer необходимые для отслеживания покупок монет и премиум-версии, соответственно, расходных и не расходуемых товаров.

Следующий код в viewDidLoad() выполняет несколько вещей, как только приложение запускается:

01
02
03
04
05
06
07
08
09
10
11
12
// 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 зависимости от того, был ли приобретен непотребляемый продукт. Для начала, он покажет Премиум версию LOCKED! так как мы еще не сделали премиальную покупку.

Последняя строка кода вызывает метод, который мы увидим позже, который просто выбирает продукты, которые мы ранее сохранили в iTC.

Теперь давайте посмотрим, что делают две кнопки покупки, которые мы установили в нашем демонстрационном приложении:

01
02
03
04
05
06
07
08
09
10
// 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 для обработки покупки.

Как упоминалось ранее, нам нужна третья кнопка, чтобы восстановить нашу непотребляемую покупку. Вот его код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// 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 присоединена к кнопке « Восстановить покупку» в раскадровке и начинает подключаться к системе покупок в приложении Apple, чтобы восстановить покупку, если она уже была сделана.

paymentQueueRestoreCompletedTransactionsFinished() — это метод делегата из среды StoreKit, который сохранит нашу переменную nonConsumablePurchaseMade в true после успешного восстановления покупки.

Мы закончили с кнопками, поэтому давайте посмотрим, что fetchAvailableProducts() функция fetchAvailableProducts() :

01
02
03
04
05
06
07
08
09
10
11
12
13
// 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 , который в основном представляет собой массив строк. Мы будем хранить два идентификатора продукта, которые мы ранее объявили там.

Затем мы запускаем запрос SKProductsRequest на основе этих идентификаторов, чтобы приложение отображало информацию о продуктах IAP (описание и цена), которая будет обрабатываться этим методом делегата:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 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 и распечатать их описание и цену на этикетках.

Прежде чем перейти к основному коду покупки в приложении, нам нужно еще несколько функций:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
// 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 .

Теперь мы наконец пришли к последнему методу делегата, который обрабатывает результаты оплаты:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// MARK:- IAP PAYMENT QUEUE
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction:AnyObject in transactions {
            if let trans = transaction as?
                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 вызывается, если покупка была успешно сделана, и завершает свою транзакцию.

Внутри этого блока мы должны проверить, какой идентификатор продукта мы выбрали, и выполнить необходимые действия для обновления нашего приложения — поэтому, если пользователь купил 10 дополнительных монет, мы добавим 10 к нашей переменной coins , сохраняя ее значение с помощью UserDefaults , показать новое количество монет, которые мы получили, и подать предупреждение об этом.

Обратите внимание, что вы можете сделать эту покупку несколько раз без ограничений, так как это расходный IAP, и нет необходимости в функции восстановления покупки.

Точно так же, если мы купили премиум-продукт не для потребления, приложение устанавливает nonConsumablePurchaseMade переменной nonConsumablePurchaseMade значение true , сохраняет ее, изменяет текст premiumLabel и premiumLabel предупреждение, чтобы уведомить вас об успешной покупке.

В двух других cases обрабатываются результаты оплаты за сбой и восстановление. Приложение будет запускать пользовательские оповещения самостоятельно, если по какой-либо причине произойдет сбой вашей транзакции или вы восстановите не расходуемую покупку.

Это оно! Теперь просто убедитесь, что вы вошли в систему с учетными данными Sandbox Tester и запустите приложение, чтобы протестировать его. В первый раз вы получите следующее предупреждение:

App Store Войти оповещение

Выберите « Использовать существующий Apple ID» и введите имя пользователя и пароль Sandbox Tester еще раз для входа в систему. Это происходит потому, что приложение может распознать только реального пользователя из настроек iTunes & App Store , а не «песочницу».

После входа в систему вы сможете совершать покупки обоих продуктов.

Сделана покупка 10 монет

Сделана покупка нерасходимых премиум-товаров

Если вы работаете с iOS и хотите углубиться в разработку языка и приложений Swift, проверьте некоторые из моих шаблонов приложений для iOS на CodeCanyon .

На Envato Market также есть сотни других шаблонов приложений для iOS , готовых к подгонке и ускоряющих рабочий процесс. Иди проверь их! Вы можете просто сэкономить часы работы над своим следующим приложением.

В этом руководстве мы рассмотрели все шаги, необходимые для создания продуктов для покупок в приложении в iTunes Connect, и рассказали, как написать код, чтобы включить их в вашем приложении. Я надеюсь, что вы сможете использовать эти знания в своем следующем приложении для iOS!

Спасибо за чтение, и увидимся в следующий раз! Пожалуйста, ознакомьтесь с другими нашими курсами и руководствами по разработке приложений для iOS с помощью Swift.

  • IOS
    iOS с нуля с помощью Swift: изучение iOS SDK
    Барт Джейкобс
  • IOS
    Как добавить рекламные баннеры AdMob в приложение iOS Swift
  • стриж
    Протоколно-ориентированное программирование в Swift 2
    Дэвис Элли