xcode專案設定

把Capabilities中的In-App Purchase打開

程式碼: 這邊只列出重點部分

class PurchaseVC: UIViewController , UITableViewDelegate , UITableViewDataSource , SKProductsRequestDelegate , SKPaymentTransactionObserver{


    @IBOutlet weak var tableView: UITableView!
    var productIDs: [String] = [String]() // 產品ID(Consumable_Product、Not_Consumable_Product)
    var productsArray: [SKProduct] = [SKProduct]() //  存放 server 回應的產品項目
    var selectedProductIndex: Int! // 點擊到的購買項目
    var isProgress: Bool = false // 是否有交易正在進行中
 override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.productIDs.append("Consumable_Product") // 消耗性產品
        self.productIDs.append("NotConsumable_Product") // 非消耗性產品
        self.requestProductInfo()
        // Do any additional setup after loading the view.
    }

    override func viewWillDisappear(_ animated: Bool) {
        SKPaymentQueue.default().remove(self) //移除觀察者
    }
func requestProductInfo() {
        if SKPaymentQueue.canMakePayments() {
            // 取得所有在 iTunes Connect 所建立的內購項目
            let productIdentifiers: Set<String> = NSSet(array: self.productIDs) as! Set<String>
            let productRequest: SKProductsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)

            productRequest.delegate = self
            productRequest.start() // 開始請求內購產品
        } else {
            print("取不到任何內購的商品...")
        }
    }

    // 詢問是否購買或回復的 Action Sheet
    func showActionSheet(_ product: Product) {
        // 代表有購買項目正在處理中
        if self.isProgress {
            return
        }

        var message: String!
        var buyAction: UIAlertAction?
        var restoreAction: UIAlertAction?

        switch product {
        case .consumable, .nonConsumable:
            // 購買消耗性、非消耗性產品
            message = "確定購買產品?"
            buyAction = UIAlertAction(title: "購買", style: UIAlertActionStyle.default) { (action) -> Void in

                if SKPaymentQueue.canMakePayments() {
                    // 設定交易流程觀察者,會在背景一直檢查交易的狀態,成功與否會透過 protocol 得知
                    SKPaymentQueue.default().add(self)

                    // 取得內購產品
                    let payment = SKPayment(product: self.productsArray[self.selectedProductIndex])

                    // 購買消耗性、非消耗性動作將會開始在背景執行(updatedTransactions delegate 會接收到兩次)
                    SKPaymentQueue.default().add(payment)
                    self.isProgress = true

                }
            }
        default:
            // 復原購買產品
            message = "是否回復?"
            restoreAction = UIAlertAction(title: "回復", style: UIAlertActionStyle.default) { (action) -> Void in
                if SKPaymentQueue.canMakePayments() {
                    SKPaymentQueue.default().restoreCompletedTransactions()
                    self.isProgress = true

                }
            }
        }


        let actionSheetController = UIAlertController(title: "測試內購", message: message, preferredStyle: UIAlertControllerStyle.actionSheet)

        let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)

        actionSheetController.addAction(buyAction != nil ? buyAction! : restoreAction!)
        actionSheetController.addAction(cancelAction)

        self.present(actionSheetController, animated: true, completion: nil)
    }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! IAPTableViewCell

        let product = self.productsArray[indexPath.row] // 請求的產品

        cell.productLabel.text = "\(product.localizedTitle)\n\(product.localizedDescription)"
        // localizedTitle(商品名稱)、localizedDescription(商品描述)

        cell.priceLabel.text = "$\(product.price)"

        return cell
    }
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        // 送出購買則會 update 一次,購買成功 server 又會回傳一次 update
        for transaction in transactions {
            switch transaction.transactionState {
            case SKPaymentTransactionState.purchased:
                print("交易成功...")
                // 不管交易是否成功,都要把這筆交易finish掉
                SKPaymentQueue.default().finishTransaction(transaction)
                self.isProgress = false

                // 移除觀查者
                SKPaymentQueue.default().remove(self)

                // 付款成功,回傳給ViewController
                delegate.didBuySomething(self, self.selectedProductIndex == 0 ? Product.consumable : Product.nonConsumable)


                self.dismiss(animated: true, completion: nil)
            case SKPaymentTransactionState.failed:
                print("交易失敗...")

                SKPaymentQueue.default().finishTransaction(transaction)
                self.isProgress = false

                if let error = transaction.error as? SKError {
                    switch error.code {
                    case .paymentCancelled:
                        // 輸入 Apple ID 密碼時取消
                        print("Transaction Cancelled: \(error.localizedDescription)")
                    case .paymentInvalid:
                        print("Transaction paymentInvalid: \(error.localizedDescription)")
                    case .paymentNotAllowed:
                        print("Transaction paymentNotAllowed: \(error.localizedDescription)")
                    default:
                        print("Transaction: \(error.localizedDescription)")
                    }
                }

                SKPaymentQueue.default().finishTransaction(transaction)
                self.isProgress = false
            case SKPaymentTransactionState.restored:
                print("復原成功...")

                SKPaymentQueue.default().finishTransaction(transaction)
                self.isProgress = false

                // 回復成功,回傳給ViewController
                self.delegate.didBuySomething(self, Product.restore)

                self.showMessage(.restore)
            default:
                print(transaction.transactionState.rawValue)
                break
            }
        }
    }


    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {

        print("invalidProductIdentifiers: \(response.invalidProductIdentifiers.description)")
        // invalidProductIdentifiers.description 會印出不合法的內購項目,例如:沒有設定價錢、已停用的等等


        if response.products.count != 0 {
            // 取得IAP產品
            for product in response.products {
                self.productsArray.append(product)
            }
            self.tableView.reloadData()
        }
        else {
            print("取不到任何商品...")
        }
    }

    // 復原購買失敗
    func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
        print("復原購買失敗...")
        print(error.localizedDescription)
    }

    // 回復購買成功(若沒實作該 delegate 會有問題產生)
    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        print("復原購買成功...")
    }

results matching ""

    No results matching ""