it-swarm.com.ru

Как добавить покупку из приложения в приложение для iOS?

Как добавить покупку в приложении для iOS? Каковы все детали и есть ли пример кода?

Это должен быть общий вид того, как добавлять покупки из приложений в приложения для iOS

251
Jojodmo

Лучший способ заставить покупку в приложении работать для iOS 10iOS 9, 8 and 7) в Xcode 5+ состоит в следующем:

  1. Перейдите на appstoreconnect.Apple.com и войдите в систему.
  2. Нажмите My Apps, затем выберите приложение, к которому хотите добавить покупку.
  3. Щелкните заголовок Features и выберите слева In-App Purchases
  4. Нажмите на значок + в середине
  5. В этом руководстве мы добавим покупку в приложении для удаления рекламы, поэтому выберите non-consumable. Если вы собираетесь отправить физический элемент пользователю или дать ему что-то, что они могут купить более одного раза, вы должны выбрать consumable.
  6. Для справочного имени, поместите все, что вы хотите (но убедитесь, что вы знаете, что это такое)
  7. Для идентификатора продукта введите tld.websitename.appname.referencename, это будет работать лучше всего, поэтому, например, вы можете использовать com.jojodmo.blix.removeads
  8. Выберите cleared for sale, а затем выберите уровень цен 1 (99 ¢). Уровень 2 будет составлять 1,99 долл. США, а уровень 3 - 2,99 долл. США. Полный список доступен, если вы нажмете view pricing matrix. Я рекомендую использовать уровень 1, потому что обычно это самая большая сумма, которую кто-либо платит за удаление рекламы.
  9. Нажмите синюю кнопку add language и введите информацию. Это ВСЕ будет показано клиенту, поэтому не кладите ничего, что вы не хотите, чтобы он видел
  10. Для hosting content with Apple выберите нет
  11. Вы можете оставить примечания к обзору пустыми НА СЕЙЧАС .
  12. Пропустите screenshot for review FOR NOW , все, что мы пропустим, мы вернемся.
  13. Нажмите "сохранить"

Идентификация вашего продукта в App Store Connect может занять несколько часов, поэтому наберитесь терпения.

Теперь, когда вы настроили информацию о покупках в приложении в App Store Connect, зайдите в свой проект Xcode и перейдите к диспетчеру приложений (синий значок в виде страницы вверху, где находятся ваши методы и заголовочные файлы), нажмите на Ваше приложение под целями (должно быть первым), затем перейдите к общему. Внизу вы должны увидеть linked frameworks and libraries, кликнуть по маленькому символу плюса и добавить каркас StoreKit.framework Если вы этого не сделаете, покупка в приложении НЕ БУДЕТ работать!

Если вы используете Objective-C в качестве языка для вашего приложения, вы можете пропустить эти пять шагов. В противном случае, если вы используете Swift, сделайте следующее:

  1. Создайте новый .h (заголовочный) файл, перейдя в File> New> File... (Command ⌘ + N). Этот файл будет называться "Ваш .h файл" в оставшейся части руководства

  2. При появлении запроса нажмите Создать заголовок моста . Это будет наш файл заголовка моста. Если вам не предлагается , перейдите к шагу 3. Если вам предлагается , пропустите шаг 3 и перейдите непосредственно к шагу 4.

  3. Создайте другой файл .h с именем Bridge.h в основной папке проекта, затем перейдите в диспетчер приложений (синий значок в виде страницы), затем выберите свое приложение в разделе Targets и нажмите Build Settings. Найдите параметр, который говорит Swift Compiler - Генерация кода , а затем установите заголовок моста Objective-C опция для Bridge.h

  4. В своем файле заголовка моста добавьте строку #import "MyObjectiveCHeaderFile.h", где MyObjectiveCHeaderFile - имя файла заголовка, который вы создали на первом шаге. Так, например, если вы назвали свой заголовочный файл InAppPurchase.h , вы бы добавили строку #import "InAppPurchase.h" в ваш заголовочный файл моста.

  5. Создайте новый файл методов Objective C (.m), перейдя в File> New> File... (Command ⌘ + N). Назовите его так же, как заголовочный файл, созданный на шаге 1. Например, если вы вызвали файл на шаге 1 InAppPurchase.h , вы бы назвали этот новый файл InAppPurchase.m. Этот файл будет называться "Ваш .m файл" в оставшейся части руководства.

Теперь мы собираемся перейти к фактическому кодированию. Добавьте следующий код в ваш файл .h:

BOOL areAdsRemoved;

- (IBAction)restore;
- (IBAction)tapsRemoveAds;

Затем вам нужно импортировать структуру StoreKit в ваш файл .m, а также добавить SKProductsRequestDelegate и SKPaymentTransactionObserver после объявления @interface:

#import <StoreKit/StoreKit.h>

//put the name of your view controller in place of MyViewController
@interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver>

@end

@implementation MyViewController //the name of your view controller (same as above)
  //the code below will be added here
@end

и теперь добавьте следующее в ваш .m файл, эта часть усложняется, поэтому я предлагаю вам прочитать комментарии в коде:

//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product

#define kRemoveAdsProductIdentifier @"put your product id (the one that we just made in App Store Connect) in here"

- (IBAction)tapsRemoveAds{
    NSLog(@"User requests to remove ads");

    if([SKPaymentQueue canMakePayments]){
        NSLog(@"User can make payments");

        //If you have more than one in-app purchase, and would like
        //to have the user purchase a different product, simply define 
        //another function and replace kRemoveAdsProductIdentifier with 
        //the identifier for the other product

        SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]];
        productsRequest.delegate = self;
        [productsRequest start];

    }
    else{
        NSLog(@"User cannot make payments due to parental controls");
        //this is called the user cannot make payments, most likely due to parental controls
    }
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    SKProduct *validProduct = nil;
    int count = [response.products count];
    if(count > 0){
        validProduct = [response.products objectAtIndex:0];
        NSLog(@"Products Available!");
        [self purchase:validProduct];
    }
    else if(!validProduct){
        NSLog(@"No products available");
        //this is called if your product id is not valid, this shouldn't be called unless that happens.
    }
}

- (void)purchase:(SKProduct *)product{
    SKPayment *payment = [SKPayment paymentWithProduct:product];

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

- (IBAction) restore{
    //this is called when the user restores purchases, you should hook this up to a button
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"received restored transactions: %i", queue.transactions.count);
    for(SKPaymentTransaction *transaction in queue.transactions){
        if(transaction.transactionState == SKPaymentTransactionStateRestored){
            //called when the user successfully restores a purchase
            NSLog(@"Transaction state -> Restored");

            //if you have more than one in-app purchase product,
            //you restore the correct product for the identifier.
            //For example, you could use
            //if(productID == kRemoveAdsProductIdentifier)
            //to get the product identifier for the
            //restored purchases, you can use
            //
            //NSString *productID = transaction.payment.productIdentifier;
            [self doRemoveAds];
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        }
    }   
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions){
        //if you have multiple in app purchases in your app,
        //you can get the product identifier of this transaction
        //by using transaction.payment.productIdentifier
        //
        //then, check the identifier against the product IDs
        //that you have defined to check which product the user
        //just purchased            

        switch(transaction.transactionState){
            case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
                //called when the user is in the process of purchasing, do not add any of your own code here.
                break;
            case SKPaymentTransactionStatePurchased:
            //this is called when the user has successfully purchased the package (Cha-Ching!)
                [self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"Transaction state -> Purchased");
                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"Transaction state -> Restored");
                //add the same code as you did from SKPaymentTransactionStatePurchased here
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                //called when the transaction does not finish
                if(transaction.error.code == SKErrorPaymentCancelled){
                    NSLog(@"Transaction state -> Cancelled");
                    //the user cancelled the payment ;(
                }
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
        }
    }
}

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

- (void)doRemoveAds{
    ADBannerView *banner;
    [banner setAlpha:0];
    areAdsRemoved = YES;
    removeAdsButton.hidden = YES;
    removeAdsButton.enabled = NO;
    [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
    //use NSUserDefaults so that you can load whether or not they bought it
    //it would be better to use KeyChain access, or something more secure
    //to store the user data, because NSUserDefaults can be changed.
    //You're average downloader won't be able to change it very easily, but
    //it's still best to use something more secure than NSUserDefaults.
    //For the purpose of this tutorial, though, we're going to use NSUserDefaults
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Если у вас нет рекламы в вашем приложении, вы можете использовать любую другую вещь, которую вы хотите. Например, мы могли бы сделать цвет фона синим. Для этого мы бы хотели использовать:

- (void)doRemoveAds{
    [self.view setBackgroundColor:[UIColor blueColor]];
    areAdsRemoved = YES
    //set the bool for whether or not they purchased it to YES, you could use your own boolean here, but you would have to declare it in your .h file

    [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
    //use NSUserDefaults so that you can load wether or not they bought it
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Теперь где-нибудь в вашем методе viewDidLoad вы захотите добавить следующий код:

areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];
//this will load wether or not they bought the in-app purchase

if(areAdsRemoved){
    [self.view setBackgroundColor:[UIColor blueColor]];
    //if they did buy it, set the background to blue, if your using the code above to set the background to blue, if your removing ads, your going to have to make your own code here
}

Теперь, когда вы добавили весь код, перейдите в файл .xib или storyboard и добавьте две кнопки, одна из которых говорит о покупке, а другая - о восстановлении. Подключите tapsRemoveAdsIBAction к кнопке покупки, которую вы только что сделали, и restoreIBAction к кнопке восстановления. Действие restore проверит, приобрел ли пользователь ранее покупку в приложении, и предоставит ему бесплатную покупку в приложении, если у него его еще нет.

Затем перейдите в App Store Connect и нажмите Users and Access, затем щелкните заголовок Sandbox Testers, а затем щелкните символ + слева, где указано Testers. Вы можете просто ввести случайные вещи для имени и фамилии, и электронная почта не обязательно должна быть реальной - вы просто должны ее запомнить. Введите пароль (который вам придется запомнить) и заполните остальную информацию. Я бы порекомендовал вам сделать Date of Birth датой, которая сделает пользователя старше 18 лет. App Store TerritoryИМЕЕТ, чтобы быть в правильной стране. Затем выйдите из существующей учетной записи iTunes (вы можете войти в систему после этого урока).

Теперь запустите ваше приложение на вашем устройстве iOS, если вы попытаетесь запустить его на симуляторе, при покупке будет всегда ошибка, вы ДОЛЖНЫ запустите его на вашем устройстве iOS. Когда приложение запустится, нажмите кнопку покупки. Когда вам будет предложено войти в свою учетную запись iTunes, войдите в систему как созданный нами тестовый пользователь. Затем, когда он попросит вас подтвердить покупку на 99 ¢ или что-то еще, что вы установили ценовой уровень, возьмите экранный снимок это то, что ваш собираюсь использовать для вашего screenshot for review в App Store Connect. Теперь отмените оплату.

Теперь перейдите к App Store Connect , затем перейдите к My Apps> the app you have the In-app purchase on> In-App Purchases. Затем нажмите на покупку в приложении и нажмите "Изменить" под информацией о покупке в приложении. Как только вы это сделаете, импортируйте фотографию, которую вы только что сделали на свой iPhone, в свой компьютер и загрузите ее в качестве скриншота для просмотра, а затем, в примечаниях к обзору, поместите TEST USER электронная почта и пароль. Это поможет Apple в процессе проверки.

После того, как вы это сделаете, вернитесь в приложение на вашем устройстве iOS, все еще войдя в систему в качестве тестовой учетной записи пользователя, и нажмите кнопку покупки. На этот раз подтвердите платеж . Не волнуйтесь, это НЕ будет взимать с вашего счета ЛЮБЫЕ деньги, тестовые учетные записи пользователей получают все покупки в приложении бесплатно . После Вы подтвердили платеж, убедитесь, что то, что происходит, когда пользователь покупает ваш продукт, действительно происходит. Если это не так, то это будет ошибкой с вашим методом doRemoveAds. Опять же, я рекомендую использовать изменение фона на синий для тестирования покупки в приложении, хотя это не должно быть вашей реальной покупкой в ​​приложении. Если все работает и у тебя все хорошо! Просто добавьте покупку в приложении в новый бинарный файл, когда загрузите его в App Store Connect!


Вот некоторые распространенные ошибки:

Записано: No Products Available

Это может означать три вещи:

  • Вы не указали правильный код покупки в приложении в своем коде (для идентификатора kRemoveAdsProductIdentifier в приведенном выше коде
  • Вы не подтвердили свою покупку в приложении для продажи в App Store Connect
  • Вы не ожидали регистрации идентификатора покупки в приложении в App Store Connect . Подождите пару часов после создания идентификатора, и ваша проблема должна быть решена.
  • Вы не завершили заполнение своих соглашений, налоговой и банковской информации.

Если это не сработает в первый раз, не расстраивайтесь! Не сдавайся! У меня ушло около 5 часов, прежде чем я смог заставить это работать, и около 10 часов на поиск правильного кода! Если вы используете приведенный выше код точно, он должен работать нормально. Не стесняйтесь комментировать, если у вас есть какие-либо вопросы вообще .

Я надеюсь, что это поможет всем тем, кто хочет добавить покупку в приложение для своего iOS-приложения. Ура!

540
Jojodmo

Просто переведите код Jojodmo в Swift:

class InAppPurchaseManager: NSObject , SKProductsRequestDelegate, SKPaymentTransactionObserver{





//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product

let kRemoveAdsProductIdentifier = "put your product id (the one that we just made in iTunesConnect) in here"

@IBAction func tapsRemoveAds() {

    NSLog("User requests to remove ads")

    if SKPaymentQueue.canMakePayments() {
        NSLog("User can make payments")

        //If you have more than one in-app purchase, and would like
        //to have the user purchase a different product, simply define
        //another function and replace kRemoveAdsProductIdentifier with
        //the identifier for the other product
        let set : Set<String> = [kRemoveAdsProductIdentifier]
        let productsRequest = SKProductsRequest(productIdentifiers: set)
        productsRequest.delegate = self
        productsRequest.start()

    }
    else {
        NSLog("User cannot make payments due to parental controls")
        //this is called the user cannot make payments, most likely due to parental controls
    }
}


func purchase(product : SKProduct) {

    let payment = SKPayment(product: product)
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().addPayment(payment)
}

func restore() {
    //this is called when the user restores purchases, you should hook this up to a button
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}


func doRemoveAds() {
    //TODO: implement
}

/////////////////////////////////////////////////
//////////////// store delegate /////////////////
/////////////////////////////////////////////////
// MARK: - store delegate -


func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {

    if let validProduct = response.products.first {
        NSLog("Products Available!")
        self.purchase(validProduct)
    }
    else {
        NSLog("No products available")
        //this is called if your product id is not valid, this shouldn't be called unless that happens.
    }
}

func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {


    NSLog("received restored transactions: \(queue.transactions.count)")
    for transaction in queue.transactions {
        if transaction.transactionState == .Restored {
            //called when the user successfully restores a purchase
            NSLog("Transaction state -> Restored")

            //if you have more than one in-app purchase product,
            //you restore the correct product for the identifier.
            //For example, you could use
            //if(productID == kRemoveAdsProductIdentifier)
            //to get the product identifier for the
            //restored purchases, you can use
            //
            //NSString *productID = transaction.payment.productIdentifier;
            self.doRemoveAds()
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            break;
        }
    }
}


func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

    for transaction in transactions {
        switch transaction.transactionState {
        case .Purchasing: NSLog("Transaction state -> Purchasing")
            //called when the user is in the process of purchasing, do not add any of your own code here.
        case .Purchased:
            //this is called when the user has successfully purchased the package (Cha-Ching!)
            self.doRemoveAds() //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            NSLog("Transaction state -> Purchased")
        case .Restored:
            NSLog("Transaction state -> Restored")
            //add the same code as you did from SKPaymentTransactionStatePurchased here
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
        case .Failed:
            //called when the transaction does not finish
            if transaction.error?.code == SKErrorPaymentCancelled {
                NSLog("Transaction state -> Cancelled")
                //the user cancelled the payment ;(
            }
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
        case .Deferred:
            // The transaction is in the queue, but its final status is pending external action.
            NSLog("Transaction state -> Deferred")

        }


    }
}
} 
12
Yedidya Reiss

RMStore - это легкая библиотека iOS для покупок в приложении. Он оборачивает API StoreKit и предоставляет вам удобные блоки для асинхронных запросов. Приобрести продукт так же просто, как вызвать один метод.

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

4
Vladimir Grigorov

Я знаю, что опоздал, чтобы опубликовать это, но я делюсь подобным опытом, когда я изучил веревки модели IAP.

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

Подвести итоги:

1 - Запросите продукты - используйте классы SKProductRequest и SKProductRequestDelegate, чтобы отправить запрос на идентификаторы продуктов и получить их обратно из собственного магазина itunesconnect.

Эти SKProducts должны использоваться для заполнения пользовательского интерфейса вашего магазина, который пользователь может использовать для покупки определенного товара.

2 - Оформить запрос на оплату - используйте SKPayment & SKPaymentQueue, чтобы добавить платеж в очередь транзакций.

3 - Отслеживание очереди транзакций для обновления статуса - используйте метод updatedTransactions протокола SKPaymentTransactionObserver для мониторинга статуса:

SKPaymentTransactionStatePurchasing - don't do anything
SKPaymentTransactionStatePurchased - unlock product, finish the transaction
SKPaymentTransactionStateFailed - show error, finish the transaction
SKPaymentTransactionStateRestored - unlock product, finish the transaction

4 - Поток кнопки Восстановить - используйте SKPaymentQueue's restoreCompletedTransactions для выполнения этого - шаг 3 позаботится об остальном, наряду со следующими методами SKPaymentTransactionObserver:

paymentQueueRestoreCompletedTransactionsFinished
restoreCompletedTransactionsFailedWithError

Здесь это пошаговое руководство (написанное мной в результате моих собственных попыток понять его), которое объясняет это. В конце он также предоставляет пример кода, который вы можете использовать напрямую.

Здесь это еще один, который я создал, чтобы объяснить некоторые вещи, которые только текст мог бы описать лучше.

0
Nirav Bhatt