0

Please be patient. This is my first time setting up an in-app purchase and I will try and provide as much information as I can. Instead of grooming the internet for someone else's code I ended up purchasing a class from infinite skills specifically on how to add a non-renewing subscription in-app purchase to my app. Their class was outdated, and come to find out, the "follow along" project files did not download. So I did a lot of research and this is what I came up with:

  1. I created an in-app purchase in itunes, the in-app identifier matches the identifier in my .m coding.

  2. I created a new provisioning profile and enabled in-app purchases and the icloud to manage the backend for the purchase. When I returned to the app i enabled icloud and made sure in-app purchases was turned on in the project target.

  3. I created a view controller, added buttons and for the subclass I used SKStoreProductViewController. That View Controller looks like this: in-app View Controller

  4. I imported the storekit and the SK delegates.

It crashes when I hit the tabbarbutton from my home view to bring me to the in-app view controller. error

Finally the coding: InAppViewController.h:

#import <StoreKit/StoreKit.h>

@interface InAppViewController : SKStoreProductViewController

@end

InAppViewController.m:

//
//  InAppViewController.m
//  Contractor Rich
//
//  Created by Joshua Hart on 2/1/15.
//  Copyright (c) 2015 Code By Hart. All rights reserved.
//

#import "InAppViewController.h"
#import <StoreKit/StoreKit.h>

@interface InAppViewController ()<SKProductsRequestDelegate, SKPaymentTransactionObserver>

@property (weak, nonatomic) IBOutlet UIButton *btnBuyAccess;
@property (weak, nonatomic) IBOutlet UIButton *btnPremiumFeature;
@property (weak, nonatomic) IBOutlet UILabel *lblStatus;

@property (strong, nonatomic) SKProduct *product;
@property (strong, nonatomic) NSUbiquitousKeyValueStore *keyStore;
@property (strong, nonatomic) NSDate *expirationDate;

- (IBAction)btnBuyAccessTouched: (id)sender;

-(void)getProductInfo;


@end

@implementation InAppViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _btnBuyAccess.userInteractionEnabled = NO;

    _keyStore = [[NSUbiquitousKeyValueStore alloc] init];




    _expirationDate = [_keyStore objectForKey:@"expirationDate"];
    NSDate *today = [NSDate date];
    if (_expirationDate == nil)
        _expirationDate = today;

    if (_expirationDate > today) {
        _btnPremiumFeature.userInteractionEnabled = YES;
    }
        else {
            _btnBuyAccess.userInteractionEnabled = YES;

            [self getProductInfo];
        }
    }

-(void) getProductInfo{

    if ([SKPaymentQueue canMakePayments])
    {
        NSMutableArray *productIdentifierList = [[NSMutableArray alloc] init];

        [productIdentifierList addObject:[NSString stringWithFormat:@"com.joshua.contractorrich.inapp"]];

                                          SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithArray:productIdentifierList]];

        request.delegate = self;
        [request start];
    }
}

-(void) productsRequest: (SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *products = response.products;

    if (products.count != 0)
    {
        _product = products[0];
        _btnBuyAccess.userInteractionEnabled = YES;
        _lblStatus.text = @"Ready for Purchase!";
    }else{
        _lblStatus.text = @"Product was not Found!";
    }
    products = response.invalidProductIdentifiers;
    for (SKProduct *product in products)
    {
        NSLog(@"Product not found: %@", product);
    }

}



- (IBAction)btnBuyAccessTouched: (id)sender {

    SKPayment *payment = [SKPayment paymentWithProduct:_product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                _btnPremiumFeature.userInteractionEnabled = YES;
                _lblStatus.text = @"Purchase Completed!";
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;

            case SKPaymentTransactionStateFailed: NSLog(@"Transaction Failed!");
                _lblStatus.text = @"Purchase Failed!";
                [[SKPaymentQueue defaultQueue]
            finishTransaction:transaction];

            default:
                break;
        }
    }
}

-(void) setExpirationDate {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setMonth:3];
    NSDate *expirationDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:[NSDate date] options:0];
    [_keyStore setObject:expirationDate forKey:@"expirationDate"];
    [_keyStore synchronize];
}

-(void) initializeStore {
    [_keyStore setObject:nil forKey:@"expirationDate"];
    [_keyStore synchronize];
}



- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

Please understand this is my first time trying this. What may seem stupid is still the learning phase for me. Thank you!

Joshua Hart
  • 772
  • 1
  • 21
  • 31
  • What is CUICatalog? That is the source of the error message. – matt Feb 01 '15 at 02:40
  • Its a ui image that i cannot find thats caused some headaches somewhere, it's been an error that i havent been able to fix for quite sometime. App runs good even tho that displays in the debugger tho. Definitely not affecting the in-app runtime error. – Joshua Hart Feb 01 '15 at 02:43
  • But that's the only problem you're having. If that's not a problem, what problem are you having? I see no other "runtime error" in your screen shot. – matt Feb 01 '15 at 03:06

1 Answers1

2

There is no runtime error in this story. All that's happened is that you've created an Exceptions breakpoint. Now you are pausing at it. Simply resume running. If this is troublesome, disable the Exceptions breakpoint.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • You are correct, however now when I try to run it I receive the Error: 'InAppViewController must be used in a modal view controller', and then terminates with an uncaught NSException... – Joshua Hart Feb 01 '15 at 13:24
  • "now when I try to run it I receive the Error" Right, but as I'm sure you now realize, that's the point. You need to get past the breakpoint to find out what the exception _is_! – matt Feb 01 '15 at 15:09
  • I get no error now, however my IAP View Controller presents with a total black screen, no errors, what could cause this? – Joshua Hart Feb 01 '15 at 22:52
  • Typically because the view controller is failing to find the nib containing its view. Is its view in a nib (a _.xib_ file)? If that's the issue, see my discussion here: http://stackoverflow.com/a/25539016/341994 – matt Feb 01 '15 at 23:42
  • If that's _not_ the issue, I have to wonder whether you are right to ignore so blithely the "could not load the image" error. – matt Feb 01 '15 at 23:45
  • All the views are on the storyboard. – Joshua Hart Feb 02 '15 at 01:43