In-App Purchase with an IBAction / Button

前端 未结 3 1504
暖寄归人
暖寄归人 2020-12-17 06:25

I\'m using Ray Wenderlich tutorial to create IAP (http://www.raywenderlich.com/23266/) , everything works well, but I don\'t want to use table view on my app, I want to use

3条回答
  •  有刺的猬
    2020-12-17 07:28

    Thanks to everyone that helped me here! I finally made it work.

    I came out with a different code. I will try to explain everything I did here so if anyone wants to do the same.

    Fist create an App ID on iOS Provisioning Portal and create the IAP Purchase on iTunes Connect.

    Then, get this project: http://xcodenoobies.blogspot.com.br/2012/04/implementing-inapp-purchase-in-xcode.html and import the "SFHFKeychainUtils.h" and .m files. Don't forget to add the SFHFKeychainUtils.m to your Compile Sources (Project -> Build Phases - > Compile Sources).

    Now the code:

    .h

    #import 
    
    (...)
    
     {
    IBOutlet UIButton *feature2Btn;
    IBOutlet UILabel *featureLabel, *statusLabel;
    UIAlertView *askToPurchase;
    
    int64_t coins;
    IBOutlet UILabel * coinsLabel;
    
    }
    
    @property (nonatomic, retain)  UIButton *feature2Btn;
    @property (nonatomic, retain)  UILabel *featureLabel, *statusLabel;
    @property (nonatomic, assign)  int64_t coins;
    
    -(IBAction)button10Coins:(id)sender;
    -(BOOL)IAPItemPurchased;
    

    .m

    #import "SFHFKeychainUtils.h"
    
    @synthesize feature2Btn, featureLabel, statusLabel, coins;
    #define kStoredData @"com.IAPID.10coins"
    

    The button:

    -(IBAction)button10Coins:(id)sender {
    
        askToPurchase = [[UIAlertView alloc]
                         initWithTitle:@"IAP"
                         message:@"Would you like to buy 10 coins?"
                         delegate:self
                         cancelButtonTitle:nil
                         otherButtonTitles:@"Yes", @"No", nil];
        askToPurchase.delegate = self;
        [askToPurchase show];
    }
    

    Check if IAP is available:

    #pragma mark AlertView Delegate
    
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    
    if (alertView==askToPurchase) {
        if (buttonIndex==0) {
            // user tapped YES, but we need to check if IAP is enabled or not.
            if ([SKPaymentQueue canMakePayments]) {
    
                NSLog(@"IAP: Checking if IAP Available");
    
                SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"com.IAPID.10coins"]];
    
                request.delegate = self;
                [request start];
    
    
            } else {
                UIAlertView *tmp = [[UIAlertView alloc]
                                    initWithTitle:@"Prohibited"
                                    message:@"Parental Control is enabled, cannot make a purchase!"
                                    delegate:self
                                    cancelButtonTitle:nil
                                    otherButtonTitles:@"Ok", nil];
                [tmp show];
            }
        }
    } }
    

    Request the product, if available, or cancel the purchase if not:

    -(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    {
    
    NSLog(@"IAP: Received Response");
    
    // remove wait view here
    statusLabel.text = @"";
    
    SKProduct *validProduct = nil;
    int count = [response.products count];
    
    if (count>0) {
    
        NSLog(@"IAP: Available, starting transaction");
    
        validProduct = [response.products objectAtIndex:0];
    
    
        SKPayment *payment = [SKPayment paymentWithProductIdentifier:@"com.IAPID.10coins"];
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    
    
    } else {
    
        NSLog(@"IAP: Item not found");
    
        UIAlertView *tmp = [[UIAlertView alloc]
                            initWithTitle:@"Internet Connection Required"
                            message:@"You must connect to a Wi-Fi  or cellular data network to perform an In-App Purchase."
                            delegate:self
                            cancelButtonTitle:nil
                            otherButtonTitles:@"Ok", nil];
        [tmp show];
    } }
    

    Finally, the action:

    #pragma mark StoreKit Delegate
    
    -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
    
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchasing: {
    
                // show wait view here
                NSLog(@"IAP: Processing...");}
                break;
    
            case SKPaymentTransactionStatePurchased:{
    
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                // remove wait view and unlock feature 2
                statusLabel.text = @"Done!";
                UIAlertView *tmp = [[UIAlertView alloc]
                                    initWithTitle:@"Completet"
                                    message:@"The purchase has been completed!"
                                    delegate:self
                                    cancelButtonTitle:nil
                                    otherButtonTitles:@"Ok", nil];
    
                [tmp show];
    
    
                NSError *error = nil;
                [SFHFKeychainUtils storeUsername:@"IAPNoob01" andPassword:@"whatever" forServiceName:kStoredData updateExisting:YES error:&error];
    
                // apply purchase action  - hide lock overlay and
                [feature2Btn setBackgroundImage:nil forState:UIControlStateNormal];
    
                // Get The Coins, rock, favor points, whatever:
    
                self.coins = coins +10;
                coinsLabel.text = [NSString stringWithFormat: @"%lld", self.coins];
    
            }
                break;
    
            case SKPaymentTransactionStateRestored:{
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                // remove wait view here
                statusLabel.text = @"";}
                break;
    
            case SKPaymentTransactionStateFailed:{
    
                if (transaction.error.code != SKErrorPaymentCancelled) {
                    NSLog(@"Error payment cancelled");
                }
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                // remove wait view here
                statusLabel.text = @"Purchase Error!";}
                break;
    
            default:
                break;
        }
    } }
    

    Not quite sure if you must add this or not:

    -(void)requestDidFinish:(SKRequest *)request {
    }
    
    -(void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    NSLog(@"Failed to connect with error: %@", [error localizedDescription]);
    }
    

    This is the easiest code ever. Not sure if Apple will approve, but it is working. This works on iOS 4.3 and higher which I think it is great, but doesn't implement the Receipts so some smart kids will be able to get coins for free.

    Don't forget to create the Consumable item on iTunes Connect and change the id "com.IAPID.10coins" with the correct ID created created by you over there.

    "paymentWithProductIdentifier" is deprecated but still works, to fix it change it for "paymentWithProduct" and find a way to add the IAP ID. I tried but didn't succeed.

    This is ARC ready, except the "SFHFKeychainUtils.m", you can try to fix it or disable ARC on that single file, here is the tutorial: http://www.leesilver.net/1/post/2011/8/disabling-arc-on-certain-files-in-xcode.html

    You also must add the ScoreKit and Security framework to your project.

    For consumable itens, thats it! For non-consumable you must add a RESTORE button or Apple will give you a rejection. But that's pretty easy:

    // RESTORE
    
     - (IBAction)IAPRestore:(id)sender
     {
         [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
         [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
     }
    
    
     - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
     {
         NSLog(@"Restore completed transactions finished.");
         NSLog(@" Number of transactions in queue: %d", [[queue transactions] count]);
         for (SKPaymentTransaction *trans in [queue transactions])
         {
             NSLog(@" transaction id %@ for product %@.", [trans transactionIdentifier], [[trans payment] productIdentifier]);
             NSLog(@" original transaction id: %@ for product %@.", [[trans originalTransaction] transactionIdentifier],
              [[[trans originalTransaction] payment]productIdentifier]);
    
    
        if ([[[trans payment] productIdentifier] isEqual: @"com.AppID.IAPID"]) {
    
            NSLog(@"Purchase Restored");
    
            // Do your stuff to unlock
    
              }
    
         }
         UIAlertView *tmp = [[UIAlertView alloc]
                             initWithTitle:@"Purchases Restored"
                             message:@"Your previously purchased products have been restored!"
                             delegate:self 
                             cancelButtonTitle:nil 
                             otherButtonTitles:@"OK", nil]; 
    
                     [tmp show];
    
     }
    

    I hope this is useful to someone and that Apple approves it :)

    UPDATE: Apple approved it and sales are coming in just fine, iOS 4.3, 5 and 6 sales are working :) UPDATE2: Tested and working flawlessly on Xcode 4.6 and iOS 6.1.2.

提交回复
热议问题