iOS內購集成

In-App Purchase:應用內購買服務,簡稱IAP。是蘋果爲App內的虛擬商品和服務的交易定製的系統。git

所謂應用內購買,是指在操做虛擬商品交易的時候,不容許使用相似微信/支付寶/Apple Pay第三方支付手段,若是經過另類方式避開的話,會被下架。github

配置內購信息

請參考前一篇文章 《iOS打包上架最新(含內購)2019年swift

建立商品類型

消耗型:使用一次並耗盡,能夠重複購買。相似於寶箱,武器皮膚安全

非消耗型:只需購買一次,不會過時。相似於地圖,電子書ruby

自動續期訂閱:購買一次後服務或內容會自動續訂,直到用戶決定取消。相似於Apple musicbash

非續期訂閱:購買一次後,不會自動續訂,而且能夠再次購買,等同於購買一段時間的服務能夠疊加。相似於會員,必定數量鑽石服務器

StoreKit

經過StoreKit框架使應用程序鏈接到App Store,以提示並安全地處理付款。微信


先遵循SKProductsRequestDelegate,SKPaymentTransactionObserver協議。app

//添加支付監聽
SKPaymentQueue.default().add(self) 
//移除監聽
SKPaymentQueue.default().remove(self)複製代碼

點擊購買
框架

//是否容許付款(經過權限限制購買的人羣)
if SKPaymentQueue.canMakePayments() {
    pid:這裏指的是選擇套餐對應的id,從蘋果後臺的套餐配置生成,App服務端獲取
	let set = NSSet(array: [pid])
	//檢索本地化商品信息
	let request = SKProductsRequest(productIdentifiers: set as! Set<String>)  
	request.delegate = self
	request.start()
}else {
    print("禁止購買")
}複製代碼

恢復購買,這裏的做用是持久化咱們的訂單信息,下次從新監聽支付隊列的時候會從新調用

恢復以前的購買
SKPaymentQueue.default().restoreCompletedTransactions()//非續訂訂閱型和消耗型沒法恢復

購買歷史記錄的事務,添加回隊列出錯回調
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
	print("錯誤恢復: \(error)")
}

恢復購買,成功添加隊列回調
func paymentQueueRestoreCompletedTransactionsFinished(_ queue:SKPaymentQueue){
    
}複製代碼

產品要求代理<SKProductsRequestDelegate>

收到產品信息的響應
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
}

請求失敗
func request(_ request: SKRequest, didFailWithError error: Error) {
}

請求完成
func requestDidFinish(_ request: SKRequest) {
}複製代碼

付款交易觀察代理<SKPaymentTransactionObserver>

監聽交易狀態
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for tran in transactions {
            switch tran.transactionState {
            case .purchased:
                //交易完成,調起驗證購買
                //1.從沙盒獲取持久化訂單信息
                //2.將收據上傳到App服務器,成功後結束交易
                //3.刪除保存的訂單信息
            case .purchasing:
            	//交易中
            case .restored:
                //已經購買過
            case .failed:
                //交易失敗
                break
            default:
                break
      }
   }
}

交易結束
private func payFinish(transaction:SKPaymentTransaction) {
}複製代碼

代碼

import UIKit
import StoreKit
// MARK: - swift title: IAP應用內購買
// MARK: - 點擊購買
class UserIAPBuy: NSObject,SKProductsRequestDelegate,SKPaymentTransactionObserver {​    
    func startBuyInnerProduct(_ type: String) -> () {​        
        SKPaymentQueue.default().add(self as SKPaymentTransactionObserver)​        ​        
        localRequest(type)​    
    }​    ​    
    func localRequest(_ type: String) -> () {​        ​        
        if SKPaymentQueue.canMakePayments() {​            
            let set = NSSet(array: [type])​            
            //檢索本地化商品信息​            
            let request = SKProductsRequest(productIdentifiers: set as! Set<String>)​            
            request.delegate = self​            
            request.start()​        
        }else {​            
            print("禁止購買")​        
        }​        ​    
    }​    
}
// MARK: - 恢復購買
extension UserIAPBuy {​    
    func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {​        
        print("錯誤恢復 code: (error)")​    
    }​    ​    
    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {​        
        //恢復購買獲取成功回調​        
        var array = String​        
        print("received restored transactions: (queue.transactions.count)")​        
        for pay:SKPaymentTransaction in queue.transactions {​            
            let productID = pay.payment.productIdentifier​            
            array.append(productID)​            
            print("message: (array)")​        
        }​    
    }​    
    //恢復以前購買​    
    @objc func replyToBuy() {​        
        SKPaymentQueue.default().restoreCompletedTransactions()​    
    }
}
// MARK: - 代理:商品 SKProductsRequestDelegate
extension UserIAPBuy {​    
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {​        
        // 收到App Store商品信息的響應​        
        let pro = response.products​        ​        
        if pro.count > 0 {​            
            var p: SKProduct?​            
            for pid in pro {​                
                print("描述信息: (pid.description)")​                
                print("產品標題: (pid.localizedTitle), 產品描述信息: (pid.localizedDescription)")​                
                print("價格: (pid.price)")​                
                p = pid​            
            }​            
            guard let pro = p else {​                
                return​            
            }​            
            SKPaymentQueue.default().add(SKPayment(product: p))​            ​        
        }else {​            
            // 處理沒法得到商品信息的操做​            
            print("沒法取得商品信息")​        
        }​    
    }​    ​    
    func requestDidFinish(_ request: SKRequest) {​        
        // 處理請求完成​    
    }​    ​    
    func request(_ request: SKRequest, didFailWithError error: Error) {​        
        // 處理請求失敗​    
    }
}
// MARK: - 代理:付款交易觀察 SKPaymentTransactionObserver
extension UserIAPBuy {​    
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {​        
        //監聽交易狀態​        
        for tran in transactions {​            
            switch tran.transactionState {​            
            case .purchased:​                
                //交易完成,調起驗證購買​                
                //1.從沙盒獲取持久化訂單信息​                
                //2.將收據上傳到App服務器,成功後結束交易​                
                //3.刪除保存的訂單信息​                
                paymentTransactionPurchased()​                
                SKPaymentQueue.default().finishTransaction(tran)​            
            case .purchasing:​                
                //交易中​                
                paymentTransactionPurchasing()​            
            case .restored:​                
                //已經購買過​                
                paymentTransactionRestored()​                
                SKPaymentQueue.default().finishTransaction(tran)​            
            case .failed:​               
                //交易失敗​               
                paymentTransactionFailed(tran)​            
            default:​                
                break​            
            }​        
        }​    
    }​    ​    
    func paymentTransactionPurchased() {​        
        // 驗證購買,避免越獄軟件模擬蘋果請求達到非法購買問題​        
        guard let receiptUrl = Bundle.main.appStoreReceiptURL,let receiptData = try? Data(contentsOf: receiptUrl) else {​                        
            // 從沙盒中獲取交易憑證而且b拼接成請求提數據0​            
            return​        
        }​        
        let receiptStr = receiptData.base64EncodedString(options: Data.Base64EncodingOptions.endLineWithLineFeed)​        
        //處理訂單信息​        
        print("訂單信息: (receiptStr)")​        
        //刪除保存的訂單​    
    }​    ​    
    func paymentTransactionPurchasing() {​        
        print("交易中")​    
    }​    ​    
    func paymentTransactionRestored() {​        
        print("已經購買過")​    
    }​    ​    
    func paymentTransactionFailed(_ transaction: SKPaymentTransaction) {​        
        guard let err = transaction.error else {​            
            SKPaymentQueue.default().finishTransaction(transaction)​            
            return​        
        }​        
        if (err as NSError).code != SKError.paymentCancelled.rawValue {​            
            print("交易失敗")​        
        }else{​            
            print("交易取消")​        
        }​    
    }  
}複製代碼

沙箱測試

沙箱帳號是測試用途的Apple ID,因爲內購涉及實際金錢交易,在測試階段咱們能夠經過註冊蘋果的沙箱帳號來完成內購付款。

電子郵箱能夠自定義。
App Store地區的選擇和結算價格有關。


應用IAP權限打開



最後

技術總結:

1.在App Store後臺配置內購買項目,須要先完成協議,稅務銀行項目。這部分可參考上一篇

2.配置具有In-App Purchase功能的App ID,並開啓IAP權限。

3.經過StoreKit框架,在對應的地方實現並調整你的內購代碼。

須要注意的地方:

1.有關於服務端驗證收據,服務端也是有沙盒和正式兩個環境,具體實現也有不少成熟的開源框架可用,這裏也須要把應用套餐的信息給服務端配置。

2.蘋果自帶的內購買體驗確實不是很好,因爲自己服務器在美區,鏈接會比較慢,添加沙盒App ID的時候,建議不要在App內綁定,能夠選擇從設置-iTunesStore來綁定AppleID測試帳號,綁定成功,底部會新增一個沙盒帳號。

3.應用套餐也是須要審覈的,把改填的地方填寫清楚,問題不大,另外應用內套餐審覈是伴隨主App一塊兒審覈的,若是主App沒有過,那麼原先套餐審覈經過的狀態就會改變,在下一次從新提交主App的時候須要重置套餐的狀態,不然,沒法查找對應套餐信息。

驗證購買(二次驗證):

1.App將訂單收據傳給服務器

2.服務器收到收據後發送給App Store進行驗證,並返回驗證結果

這一步儘可能放在服務端操做,將全部的驗證交易數據放在客戶端不只不安全,並且不穩定。

服務端ruby集成的內購框架(Monza)

OC代碼Demo下載:github.com/marst123/In…


純屬我的分享,但願對iOS社區能有更多貢獻。

相關文章
相關標籤/搜索