首页 文章

如何在iOS应用程序中添加应用内购买?

提问于
浏览
244

如何在iOS应用中添加应用内购买?什么是详细信息,是否有任何示例代码?

对于如何向iOS应用添加应用内购买,这意味着各种各样

4 回答

  • 12

    只需将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")
    
            }
    
    
        }
    }
    }
    
  • 0

    我知道我发布这篇文章已经很晚了,但是当我学习IAP模型的绳索时,我也有类似的经历 .

    应用内购买是Storekit框架实现的iOS中最全面的工作流程之一 . 如果你耐心地阅读它,那么entire documentation就很清楚了,但在技术性方面有点先进 .

    总结一下:

    1 - 请求产品 - 使用SKProductRequest和SKProductRequestDelegate类发出产品ID请求,并从您自己的itunesconnect商店接收回来 .

    这些SKProducts应该用于填充用户可以用来购买特定产品的商店UI .

    2 - 发出付款请求 - 使用SKPayment和SKPaymentQueue将付款添加到交易队列 .

    3 - 监视状态更新的事务队列 - 使用SKPaymentTransactionObserver协议的updatedTransactions方法监视状态:

    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的restoreCompletedTransactions来完成此任务 - 第3步将处理其余部分,以及SKPaymentTransactionObserver的以下方法:

    paymentQueueRestoreCompletedTransactionsFinished
    restoreCompletedTransactionsFailedWithError
    

    Here是一个循序渐进的教程(由我自己试图理解它而由我编写)解释了它 . 最后,它还提供了可以直接使用的代码示例 .

    Here是我创建的另一个用于解释某些事情的文章,只有文字才能更好地描述 .

  • 534

    在Xcode 5中为 iOS 10 (和 iOS 9, 8 and 7 )进行应用内购买的最佳方法是执行以下操作:

    • 转到itunes.connect.apple.com并登录

    • 单击 My Apps ,然后单击要添加购买的应用程序

    • 单击 Features Headers ,然后选择左侧的 In-App Purchases

    • 单击中间的 + 图标

    • 在本教程中,我们将添加应用内购买以移除广告,因此请选择 non-consumable . 如果您要向用户发送物理项目,或者向他们提供他们可以多次购买的东西,您可以选择 consumable .

    • 对于参考名称,放置你想要的任何东西(但要确保你知道它是什么)

    • 对于产品ID put tld.websitename.appname.referencename 这将是最好的,所以例如,你可以使用 com.jojodmo.blix.removeads

    • 选择 cleared for sale ,然后选择价格等级为1(99¢) . 第2层为1.99美元,第3层为2.99美元 . 如果您单击 view pricing matrix ,则可以使用完整列表 . 我建议您使用第1层,因为这通常是删除广告所付出的最多的人 .

    • 单击蓝色 add language 按钮,然后输入信息 . 这将全部显示给客户,所以不要让他们看到

    • For hosting content with Apple 选择 no

    • 您现在可以将评论说明留空 .

    • 跳过 screenshot for review 现在,我们跳过的所有内容都会回来 .

    • 点击'save'

    您的产品ID可能需要几个小时才能在 iTunesConnect 中注册,因此请耐心等待 .

    现在您已经在iTunesConnect上设置了应用程序内购买信息,进入Xcode项目,然后转到应用程序管理器(方法和头文件所在位置的蓝色页面图标)单击您的应用程序在目标下(应该是第一个)然后去一般 . 在底部,您应该看到 linked frameworks and libraries 单击小加号并添加框架 StoreKit.framework 如果您不这样做,应用程序内购买将无效!

    如果您使用Objective-C作为应用程序的语言,则可以跳过这五个步骤 . 否则,如果您使用的是Swift,请执行以下操作:

    • 转到 File > New > File... (命令⌘N)创建新的 .h ( Headers )文件 . 在本教程的其余部分中,此文件将被称为“您的 .h 文件”

    • 出现提示时,单击 Create Bridging Header . 这将是我们的桥接头文件 . 如果出现提示,请转到步骤3.如果出现提示,请跳过步骤3直接转到步骤4 .

    • 在主项目文件夹中创建另一个名为 Bridge.h.h 文件,然后转到应用程序管理器(蓝色页面图标),然后在 Targets 部分中选择您的应用程序,然后单击 Build Settings . 找到 Swift Compiler - Code Generation 的选项,然后将 Objective-C Bridging Header 选项设置为 Bridge.h

    • 在桥接头文件中,添加行 #import "MyObjectiveCHeaderFile.h" ,其中 MyObjectiveCHeaderFile 是您在步骤1中创建的头文件的名称 . 因此,例如,如果您将头文件命名为 InAppPurchase.h ,则应将行 #import "InAppPurchase.h" 添加到桥头文件中 .

    • 通过转到 File > New > File... (命令⌘N)创建新的Objective-C方法( .m )文件 . 将其命名为您在步骤1中创建的头文件 . 例如,如果您在步骤1 InAppPurchase.h中调用了该文件,则可以将其命名为新文件InAppPurchase.m . 在本教程的其余部分中,此文件将被称为“Your .m file” .

    现在我们将进入实际编码 . 将以下代码添加到 .h 文件中:

    BOOL areAdsRemoved;
    
    - (IBAction)restore;
    - (IBAction)tapsRemoveAds;
    

    接下来,您需要将 StoreKit 框架导入 .m 文件,并在 @interface 声明后添加 SKProductsRequestDelegateSKPaymentTransactionObserver

    #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 iTunesConnect) 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;
            }
        }
    }
    

    现在,您想要为用户完成事务时将要发生的代码添加代码,对于本教程,我们使用删除添加,您必须添加自己的代码,以便在加载 Banner 视图时发生的情况 .

    - (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
    }
    

    现在您已添加了所有代码,请进入 .xibstoryboard 文件,然后添加两个按钮,一个说购买,另一个说恢复 . 将 tapsRemoveAds IBAction 连接到您刚刚创建的购买按钮,将 restore IBAction 连接到恢复按钮 . restore 操作将检查用户之前是否已购买应用程序内购买,并且如果他们还没有购买,则免费向他们提供应用内购买 .

    接下来,进入iTunesConnect,然后单击 Users and Roles 然后单击 Sandbox Testers Headers ,然后单击左侧的 + 符号,表示 Testers . 您可以随意添加名字和姓氏,电子邮件不必是真实的 - 您只需要能够记住它 . 输入密码(您必须记住)并填写其余信息 . 我建议您将 Date of Birth 设为使用户年满18周岁的日期 . App Store Territory HAS 在正确的国家/地区 . 接下来,注销现有的iTunes帐户(您可以在本教程之后重新登录) .

    现在,在您的iOS设备上运行您的应用程序,如果您尝试在模拟器上运行它,购买将始终出错,您在iOS设备上运行它 . 应用程序运行后,点按“购买”按钮 . 当系统提示您登录iTunes帐户时,请以我们刚创建的测试用户身份登录 . 接下来,当它要求您确认购买99美分或您设置价格等级时, TAKE A SCREEN SNAPSHOT OF IT 这将是您在iTunesConnect上用于 screenshot for review 的内容 . 现在取消付款 .

    现在,转到iTunesConnect,然后转到 My Apps > the app you have the In-app purchase on > In-App Purchases . 然后点击您的应用内购买,然后点击应用内购买详情下的修改 . 完成后,将刚刚拍摄的iPhone上的照片导入计算机,然后将其上传为截图供审阅,然后在评论说明中输入您的 TEST USER 电子邮件和密码 . 这将有助于苹果在审核过程中 .

    完成此操作后,返回iOS设备上的应用程序,仍以测试用户帐户登录,然后单击购买按钮 . 这一次,确认付款 Don't worry, this will NOT charge your account ANY money, test user accounts get all in-app purchases for free 确认付款后,请确保用户实际购买产品时会发生什么 . 如果没有,那么那将是你的 doRemoveAds 方法的错误 . 同样,我建议使用将背景更改为蓝色以测试应用内购买,但这不应该是您实际的应用内购买 . 如果一切正常,你就会好起来!只需确保在将新的二进制文件上传到iTunesConnect时将其包含在新二进制文件中!


    以下是一些常见错误:

    Logged: No Products Available

    这可能意味着三件事:

    • 您未在代码中输入正确的应用内购买ID(以上代码中的标识符 kRemoveAdsProductIdentifier

    • 您没有在iTunesConnect清除您的应用内购买

    • 您没有等待在iTunesConnect中注册应用内购买ID . 等待几个小时创建ID,您的问题应该得到解决 .

    • 您未完成填写协议,税务和银行信息 .


    如果它没有沮丧!不要放弃!我需要大约5个小时才能完成这项工作,大约需要10个小时才能找到正确的代码!如果你完全使用上面的代码,它应该工作正常 . 如果您有任何问题,请随时发表评论 .

    我希望这有助于所有希望在他们的iOS应用程序中添加应用程序内购买的人 . 干杯!

  • 4

    RMStore是一个用于应用程序内购买的轻量级iOS库 . 它包装了StoreKit API,为您提供了异步请求的方便块 . 购买产品就像调用单一方法一样简单 .

    对于高级用户,此库还提供收据验证,内容下载和事务持久性 .

相关问题