Недавно решил добавить встроенные покупки в одно из моих приложений для изучения английского языка. Не нашел ни одного вменяемого урока по добавлению встроенных покупок на Objective C. Все уроки либо очень старые, либо на Swift. Здесь хочу предложить вашему вниманию довольно простое решение, которое я использовал в своем приложении, сделанном на Objective C в Xcode 8.

Необходимо сделать следующее:

1. Перейдите на сайт itunes.connect.apple.com и войдите в систему.
2. Нажмите «Мои приложения», затем нажмите приложение, которое вы хотите добавить
3. Щелкните заголовок «Функции», а затем справа от надписи «Встроенные покупки» нажмите значок +
4. Для этого примера мы делаем покупку для удаления рекламы «Нерасходуемая покупка». Если вы собираетесь отправить физический элемент пользователям или дать им что-то, что они могут купить более одного раза, то используйте «Расходуемая покупка»
5. Оригинальное название может быть любым, но понятным для вас.
6. В качестве идентификатора продукта рекомендуется использовать Bundle ID и через точку название, например, вы можете использовать ru.yourdomen.removeads
7. Выберите Доступно для продажи, а затем уровень цен.
8. Отображаемое название и описание будут видны клиенту.
9. Нажмите «Сохранить»

Для вашего идентификатора продукта может потребоваться несколько часов для регистрации в iTunesConnect, поэтому придется подождать.

Теперь, когда вы установили информацию о покупке своего приложения в iTunesConnect, зайдите в свой проект Xcode и добавьте StoreKit.framework (Build Phases --> Link Binary With Libraries --> +). Если вы этого не сделаете, покупка в приложении НЕ будет работать!

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

@interface ViewController : UIViewController{
    BOOL areAdsRemoved;
}

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

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

#import <StoreKit/StoreKit.h>

//напишите название вашего view controller вместо MyViewController
@interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver>

@end

@implementation MyViewController //название вашего view controller (такое же, как выше)
  //здесь код вашего приложения
@end

И теперь добавьте следующее в ваш .m-файл.

//Если у вас больше, чем одна встроенная покупка, вы можете объявить их обе здесь
//Например kRemoveAdsProductIdentifier
//и kBuyCurrencyProductIdentifier к каждому свой идентификатор
//
//для этого примера мы используем только один продукт

#define kRemoveAdsProductIdentifier @"ваш product id (который мы создавали в iTunesConnect) напишите здесь"

- (IBAction)tapsRemoveAds{
    NSLog(@"Пользователь запросил удаление рекламы");

    if([SKPaymentQueue canMakePayments]){
        NSLog(@"Пользователь может совершить покупку");

        //Если у вас больше чем одна встроенная покупка, и вы хотели бы
        //чтобы пользователь купил другой продукт просто объявите 
        //другую функцию и измените kRemoveAdsProductIdentifier на
        //id другого продукта

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

    }
    else{
        NSLog(@"Пользователь не может производить платежи из-за родительского контроля");
        
    }
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    SKProduct *validProduct = nil;
    int count = [response.products count];
    if(count > 0){
        validProduct = [response.products objectAtIndex:0];
        NSLog(@"Продукты доступны!");
        [self purchase:validProduct];
    }
    else if(!validProduct){
        NSLog(@"Нет доступных продуктов");
        //Это вызывается, если ваш идентификатор продукта недействителен.
    }
}

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

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

- (IBAction) restore{
    //Это называется, когда пользователь восстанавливает покупки, вы должны подключить это к кнопке
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"Получены восстановленные транзакции: %i", queue.transactions.count);
    for(SKPaymentTransaction *transaction in queue.transactions){
        if(transaction.transactionState == SKPaymentTransactionStateRestored){
            //вызывается когда пользователь успешно восстанавливает покупку
            NSLog(@"Transaction state -> Restored");

           // если у вас более одного продукта для покупки в приложении,
             // вы восстанавливаете правильный продукт для идентификатора.
             // Например, вы можете использовать
             // if (productID == kRemoveAdsProductIdentifier)
             // для получения идентификатора продукта для
             // восстановленных покупок, вы можете использовать
             //
            //NSString *productID = transaction.payment.productIdentifier;
            [self doRemoveAds];
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        }
    }   
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions){
       // если у вас несколько покупок в приложении,
         // вы можете получить идентификатор продукта для этой транзакции
         // с помощью transaction.payment.productIdentifier
         //
         // затем, проверьте идентификатор для продукта
         //, который вы определили для проверки какой продукт пользователь
         // только что купил         

        switch(transaction.transactionState){
            case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
                //Вызывается, когда пользователь находится в процессе покупки, не добавляйте свой код.
                break;
            case SKPaymentTransactionStatePurchased:
            //Это вызывается, когда пользователь успешно приобрел продукт
                [self doRemoveAds]; //Вы можете добавить свой код для того, что вы хотите, чтобы произошло, когда пользователь совершает покупку, для этого урока мы используем удаление объявлений
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"Transaction state -> Purchased");
                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"Transaction state -> Restored");
                //добавьте сюда тот же код, что вы делали для SKPaymentTransactionStatePurchased 
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                //вызывается когда транзакция не закончена
                if(transaction.error.code == SKErrorPaymentCancelled){
                    NSLog(@"Transaction state -> Cancelled");
                    //пользователь отменил покупку ;(
                }
                [[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"];
   // используем NSUserDefaults, чтобы мы могли узнать, купил ли пользователь это или нет.
     // было бы лучше использовать доступ KeyChain или что-то более безопасное
     // для хранения пользовательских данных, поскольку NSUserDefaults можно изменить.
     // Обычный пользователь, не сможете легко его изменить, но
     // лучше использовать что-то более безопасное, чем NSUserDefaults.
     // Для этого урока мы будем использовать NSUserDefaults
    [[NSUserDefaults standardUserDefaults] synchronize];
}

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

areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];

if(areAdsRemoved){
    //если вы удаляете рекламу или делаете еще что-то, вам нужно разместить соответствующий код здесь
}

Теперь, когда вы добавили весь код, зайдите в ваш .xib или storyboard файл и добавьте две кнопки, одну «Куплю», а другую — «Восстановить покупки». Подсоедините tapsRemoveAds IBAction к кнопке «Куплю», которую вы только что создали, и restore IBAction к кнопке «Восстановить покупки». По кнопке «Восстановить покупки» будет проверено, делал ли пользователь ранее эту покупку и если да, то она будет восстановлена.

По-хорошему нужно еще добавить различные алерты, объясняющие пользователю что происходит в процессе покупки или восстановления, а также после их завершения, здесь вам простор для творчества. Как тестировать покупки здесь объяснять не буду, так как этого материала достаточно в сети. Наверное не все еще перешли на Swift, да и много еще Objective C приложений дорабатываются, поэтому думаю, что кому-нибудь моя статья будет полезной.

Комментарии (3)


  1. IgorFedorchuk
    07.08.2017 19:37
    +1

    @interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver>
    

    Серьезно, код работы с инапами прям во ViewController?!


    1. Elis767 Автор
      07.08.2017 20:20
      -2

      Да


  1. rock88
    07.08.2017 21:36
    +1

    areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    

    Береженого бог бережет