Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

kevindosi

macrumors regular
Original poster
Mar 16, 2006
191
0
I'm using BuzzTouch (essentially a CMS for iphone/android app development) to create a content-rich app. I really don't know anything about programming and don't need to in order to make a basic app on buzztouch. Unfortunately, I want to utilize in-app purchases for the content on my app and need to know what I'm doing in xcode order to accomplish that. I was just wondering if someone out there might be willing to tutor me for a couple of lessons to walk me through implementing in-app purchases until I can manage to do it on my own. I'd like to use iChat's screen sharing.
 
Last edited by a moderator:
Hmm, you don't need to pay anyone when you can get free help here..
The thing is, it's actually not that hard, it's the connecting to iTunes Connect that actually sucks.

(i'm gonna post the entire code, but this isn't top notch, so i hope someone can refactor it a bit)

Basically, You want an InAppPurchaseManager
->
InAppPurchaseManager.h (I used SynthesizedSingleton, to make it a Singleton, so you need to download this one from my cloud -> http://cl.ly/420y0p111f1x3H3Z1a0A)
Code:
//
//  InAppPurchaseManager.h
//
//  Created by Thijs Bastiaens on 06/04/12.

#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
#import "SynthesizeSingleton.h"

#define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification"
#define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification"
#define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification"

@interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
{
    SKProduct *proUpgradeProduct;
    SKProductsRequest *productsRequest;
}

+ (InAppPurchaseManager *) sharedInAppPurchaseManager;

// public methods
- (void) requestAddonMPack1Data; 
- (void) requestAddonFPack1Data;
- (void)loadStore;
- (BOOL)canMakePurchases;

/* PURCHASE PACKS */
- (void)purchaseMAddonPack1;
- (void)purchaseFAddonPack1;


@end

InAppPurchaseManager.m

Code:
//
//  InAppPurchaseManager.m
//
//  Created by Thijs Bastiaens on 06/04/12.

#import "InAppPurchaseManager.h"
#import "SVProgressHUD.h"

/*
#define kInAppMPack1ProductId @"com.yourcompany.yourappName.malePack1"
#define kInAppFPack1ProductId @"com.yourcompany.yourappName.femalePack1"
 */
#define kInAppMPack1 @"malePack1"
#define kInAppFPack1 @"femalePack1"

@implementation InAppPurchaseManager
SYNTHESIZE_SINGLETON_FOR_CLASS(InAppPurchaseManager);

- (id)init
{
    self = [super init];
    if (self) {
    }
    return self;
}

- (void)requestAddonMPack1Data
{
    NSSet *productIdentifiers = [NSSet setWithObjects:kInAppMPack1, nil];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}

- (void) requestAddonFPack1Data {
    NSSet *productIdentifiers = [NSSet setWithObjects:kInAppFPack1, nil];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}



#pragma mark -
#pragma mark SKProductsRequestDelegate methods
 
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    /*
    NSMutableArray *products = [[NSMutableArray alloc] initWithArray:response.products];
    proUpgradeProduct = [products count] == 1 ? [[products objectAtIndex:0] retain] : nil;
    if (proUpgradeProduct)
    {
        NSLog(@"Product title: %@" , proUpgradeProduct.localizedTitle);
        NSLog(@"Product description: %@" , proUpgradeProduct.localizedDescription);
        NSLog(@"Product price: %@" , proUpgradeProduct.price);
        NSLog(@"Product id: %@" , proUpgradeProduct.productIdentifier);
    }
    
    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    {
        NSLog(@"Invalid product id: %@" , invalidProductId);
    }*/
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
}

#pragma -
#pragma Public methods

//
// call this method once on startup (For example, App Delegate)
//
- (void)loadStore
{
    // restarts any purchases if they were interrupted last time the app was open
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    
    // get the product description (defined in early sections)
    [self requestAddonMPack1Data];
    [self requestAddonFPack1Data];
}

//
// call this before making a purchase
//
- (BOOL)canMakePurchases
{
    NSLog(@"%i", [SKPaymentQueue canMakePayments]);
    return [SKPaymentQueue canMakePayments];
}

//
// kick off the upgrade transaction
//
- (void)purchaseMAddonPack1
{
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppMPack1];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    [SVProgressHUD showWithStatus:@"Requesting Male Package" maskType:SVProgressHUDMaskTypeGradient];
}

- (void)purchaseFAddonPack1 {
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppFPack1];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    [SVProgressHUD showWithStatus:@"Requesting Female Package" maskType:SVProgressHUDMaskTypeGradient];
}

#pragma -
#pragma Purchase helpers

//
// saves a record of the transaction by storing the receipt to disk
//
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
    if ([transaction.payment.productIdentifier isEqualToString:kInAppMPack1])
    {
        // save the transaction receipt to disk
        [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"addonMPack1TransactionReceipt" ];
        [[NSUserDefaults standardUserDefaults] synchronize];
    } else if ([transaction.payment.productIdentifier isEqualToString:kInAppMPack1]) {
        // save the transaction receipt to disk
        [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"addonFPack1TransactionReceipt" ];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

//
// enable pro features
//
- (void)provideContent:(NSString *)productId
{
    if ([productId isEqualToString:kInAppMPack1])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isMAddonPackage1Bought" ];
        [[NSUserDefaults standardUserDefaults] synchronize];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"packageBought" object:nil];
    } else if ([productId isEqualToString:kInAppFPack1])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isFAddonPackage1Bought" ];
        [[NSUserDefaults standardUserDefaults] synchronize];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"packageBought" object:nil];
    }
}

//
// removes the transaction from the queue and posts a notification with the transaction result
//
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
    // remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    
    NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
    if (wasSuccessful)
    {
        // send out a notification that we’ve finished the transaction
        [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];
    }
    else
    {
        // send out a notification for the failed transaction
        [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
    }
}

//
// called when the transaction was successful
//
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction];
    [self provideContent:transaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}

//
// called when a transaction has been restored and and successfully completed
//
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction.originalTransaction];
    [self provideContent:transaction.originalTransaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}

//
// called when a transaction has failed
//
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // error!
        [self finishTransaction:transaction wasSuccessful:NO];
    }
    else
    {
        // this is fine, the user just cancelled, so don’t notify
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}

#pragma mark -
#pragma mark SKPaymentTransactionObserver methods

//
// called when the transaction status is updated
//
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
            default:
                break;
        }
    }
    [SVProgressHUD dismiss];
}

@end

You can also use an SKProduct category called LocalizedPrice (this is taken from a blog the code, so I don't take any credit).

SKProduct+LocalizedPrice.h

Code:
//
//  SKProduct+LocalizedPrice.h
//
//  Created by Thijs Bastiaens on 06/04/12.

#import <StoreKit/StoreKit.h>

@interface SKProduct (LocalizedPrice)

@property (nonatomic, readonly) NSString *localizedPrice;


@end

.M file
Code:
//
//  SKProduct+LocalizedPrice.m
//
//  Created by Thijs Bastiaens on 06/04/12.

#import "SKProduct+LocalizedPrice.h"

@implementation SKProduct (LocalizedPrice)

- (NSString *)localizedPrice
{
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
    [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    [numberFormatter setLocale:self.priceLocale];
    NSString *formattedString = [numberFormatter stringFromNumber:self.price];
    [numberFormatter release];
    return formattedString;
}

@end

After that, basically in your code you can do stuff like this ->

Code:
- (IBAction)pressedButton:(id)sender {
    UIButton *button = (UIButton*)sender;
    NSInteger taggie = button.tag;
    if (taggie == 0) {
        [self goToMainVCWithArray:[[DataUtil sharedDataUtil] getArrayWithInteger:taggie+1]]; 
    }
    else if ([self packageBought]) {
        [self goToMainVCWithArray:[[DataUtil sharedDataUtil] getArrayWithInteger:taggie+1]]; 
    } else {
        if ([[DataUtil sharedDataUtil] gender] == kTypeMale) {
            [[InAppPurchaseManager sharedInAppPurchaseManager] purchaseMAddonPack1];
        } else if ([[DataUtil sharedDataUtil] gender] == kTypeFemale) {
            [[InAppPurchaseManager sharedInAppPurchaseManager] purchaseFAddonPack1];
        }
    }
}

- (BOOL) packageBought {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([[DataUtil sharedDataUtil] gender] == kTypeMale) {
        if ([defaults boolForKey:@"isMAddonPackage1Bought"] == YES) {
            return YES;
        } else {
            return NO;
        }
    } else  if ([[DataUtil sharedDataUtil] gender] == kTypeFemale) {
        if ([defaults boolForKey:@"isFAddonPackage1Bought"] == YES) {
            return YES;
        } else {
            return NO;
        }
    }
    return NO;
}

I tried to make a clean example, I hope it can helps you :)
(the itunes connect steps are ignored in my "guide")

EDIT
ALso, in your view controller, you can listen to ->
Code:
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadButtons) name:@"packageBought" object:nil];

To optionally refresh your UI :)
 
Hey, thanks for your post! That looks like a very clear tutorial, and I know there are a lot of helpful people on here who can help out. The problem is that I'm such a beginner, that I don't feel completely comfortable even with a nice tutorial like this. I can try it on my own using a tutorial like yours, I just don't feel completely comfortable because I still don't know what I'm doing, haha. That's why I was looking for someone who can guide me through the process, because I'm a visual person and the feedback is helpful. If I can't find anyone, I'll give this a whirl too.
 
Just PM Me with more specific questions, otherwise this thread will end up in a "Star Wars vs Star Trek thread", with that I mean, in the end, people will end up talking about the SDK of In App Purchase of Apple, next thing you know, you're talking bout how LIght Sabers are the best.. (I want to avoid that, so mail me)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.