Swift做爲當前在github上成長最快的語言之一,本人在學習iOS不曾學習過OC,所以在作iOS項目過程當中所有采用了Swift,下面詳細介紹下Swift的內購的實現。github地址:https://github.com/RyanLeeLY/...html
首先我就不介紹如何在iTunesConnect上添加內購商品了,總之添加完商品後,咱們須要用到的是productIdentifiers即你填寫的商品ID,這個ID是商品在商店中的惟一標識。
android
導入StoreKit,建立一個類,SKPaymentTransactionObserver
協議:當交易在隊列中有更新或者移出隊列時這個觀察者會被調用;SKProductsRequestDelegate
實現該協議的代理會受到商品請求返回的信息。git
public class LYIAPManager: NSObject, SKPaymentTransactionObserver, SKProductsRequestDelegate
自定義協議,LYIAPRequestDelegate
處理請求成功後的代理,LYIAPPaymentDelegate
交易時的代理,
LYIAPDelegate繼承上面兩個協議,方便使用。github
@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, 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:Error) @objc optional func transactionRestoreFinished(_ isSuccess:Bool) } public let LYIAP = LYIAPManager.LYIAPInstance public class LYIAPManager: NSObject, SKPaymentTransactionObserver, 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
json
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