美文网首页
iOS 内购 IAP 流程

iOS 内购 IAP 流程

作者: 包砸豆沙馅 | 来源:发表于2020-02-21 21:11 被阅读0次
iOS内购也算是老生常谈的一个技术点了, 但是对于我这种刚刚接触的人来讲, 还是踩了不少的坑, 这几天刚搞完, 来简单的总结一下内购的流程.
暂且不说申请税务, 添加银行卡 这些步骤, 直接进入代码.

首先了解一下iOS IAP内购的总的流程, 如下图:

内购大致的流程图

那么根据上图所述6点进行 代码阐述.

  1. Appdelegate中应用程序启动时 设置transectionObserver:
    SKPaymentQueue.default().add(self)
  2. 根据后端返回的产品id 或者 产品id 的集合, 进行产品的查询.
@discardableResult
    public func requestProductsInfo(productIds: [String]) -> SKProductsRequest {
        let request = SKProductsRequest(productIdentifiers: Set(productIds))
        request.delegate = self
        request.start()
        return request
    }
  1. SKProductsRequestDelegate代理方法中 可以找到接收到苹果服务器返回的查询产品方法
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let products = response.products
        print("products : \(products)")
/// 拿到数据集合 进行UI界面的更新
#warning UpdateUI
    }

4, 5 . 如果后端有订单系统的话, 那么当点击某一款产品时, 要向后端请求生成订单号. 没有订单系统, 不要订单号也是可以的. 然后根据product创建payment实例, 并将其放入paymentQueue中, 发起付款请求:

 public func purchaseProduct(product: SKProduct, orderId: String?) {
        let payment = SKMutablePayment(product: product)
        //设置订单号
        if let orderId = orderId {
            payment.applicationUsername = orderId
        }
        SKPaymentQueue.default().add(payment)
    }
  1. . 收到付款的回调, 回调中会将transection 带出来, 可以根据transection.transactionState 来判断交易的状态, 根据交易状态来进行不同的处理, 要记住, 处理结束之后 一定要调用结束交易的代码:
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            //            print("有交易更新")
          switch transaction.transactionState {
                 case .purchasing:
                   printLog("商品添加进列表")
                case .purchased:
                   printLog("交易完成")
               case .failed:
                     if let swiftError = transaction.error {
                           let error = swiftError as NSError
                           if error.code == SKError.Code.paymentCancelled.rawValue {
                                         //                    printLog("交易取消")
                             } else {
                                       //                    printLog("交易失败")
                             }
                    }

            SKPaymentQueue.default().finishTransaction(transaction)
        case .restored:
            //            printLog("已经购买过商品")
            SKPaymentQueue.default().finishTransaction(transaction)
        case .deferred:
            break
        @unknown default:
            break
             }
      }
}

要注意:

  • 发起productRequest之前要判断当前设备或者AppId是否支持IAP:
 func canMakePurchases() -> Bool {
        return SKPaymentQueue.canMakePayments()
 }
  • 如果当前产品为非消耗类型的, 那么只能购买一次, 再次购买的话就会出现以下图片:


    非消耗类型产品, 多次购买

    如果你的产品中有非消耗类型的产品, 那么需要判断当前产品是否已经购买过, 如果购买过, 苹果要求要有一个恢复购买按钮, 用来恢复当前appid的权益, 否则会被guildline 3.1.1 拒绝掉. 可通过下面的步骤查询到当前已经购买过的产品:

1. 在进入商品列表或者购买页面的时候 向PaymentQueue中添加存储已经完成交易的操作: SKPaymentQueue.default().restoreCompletedTransactions()
2. 接下来会出发SKPaymentTransactionObserver中的完成交易的代理方法, 在代理方法中 可以将已经完成交易的产品 存储起来:
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        // 处理已经购买过的商品.
        for transaction in queue.transactions {
            let productId = transaction.payment.productIdentifier
            printLog("已经购买过的产品id = \(productId)")
            /// 可以将产品或者产品id放入集合中 存储起来.
        }
    }

如果产品类型属于非续期订阅, 那么以上方法是查不出来的. 因为非续期订阅 是可以无限次购买的产品, 产品有有效期, 买的越多, 有效期越长, 例如为期一年的已归档文章目录订阅.

写在最后

关于iOS内购的代码流程 差不多也就这些, 但是如果要写出体系比较健壮的内购,例如: 发起购买时不会丢单, 如果丢单, 如何处理, 如何应对各种异常情况, 还是需要很大的经理和时间投入, 不单单要客户端处理好每一步, 而且需要服务端的紧密配合. 我还有很多的小细节没有涉及到, 如果有什么不对, 欢迎指正交流.

相关文章

网友评论

      本文标题:iOS 内购 IAP 流程

      本文链接:https://www.haomeiwen.com/subject/tidhqhtx.html