Swift实现iOS内购

前端之家收集整理的这篇文章主要介绍了Swift实现iOS内购前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

  • Swift作为当前在github上成长最快的语言之一,本人在学习iOS未曾学习过OC,因此在做iOS项目过程中全部采用了Swift,下面详细介绍下Swift的内购的实现。github地址:https://github.com/RyanLeeLY/...


起步

  • 首先我就不介绍如何在iTunesConnect上添加内购商品了,总之添加完商品后,我们需要用到的是productIdentifiers即你填写的商品ID,这个ID是商品在商店中的唯一标识。

  • 导入StoreKit,创建一个类,SKPaymentTransactionObserver协议:当交易在队列中有更新或者移出队列时这个观察者会被调用SKProductsRequestDelegate实现该协议的代理会受到商品请求返回的信息。

public class LYIAPManager: NSObject,SKPaymentTransactionObserver,SKProductsRequestDelegate
  • 自定义协议,LYIAPRequestDelegate处理请求成功后的代理,LYIAPPaymentDelegate交易时的代理,
    LYIAPDelegate继承上面两个协议,方便使用。

@objc public protocol LYIAPDelegate: LYIAPRequestDelegate,LYIAPPaymentDelegate{
    
}

@objc public protocol LYIAPRequestDelegate: NSObjectProtocol{
    @objc optional func requestFinished()

}

@objc public protocol LYIAPPaymentDelegate: NSObjectProtocol{
    func transactionPurchased(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction)
    @objc optional func transactionFailed(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction)
    @objc optional func transactionRestore(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction)
    @objc optional func transactionDeferred(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction)
    @objc optional func transactionPurchasing(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction)
    @objc optional func transactionRestoreFailedWithError(_ error:NSError)
    @objc optional func transactionRestoreFinished(_ isSuccess:Bool)
    
}

全部实现

//
//  LYIAPManager.swift
//  crater
//
//  Created by 李尧 on 2016/10/11.
//  Copyright © 2016年 secstudio. All rights reserved.
//

import UIKit
import StoreKit

private func printLog<T>(_ message:T,file:String = #file,method:String = #function,line:Int = #line){
    #if DEBUG
        print("\((file as NSString).lastPathComponent)[\(line)],\(method): \(message)")
    #endif
}

@objc public protocol LYIAPDelegate: LYIAPRequestDelegate,transaction: SKPaymentTransaction)
    @objc optional func transactionRestoreFailedWithError(_ error:Error)
    @objc optional func transactionRestoreFinished(_ isSuccess:Bool)
    
}

public let LYIAP = LYIAPManager.LYIAPInstance

public class LYIAPManager: NSObject,SKProductsRequestDelegate {
    fileprivate let VERIFY_RECEIPT_URL = "https://buy.itunes.apple.com/verifyReceipt"
    fileprivate let ITMS_SANDBox_VERIFY_RECEIPT_URL = "https://sandBox.itunes.apple.com/verifyReceipt"
    fileprivate var restoreSuccess = false
    
    fileprivate var productDict:NSMutableDictionary?
    
    static let LYIAPInstance = LYIAPManager()
    
    var request:SKProductsRequest?
    var observer:SKPaymentTransactionObserver?
    
    weak var delegate:LYIAPDelegate?
    weak var requestDelegate:LYIAPRequestDelegate?
    weak var paymentDelegate:LYIAPPaymentDelegate?
    
    fileprivate override init() {
        
    }
    /**
     Example: let productsIds = NSSet(array: ["com.xxx.xxx.abc"])
     */
    func setRequestWithProducts(_ productsIds: NSSet,delegate: LYIAPDelegate?) {
        request = SKProductsRequest(productIdentifiers: productsIds as! Set<String>)
        request?.delegate = self
        SKPaymentQueue.default().add(self)
        
        if(delegate != nil){
            self.delegate = delegate!
            paymentDelegate = delegate!
            requestDelegate = delegate!
        }
    }
    
    func setPaymentTransactionsDelegate(_ delegate: LYIAPPaymentDelegate){
        paymentDelegate = delegate
    }
    
    func setProductsRequestDelegate(_ delegate: LYIAPRequestDelegate){
        requestDelegate = delegate
    }
    
    func removeRequestDelegate(){
        requestDelegate = nil
    }
    
    func removeProductsDelegate(){
        paymentDelegate = nil
    }
    
    func startRequest(){
        testIsNil()
        request?.start()
    }
    
    func cancelRequest(){
        testIsNil()
        request?.cancel()
    }
    
    func startPaymentWithProductId(_ productId: String){
        //if loaded
        if(SKPaymentQueue.canMakePayments()){
            guard productDict != nil else{
                printLog("products haven't been loaded")
                return
            }
            requestPaymentWithProduct(productDict![productId] as! SKProduct)
        }else{
            printLog("IAP is not supported!")
        }
    }
    
    func restorePayment(){
        restoreSuccess = false
        SKPaymentQueue.default().restoreCompletedTransactions()
    }
    
    public func productsRequest(_ request: SKProductsRequest,didReceive response: SKProductsResponse) {
        if (productDict == nil) {
            printLog("first load products")
            productDict = NSMutableDictionary(capacity: response.products.count)
        }
        for product in response.products  {
            printLog("product \(product.productIdentifier) loaded")
            productDict!.setObject(product,forKey: product.productIdentifier as NSCopying)
        }
        requestDelegate?.requestFinished?()
    }
    
    public func paymentQueue(_ queue: SKPaymentQueue,updatedTransactions transactions: [SKPaymentTransaction]) {
        print("updatedTransactions")
        for transaction in transactions {
            switch transaction.transactionState{
            case .purchased:
                printLog("purchased")
                paymentDelegate?.transactionPurchased(queue,transaction: transaction)
                SKPaymentQueue.default().finishTransaction(transaction)
                break
            case .Failed:
                printLog("Failed")
                paymentDelegate?.transactionFailed?(queue,transaction: transaction)
                SKPaymentQueue.default().finishTransaction(transaction)
                break
            case .restored:
                printLog("restore")
                restoreSuccess = true
                paymentDelegate?.transactionRestore?(queue,transaction: transaction)
                SKPaymentQueue.default().finishTransaction(transaction)
                break
            case .purchasing:
                paymentDelegate?.transactionPurchasing?(queue,transaction: transaction)
                printLog("purchasing")
                break
            case .deferred:
                paymentDelegate?.transactionDeferred?(queue,transaction: transaction)
                printLog("deferred")
                break
            }
        }
    }
    
    public func paymentQueue(_ queue: SKPaymentQueue,restoreCompletedTransactionsFailedWithError error: Error) {
        printLog("retore Failed with error:\(error)")
        paymentDelegate?.transactionRestoreFailedWithError?(error)
        
    }
    public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        printLog("finished restore")
        paymentDelegate?.transactionRestoreFinished?(restoreSuccess)
    }
    
    private func requestPaymentWithProduct(_ product: SKProduct){
        let payment = SKPayment(product: product)
        SKPaymentQueue.default().add(payment)
    }
    
    
    
    private func testIsNil(){
        if(request == nil){
            printLog("request hasn't been init")
        }else if(request?.delegate == nil){
            printLog("request delegate hasn't been set")
        }
    }
    
    func verifyPruchase(completion:@escaping (NSDictionary?,NSError?) -> Void) {
        // 验证凭据,获取到苹果返回的交易凭据
        let receiptURL = Bundle.main.appStoreReceiptURL
        // 从沙盒中获取到购买凭据
        let receiptData = NSData(contentsOf: receiptURL!)
        #if DEBUG
            let url = NSURL(string: ITMS_SANDBox_VERIFY_RECEIPT_URL)
        #else
            let url = NSURL(string: VERIFY_RECEIPT_URL)
        #endif
        let request = NSMutableURLRequest(url: url! as URL,cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy,timeoutInterval: 10.0)
        request.httpMethod = "POST"
        let encodeStr = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions.endLineWithLineFeed)
        let payload = NSString(string: "{\"receipt-data\" : \"" + encodeStr! + "\"}")
        let payloadData = payload.data(using: String.Encoding.utf8.rawValue)
        request.httpBody = payloadData;
        
        let session = URLSession.shared
        let semaphore = DispatchSemaphore(value: -1)
        
        let dataTask = session.dataTask(with: request as URLRequest,completionHandler: {(data,response,error) -> Void in
                if error != nil{
                    print("error1")
                    completion(nil,error as NSError?)
                }else{
                    if (data==nil) {
                        print("error2")
                        completion(nil,error as NSError?)
                    }
                    do{
                        let jsonResult: NSDictionary = try JSONSerialization.jsonObject(with: data!,options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
                        if (jsonResult.count != 0) {
                            // 比对字典中以下信息基本上可以保证数据安全
                            // bundle_id&application_version&product_id&transaction_id
                            // 验证成功
                            let receipt = jsonResult["receipt"] as! NSDictionary
                            completion(receipt,nil)
                        }
                        print(jsonResult)
                    }catch{
                        print("error3")
                        completion(nil,nil)
                    }
                }
                
                semaphore.signal()
        }) as URLSessionTask
        dataTask.resume()
        semaphore.wait()
    }
}

使用方法

  • 新建一个ViewController,实现协议LYIAPDelegate

import UIKit
import StoreKit

class ViewController: UIViewController,LYIAPDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let productsIds = NSSet(array: ["com.xxx.xxx.abc"])
        LYIAP.setRequestWithProducts(productsIds,delegate: self)
        LYIAP.startRequest()
        // Do any additional setup after loading the view,typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func requestFinished() {
        // Do something when products have been loaded.
    }
    
    func transactionPurchased(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction) {
        // Identifier of the product that has been purchased
        debugPrint(transaction.payment.productIdentifier)
        
        LYIAP.verifyPruchase(completion: {(receipt,error) in
            // You can verify the transaction. In this callback,you will get the receipt if the transaction is verified by the APPLE. You can compare some tranction infomation with the receipt.
            debugPrint(receipt)
        })
    }
    
    func transactionRestore(_ queue: SKPaymentQueue,transaction: SKPaymentTransaction) {
        // Identifier of the product that has been restored
        // You must add restore function to your app accroding to APPLE's provisions
        debugPrint(transaction.payment.productIdentifier)
    }
    
    func transactionRestoreFinished(_ isSuccess: Bool) {
        // It is called when restore is finished. isSuccess will be true when some products have been restored successfully.
    }

}

部分代码参考来源:SaiWu博客园

猜你在找的Swift相关文章